Setting up Authentication, AppSync and CI/CD with AWS Amplify - Day 2

Setting up Authentication, AppSync and CI/CD with AWS Amplify - Day 2

·

7 min read

As part of the #AmplifyHashnode hackathon, I've decided to build a restaurant review app that leverages React-Native and Amplify. This is day 2 of my journey. A summary of what was accomplished today:

  1. Initialize app with Expo
  2. Setup Git repo
  3. Initialize with Amplify
  4. Add authentication
  5. Set up continuous deployment and dev environment
  6. Create GraphQL schema that leverages Amplify directives

I'll also link some video sources that I'll upload to youtube that include a live coding session. Here's a rough breakdown from the terminal.

Step 1:

$:  expo init restaurant-review-app
     > blank (a minimal app...)
$:  cd restaurant-review-app

Gif $: epxo init

Step 2:

$:  git init
$:  git add .
$:  git commit -m "Initial commit"
$:  git push

Step 3:

$:  amplify init
 ?  Enter a name for the project: restaurantreviewapp
 ?  Enter a name for the environment: dev
 ?  Choose your default editor: Visual Studio Code
 ?  Choose the type of app that you're building:  javascript
 ?  What javascript framework are you using: react-native
 ?  Source Directory Path:  /
 ?  Distribution Directory Path: /
 ?  Build Command:  npm run-script build
 ?  Start Command: npm run-scrip-start
 ?  Please choose the profile you want to use
 ?  Choose environment: dev

Step 4:

Link to video for details but quick breakdown:

$:  amplify add auth
     -  Choose Manual Configuration
     -  Choose AWS IAM for signup
     -  Allow unauthenticated logins
     -  Signup with email and phone number
     -  Choose optional MFA Configuration
     -  Required Attributes for signup: email and phone_number

I made other adjustments which you can see in the video. This will also get it's own dedicated article after the hackathon.

Step 5:

Link to video for details but quick breakdown: Amplify does everything for you, lol it's really just me getting excited that they have an automatic integration with Expo's React-Native for web for front end deployment ;)

Step 6:

Link to video for details. There's a lot going on here that I will breakdown into it's own article in the future, but for the time being, I'll layout the schema here and I recommend the video for getting an idea of how I arrived there.

type GPS {
  lon: Float
  lat: Float
}

type Establishment
  @model
  @auth(rules: [{ allow: public, provider: iam }])
  @key(fields: ["ownerId", "id"]) {
  id: ID!
  ownerId: ID!
  owner: User
  name: String!
  gps: GPS
  street: String
  city: String
  state: String
  zipcode: String
  neighborhood: String
  phone: String
  email: String
  placeID: String!
  phoneNumber: String
  likeCount: Int
  reviews: [Review]
  userLikes: [EstablishmentLike] @connection(fields: ["id"])
}

type EstablishmentLike
  @model(subscriptions: { level: public })
  @auth(rules: [{ allow: public, provider: iam }])
  @key(fields: ["establishmentId", "createdAt"])
  @key(
    name: "establishmentLikesByUser"
    fields: ["userId", "createdAt"]
    queryField: "getEstablishmentLikesByUser"
  ) {
  establishmentId: ID!
  userId: ID!
    @auth(rules: [{ allow: owner, ownerField: "userId", identityClaim: "sub" }])
  createdAt: AWSTimestamp!
  establishment: Establishment @connection(fields: ["establishmentId"])
  user: User @connection(fields: ["userId"])
  establishmentName: String
}

type CheckIn
  @model(subscriptions: { level: public })
  @auth(rules: [{ allow: public, provider: iam }])
  @key(fields: ["establishmentId", "createdAt"])
  @key(
    name: "userCheckins"
    fields: ["userId", "createdAt"]
    queryField: "getUserCheckins"
  ) {
  establishmentId: ID!
  userId: ID!
    @auth(rules: [{ allow: owner, ownerField: "userId", identityClaim: "sub" }])
  createdAt: AWSTimestamp!
  establishmentName: String
  establishment: Establishment @connection(fields: ["establishmentId"])
  user: User @connection(fields: ["userId"])
}

type EstablishmentFollow
  @model
  @key(fields: ["establishmentId", "userId"])
  @key(
    name: "establishmentsFollowedByUser"
    fields: ["userId", "establishmentId"]
    queryField: "getEstablishmentsFollowedByUser"
  ) {
  establishmentId: ID!
  userId: ID! # user.id
  establishment: Establishment @connection(fields: ["establishmentId"])
  user: User @connection(fields: ["userId"])
}

type Review
  @model(subscriptions: { level: public })
  @auth(rules: [{ allow: public, provider: iam }])
  @key(fields: ["establishmentId", "createdAt"])
  @key(
    name: "userCheckins"
    fields: ["userId", "createdAt"]
    queryField: "getUserCheckins"
  ) {
  establishmentId: ID!
  userId: ID!
    @auth(rules: [{ allow: owner, ownerField: "userId", identityClaim: "sub" }])
  createdAt: AWSTimestamp!
  establishmentName: String
  comments: String
  image: [String]
  rating: Int
  establishment: Establishment @connection(fields: ["establishmentId"])
  user: User @connection(fields: ["userId"])
}

type User
  @model(mutations: { update: "updateUser", delete: "deleteUser" })
  @auth(
    rules: [
      {
        allow: owner
        ownerField: "id"
        identityClaim: "sub"
        operations: [update, delete, read]
      }
    ]
  )
  @key(fields: ["pk_id", "id"]) {
  pk_id: ID!
  id: ID!
  firstName: String
  lastName: String
  userName: String
  birthdate: String
  gender: String
  description: String
  ownerOf: [Establishment]
  createdAt: AWSDateTime
  lastUpdated: AWSDateTime
  profilePicture: String
  followers: [UserFollow] @connection(keyName: "followers", fields: ["id"])
  followed: [UserFollow] @connection(fields: ["id"])
  establishmentLikes: [EstablishmentLike]
    @connection(keyName: "establishmentLikesByUser", fields: ["id"])
}

type UserFollow
  @model
  @key(fields: ["id", "userFollowedId"])
  @key(
    name: "followers"
    fields: ["userFollowedId", "id"]
    queryField: "getFollowers"
  ) {
  id: ID! # user.id
  userFollower: User @connection(fields: ["id"])
  userFollowedId: ID! # user.id I'm following
  userFollowed: User @connection(fields: ["userFollowedId"])
}

enum UserType {
  consumer
  owner
}

Day 1 in the books and we've already set up Authentication, an API with all our queries, mutations and subscriptions connected to DynamoDB and our CI/CD pipeline. Here's the kicker, it works on iOS, Android, and Web, schwaaaaat 🤯 🤯 🤯. All praise to Amplify, Expo, & React-Native, y'all the real MVPs.

Github repo for day one can be found here

Youtube video playlist here

Check me out on twitter @andthensumm and follow the journey