Getting Started with AWS AppSync for iOS

Learn how to consume GraphQL APIs in your SwiftUI iOS apps in a simple and type-safe way using AWS AppSync framework. By Alex Brown.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 2 of 4 of this article. Click here to view the first page.

Installing CocoaPods

You will use CocoaPods to add the AppSync frameworks to your project. If you are not familiar with CocoaPods, you can learn about it in our CocoaPods Tutorial for Swift

CocoaPods is installed through Ruby, which is already installed on your Mac. Open Terminal, type the following command and press Enter.

sudo gem install cocoapods

After a short delay you should see Successfully installed cocoapods-VERSION in the Terminal window.

Adding Amplify to the Project

Now that you’re all set up with dependencies, you can move on to setting up the project in Xcode. Make sure you close Xcode for the next step… yes you heard that right!

Open a Terminal screen, and use cd to navigate to the starter project directory. Then, type the following into the terminal window:

pod init

Once the command completes, you’ll notice a new file named Podfile has appeared inside your project directory. Open Podfile in a text editor and add the following below # Pods for RazeList:

pod 'Amplify'
pod 'Amplify/Tools'
pod 'AmplifyPlugins/AWSAPIPlugin'
pod 'AmplifyPlugins/AWSDataStorePlugin'

Navigate back to the terminal window and type the following command:

pod install

After a few seconds, you should see the following message:

Pod installation complete! There are 4 dependencies from the Podfile and 12 total pods installed.

Voilà! Just like that, your packages have been installed and included in your project.

Open the project directory in Finder, you’ll notice you now have a workspace file called RazeList.xcworkspace, which CocoaPods created. Double-click this file and your project will open in Xcode. Use this file from now on to open your project instead of RazeList.xcodeproj, because it’s the one that contains all the dependencies needed.

Adding AppSync Script

You’re almost over the finish line. The last thing you need to do before writing any code is add a Run Script to the Build Phases tab inside Xcode. This script performs some tasks needed to use AppSync in your project.

Select the RazeList project inside Xcode. In the project explorer, click Build Phases. Click the + button and select New Run Script Phase.

Steps to add a run script phase

You’ll notice a new Run Script entry at the bottom of the list. Click the arrow to expand it.

Steps for adding code to a run script phase

Inside the code editor at the top, add the following code:

"${PODS_ROOT}/AmplifyTools/amplify-tools.sh"

Now build and run the project. The build will take a little longer this time, because Xcode executes the Run Script as part of the build process. When the build finishes, you’ll have a few more files inside your project; you’ll be working with these in the next section. It’s important that you wait for the project to build before moving onto the next stage.

Initializing Amplify

Once the build process is complete, you’ll need to initialize amplify within your project. You’ll know the build has done its job as you’ll see a new folder called AmplifyConfig in the Project navigator.

Make sure you’re in the project directory in Terminal and enter the following command:

amplify init

Enter the following information when prompted:

? Enter a name for the environment
    Press Enter

? Choose your default editor
    None

? Do you want to use an AWS profile?
    Y

? Please choose the profile you want to use
    Press Enter for default

In the same Terminal window, enter the following command and then press Enter.

amplify add api

Enter the following information when prompted. Press enter on other steps to use the default setting.

? Please select from one of the below mentioned services:
    GraphQL

? Provide API name:
    Press Enter to set this to your directory name.

Next enter the following command.

amplify push

Enter the following information when prompted.

? Are you sure you want to continue? 
    Y

? Do you want to generate code for your newly created GraphQL API
    N

This may seem like a lot of setup, but Amplify has done a lot for you. You’ve created a user, set up an app and added it the AWS dashboard, created a GraphQL API and published it to AWS. Everything from here is good to go!

Creating Models Using GraphQL

When working with a back-end service, you’ll likely want to represent your data types as models. Amplify saves you the trouble of having to type them up yourself. Isn’t that nice?

You still need to tell Amplify what to generate, however, and you’ll do that with GraphQL!

Open schema.graphql inside the AmplifyConfig group.

Replace the contents of this file with the following:

type Todo @model {
  id: ID!
  name: String!
  description: String
  completed: Boolean!
}

Next, open amplifytools.xcconfig in the same directory. Change push and modelgen to true.

Build and run your project. When the build finishes, there will be a new directory in your Project navigator called AmplifyModels. Changing the line above in the configuration told Amplify to generate your model files for you from the GraphQL schema and update your configuration on AWS. Expand AmplifyModels and take a look around. You’ll see Todo.swift containing your model and some helper files.

Using Amplify in the App

In the Project navigator on the left, open AppMain.swift and add the following imports:

import Amplify
import AmplifyPlugins

Inside the AppDelegate class, add the following code before return true in the application(_:didFinishLaunchingWithOptions:) function:

let apiPlugin = AWSAPIPlugin(modelRegistration: AmplifyModels())
let dataStorePlugin = AWSDataStorePlugin(modelRegistration: AmplifyModels())
do {
  try Amplify.add(plugin: apiPlugin)
  try Amplify.add(plugin: dataStorePlugin)
  try Amplify.configure()
  print("Initialized Amplify")
} catch {
  print("Could not initialize Amplify: \(error)")
}

Build and run the project.

Initial Hello World screen when building app

There are no visual changes to speak of, but you’ve fully configured your project to work with AppSync and Amplify.

Building the To Do List UI

With the libraries installed, CocoaPods set up and models generated, it’s time to make RazeList come to life.

Some of the SwiftUI coding for this tutorial has been done for you, but you still need to build the main to do list. That’s what you’ll be doing in this section.

Adding Rows to the To Do List

You’ll start by defining the row. Right click the Views group and select the New File option. Choose SwiftUI View and click Next. Name the file TodoRowView.swift and create it.

Open that file and, just below the TodoRowView declaration, add the following.

// 1
let todoItem: Todo
// 2
let onToggleCompleted: (Todo) -> Void

The to do row defines two requirements.

  1. A Todo model to use for rendering.
  2. A closure called when the user toggles the completed state.

This will cause an error as the preview doesn’t pass in these dependencies. Replace the entire contents of TodoRowView_Previews with the following:

struct TodoRowView_Previews: PreviewProvider {
  static var previews: some View {
    TodoRowView(
      todoItem: Todo(
      id: UUID().uuidString,
      name: "Build this cool app",
      description: "I need to finish building this awesome todo list app :]",
      completed: false)) { _ in }
  }
}

Next, you’ll define a method called when the todo is toggled by the user. Add the following method to TodoRowView:

func toggleCompleted() {
  withAnimation {
    onToggleCompleted(todoItem)
  }
}

This function simply wraps onToggleCompleted in an animation block that will animate the movement of the row between sections.

Next, replace the entire body with the following:

var body: some View {
  // 1
  VStack(alignment: .leading, spacing: 8) {
    HStack(spacing: 10) {
      // 2
      Button(action: { onToggleCompleted(todoItem) }) {
        Image(systemName: todoItem.completed ? "checkmark.square" : "square")
          .imageScale(.large)
          .foregroundColor(todoItem.completed ? .pink : .primary)
      }
      // 3
      Text(todoItem.name)
        .font(.system(size: 18, weight: .semibold))
    }
    // 4
    if let description = todoItem.description {
      Text(description)
        .font(.system(size: 14, weight: .medium))
        .padding(.leading, 32)
        .padding(.trailing, 10)
        .foregroundColor(.gray)
    }
  }
}

Here’s what the above code does:

  1. Define a VStack container.
  2. Define an HStack containing a button with a checkbox image. The image is either checked or unchecked depending on the state the to do model’s completed property. Tapping the button will call onToggleCompleted(_:).
  3. The second item in the stack is a Text view containing the name of the to do.
  4. If the to do contains a description, render it inside a Text view.