├── README.md └── amplify-swift-logo-cli.png /README.md: -------------------------------------------------------------------------------- 1 | # Building real-time applications with iOS, GraphQL & AWS AppSync 2 | 3 | In this workshop we'll learn how to build cloud-enabled native iOS Swift apps with [AWS Amplify](https://aws-amplify.github.io/) and connect our apps to a GraphQL API via AWS AppSync. 4 | 5 | We'll start from a new Xcode project, add categories such as `API` and `Auth` using the Amplify Framework to provision cloud resources such as a hosted GraphQL API via AWS AppSync, Amazon DynamoDB as a data source, or an Identity Provider via Amazon Cognito to provide basic authentication. We'll start simple and work our way up to a fully connected mobile app. Please provide any feedback you have in the 'issues' and I'll take a look. Let's get started! 6 | 7 | ![](./amplify-swift-logo-cli.png) 8 | 9 | ### Topics we'll be covering: 10 | 11 | - [GraphQL API with AWS AppSync](https://github.com/dennisAWS/aws-appsync-ios-workshop#getting-started---create-an-xcode-project) 12 | - [Authentication](https://github.com/dennisAWS/aws-appsync-ios-workshop#adding-authentication) 13 | - [Adding Authorization to your GraphQL API using AWS AppSync API](https://github.com/dennisAWS/aws-appsync-ios-workshop#adding-authorization-to-the-graphql-api) 14 | - [Deleting the resources](https://github.com/dennisAWS/aws-appsync-ios-workshop#removing-services) 15 | 16 | ## Getting Started - Create an Xcode project 17 | 18 | To get started, create a new Xcode project for iOS Swift & save as: `ios-amplify-app` 19 | 20 | From a Mac Terminal, change into the new app directory & prepare to install and congigure the Amplify CLI. 21 | 22 | ### Install and Configure the Amplify CLI - Just Once 23 | 24 | Next, we'll install the AWS Amplify CLI: 25 | 26 | ```bash 27 | npm install -g @aws-amplify/cli 28 | ``` 29 | 30 | After installation, configure the CLI with your developer credentials: 31 | 32 | Note: If you already have the AWS CLI installed and use a named profile, you can skip the `amplify configure` step. 33 | `Amplify configure` is going to have you launch the AWS Management Console, create a new IAM User, asign an IAM Policy, and collect the programmatic credentials to craate a CLI profile that will be used to provision AWS resources for each project in future steps. 34 | 35 | ```js 36 | amplify configure 37 | ``` 38 | 39 | > If you'd like to see a video walkthrough of this configuration process, click [here](https://www.youtube.com/watch?v=fWbM5DLh25U). 40 | 41 | Here we'll walk through the `amplify configure` setup. Once you've signed in to the AWS console, continue: 42 | - Specify the AWS Region: __us-east-1__ 43 | - Specify the username of the new IAM user: __amplify-workshop-user__ 44 | > In the AWS Console, click __Next: Permissions__, __Next: Tags__, __Next: Review__, & __Create User__ to create the new IAM user. Then, return to the command line & press Enter. 45 | - Enter the access key of the newly created user: 46 | ? accessKeyId: __()__ 47 | ? secretAccessKey: __()__ 48 | - Profile Name: __amplify-workshop-user__ 49 | 50 | ### Initializing A New Amplify Project 51 | From the root of your Xcode project folder: 52 | ```bash 53 | amplify init 54 | ``` 55 | 56 | - Enter a name for the project: __iosamplifyapp__ 57 | - Enter a name for the environment: __master__ 58 | - Choose your default editor: __Visual Studio Code (or your default editor)__ 59 | - Please choose the type of app that you're building __ios__ 60 | - Do you want to use an AWS profile? __Y__ 61 | - Please choose the profile you want to use: __amplify-workshop-user__ 62 | 63 | AWS Amplify CLI will iniatilize a new project & you'll see a new folder: __amplify__ & a new file called `awsconfiguration.json` in the root directory. These files hold your Amplify project configuration. 64 | 65 | To view the status of the amplify project at any time, you can run the Amplify `status` command: 66 | 67 | ```sh 68 | amplify status 69 | ``` 70 | 71 | ## Adding a GraphQL API 72 | In this section we'll add a new GraphQL API via AWS AppSync to our iOS project backend. 73 | To add a GraphQL API, we can use the following command: 74 | 75 | ```sh 76 | amplify add api 77 | ``` 78 | 79 | Answer the following questions: 80 | 81 | - Please select from one of the above mentioned services __GraphQL__ 82 | - Provide API name: __ConferenceAPI__ 83 | - Choose an authorization type for the API __API key__ 84 | - Do you have an annotated GraphQL schema? __N__ 85 | - Do you want a guided schema creation? __Y__ 86 | - What best describes your project: __Single object with fields (e.g. “Todo” with ID, name, description)__ 87 | - Do you want to edit the schema now? (Y/n) __Y__ 88 | 89 | When prompted and the default schema launches in your favorite editor, update the default schema to the following: 90 | 91 | ```graphql 92 | type Talk @model { 93 | id: ID! 94 | clientId: ID 95 | name: String! 96 | description: String! 97 | speakerName: String! 98 | speakerBio: String! 99 | } 100 | ``` 101 | 102 | Next, let's deploy the GraphQL API into our account: 103 | This step take the local CloudFormation templates and deployes them to the AWS Cloud for provisioning of the services you enabled via the `add API` category. 104 | ```bash 105 | amplify push 106 | ``` 107 | 108 | - Do you want to generate code for your newly created GraphQL API __Y__ 109 | - Enter the file name pattern of graphql queries, mutations and subscriptions: __(graphql/**/*.graphql)__ 110 | - Do you want to generate/update all possible GraphQL operations - queries, mutations and subscriptions? __Y__ 111 | - Enter maximum statement depth [increase from default if your schema is deeply nested] __2__ 112 | - Enter the file name for the generated code __API.swift__ 113 | 114 | > To view the new AWS AppSync API at any time after its creation, go to the dashboard at [https://console.aws.amazon.com/appsync](https://console.aws.amazon.com/appsync). Also be sure that your region is set correctly. 115 | 116 | ### Performing mutations from within the AWS AppSync Console 117 | 118 | In the AWS AppSync console, open your API & then click on Queries. 119 | 120 | Execute the following mutation to create a new talk in the API: 121 | 122 | ```bash 123 | mutation createTalk { 124 | createTalk(input: { 125 | name: "Monetize your Mobile Apps" 126 | description: "4 ways to make money as a mobile app developer" 127 | speakerName: "Dennis" 128 | speakerBio: "Mobile Quickie Developer" 129 | }) 130 | { 131 | id 132 | name 133 | description 134 | speakerName 135 | speakerBio 136 | } 137 | } 138 | ``` 139 | 140 | Now, let's query for the talk: 141 | 142 | ```bash 143 | query listTalks { 144 | listTalks { 145 | items { 146 | id 147 | name 148 | description 149 | speakerName 150 | speakerBio 151 | } 152 | } 153 | } 154 | ``` 155 | 156 | We can even add search / filter capabilities when querying: 157 | 158 | ```bash 159 | query listTalks { 160 | listTalks(filter: { 161 | description: { 162 | contains: "money" 163 | } 164 | }) { 165 | items { 166 | id 167 | name 168 | description 169 | speakerName 170 | speakerBio 171 | } 172 | } 173 | } 174 | ``` 175 | 176 | ### Configuring the iOS applicaion - AppSync iOS Client SDK 177 | 178 | Our backend resources have been created and we just verified mutations and queries in the AppSync Console. Let's move onto the mobile client! 179 | 180 | To configure the app, we'll use [Cocoapods](https://cocoapods.org/) to install the AWS SDK for iOS and AWS AppSync Client dependencies. 181 | In the root project folder, run the following command to initialize Cocoapods. 182 | 183 | ```js 184 | pod init 185 | ``` 186 | 187 | This will create a new `Podfile`. Open up the `Podfile` in your favorite editor and add the following dependency for adding the AWSAppSync SDK to your app: 188 | 189 | ```swift 190 | target 'ios-amplify-app' do 191 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks 192 | use_frameworks! 193 | 194 | # Pods for ios-amplify-app 195 | pod 'AWSAppSync', ' ~> 2.10.0' 196 | 197 | end 198 | ``` 199 | 200 | Install the AppSync iOS SDK by running: 201 | ```js 202 | pod install --repo-update 203 | ``` 204 | 205 | ## Add the `awsconfiguration.json` and `API.swift` files to your Xcode project 206 | 207 | We need to configure our iOS Swift application to be aware of our new AWS Amplify project. We do this by referencing the auto-generated `awsconfiguration.json` and `API.Swift` files in the root of your Xcode project folder. 208 | 209 | Launch Xcode using the .xcworkspace from now on as we are using Cocoapods. 210 | ```js 211 | $ open ios-amplify-app.xcworkspace/ 212 | ``` 213 | 214 | In Xcode, right-click on the project folder and choose `"Add Files to ..."` and add the `awsconfiguration.json` and the `API.Swift` files to your project. When the Options dialog box that appears, do the following: 215 | 216 | * Clear the Copy items if needed check box. 217 | * Choose Create groups, and then choose Next. 218 | 219 | Build the project (Command-B) to make sure we don't have any compile errors. 220 | 221 | ## Initialize the AppSync iOS Client 222 | #### Update ViewController.swift 223 | Add the folowing four numbered code snippets to your `ViewController.swift` class: 224 | 225 | ```swift 226 | import AWSAppSync // #1 227 | 228 | class ViewController: UIViewController { 229 | 230 | // Reference AppSync client 231 | var appSyncClient: AWSAppSyncClient? // #2 232 | 233 | //... 234 | 235 | override func viewDidLoad() { 236 | super.viewDidLoad() 237 | 238 | //... 239 | 240 | initializeAppSync() // #3 241 | 242 | //... 243 | } 244 | 245 | // #4 246 | // Use this code when setting up AppSync with API_key auth mode. This mode is used for testing our GraphQL mutations, queries, and subscriptions with an API key. 247 | func initializeAppSync() { 248 | do { 249 | // Initialize the AWS AppSync configuration 250 | let appSyncConfig = try AWSAppSyncClientConfiguration(appSyncServiceConfig: AWSAppSyncServiceConfig(), 251 | cacheConfiguration: AWSAppSyncCacheConfiguration()) 252 | 253 | // Initialize the AWS AppSync client 254 | appSyncClient = try AWSAppSyncClient(appSyncConfig: appSyncConfig) 255 | } catch { 256 | print("Error initializing appsync client. \(error)") 257 | } 258 | } 259 | // End #4 260 | } 261 | ``` 262 | 263 | ## Add GraphQL Mutation 264 | 265 | Add the following mutation function to your `ViewController.swift` class: 266 | 267 | ```swift 268 | // GraphQL Mutation - Add a new talk 269 | func createTalkMutation(){ 270 | let conferenceInput = CreateTalkInput(name: "Monetize your iOS app", description: "How to make dough as an iOS developer", speakerName: "Steve Jobs", speakerBio: "I do cool stuff at Apple") 271 | appSyncClient?.perform(mutation: CreateTalkMutation(input: conferenceInput)) 272 | { (result, error) in 273 | if let error = error as? AWSAppSyncClientError { 274 | print("Error occurred: \(error.localizedDescription )") 275 | } 276 | if let resultError = result?.errors { 277 | print("Error saving conf talk: \(resultError)") 278 | return 279 | } 280 | 281 | guard let result = result?.data else { return } 282 | 283 | print("Talk created: \(String(describing: result.createTalk?.id))") 284 | } 285 | } 286 | ``` 287 | 288 | ## Add GraphQL Query 289 | 290 | Add the following query function to your `ViewController.swift` class: 291 | 292 | ```swift 293 | // GraphQL Query - List all talks 294 | func getTalksQuery(){ 295 | appSyncClient?.fetch(query: ListTalksQuery(), cachePolicy: .returnCacheDataAndFetch) { (result, error) in 296 | if error != nil { 297 | print(error?.localizedDescription ?? "") 298 | return 299 | } 300 | 301 | guard let talks = result?.data?.listTalks?.items else { return } 302 | talks.forEach{ print(("Title: " + ($0?.name)!) + "\nSpeaker: " + (($0?.speakerName)! + "\n")) } 303 | } 304 | } 305 | ``` 306 | 307 | ### Run App and Invoke Mutation and Query Functions 308 | 309 | In order to execute the mutation and/or query functions above, we can invoke those functions from `ViewDidLoad()` in the `ViewController.swift` class: 310 | ```swift 311 | override func viewDidLoad() { 312 | super.viewDidLoad() 313 | 314 | //... 315 | 316 | createTalkMutation() 317 | getTalksQuery() 318 | 319 | //... 320 | } 321 | ``` 322 | Build (Command-B) and run your app. 323 | 324 | ### Add GraphQL Subscriptions 325 | 326 | GraphQL subscriptions give us the real-time updates when data changes in our API. 327 | First, set the discard variable at the `ViewController.swift` class level: 328 | 329 | ```swift 330 | // Set a discard variable at the class level 331 | var discard: Cancellable? 332 | ``` 333 | 334 | Now add this new `subscribeToTalks()` function to your `ViewController.swift` class: 335 | 336 | ```swift 337 | func subscribeToTalks() { 338 | do { 339 | discard = try appSyncClient?.subscribe(subscription: OnCreateTalkSubscription(), resultHandler: { (result, transaction, error) in 340 | if let result = result { 341 | print("Subscription triggered! " + result.data!.onCreateTalk!.name + " " + result.data!.onCreateTalk!.speakerName) 342 | } else if let error = error { 343 | print(error.localizedDescription) 344 | } 345 | }) 346 | } catch { 347 | print("Error starting subscription.") 348 | } 349 | } 350 | ``` 351 | 352 | Finally, call the `subscribeToTalks()` from `ViewDidLoad()` in your `ViewController.swift` class: 353 | 354 | ```swift 355 | override func viewDidLoad() { 356 | super.viewDidLoad() 357 | 358 | // ... 359 | 360 | // invoke to subscribe to newly created talks 361 | subscribeToTalks() 362 | } 363 | ``` 364 | > Don't forget to comment out the calls to createTalkMutation() getTalksQuery() in the ViewDidLoad() or the app will create a new talk each time it loads. 365 | 366 | Run the mobile app and it'll then subscribe to any new talk creation. To test the real-time subscription: Leave the app running and then create a new talk via the AppSync Console through a Mutation and you should see the iOS app log the new talk via a subscription! 367 | 368 | ## Adding Authentication to Your iOS App 369 | #### Add Cognito User Pools (Basic Auth) 370 | 371 | Up to this point, we used API key as authorization to calling our GraphQL API. This is good for testing but we need to add authentication to provide controlled (secure) access to our AppSync GraphQL API. Back at the project folder in Terminal, let's add authentication to our project via the Amplify CLI. 372 | 373 | ```sh 374 | amplify add auth 375 | ``` 376 | 377 | - Do you want to use default authentication and security configuration? __Default configuration__ 378 | - How do you want users to be able to sign in when using your Cognito User Pool? __Username__ 379 | - What attributes are required for signing up? __Email__ (keep default) 380 | 381 | Now run the `amplify push` command and the cloud resources will be created in your AWS account. 382 | 383 | ```bash 384 | amplify push 385 | ``` 386 | 387 | > To view the new Cognito authentication service at any time after its creation, go to the dashboard at [https://console.aws.amazon.com/cognito/](https://console.aws.amazon.com/cognito/). Also be sure that your region is set correctly. 388 | 389 | ### Configure iOS App - AWS Auth iOS SDK 390 | 391 | Open up your Podfile and add the following dependencies: 392 | ```swift 393 | target 'ios-amplify-app' do 394 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks 395 | use_frameworks! 396 | 397 | # Pods for ios-amplify-app 398 | pod 'AWSAppSync', ' ~> 2.10.0' # Added previously 399 | pod 'AWSMobileClient', '~> 2.9.0' # Required dependency for auth 400 | pod 'AWSAuthUI', '~> 2.9.0' # Optional for drop-in UI 401 | pod 'AWSUserPoolsSignIn', '~> 2.9.0' # Optional for drop-in UI 402 | end 403 | ``` 404 | 405 | Now run a Pod install to add the new dependencies for auth: 406 | 407 | ```bash 408 | pod install 409 | ``` 410 | 411 | ### Add the AWSMobileClient 412 | AWSMobileClient itself is a credentials provider now and will be used for all authentication needs from federating logins to issuing AWS credentials via Cognito Identity. 413 | To add AWSMobileClient to our iOS app, we'll go into __ViewController.swift__ and first import the `AWSMobileClient`: 414 | 415 | ```swift 416 | import AWSMobileClient 417 | ``` 418 | 419 | Next, we'll initialize the `AWSMobileClient` in the ViewDidLoad() function in the `ViewController.swift` file: 420 | 421 | ```swift 422 | AWSMobileClient.sharedInstance().initialize { (userState, error) in 423 | if let userState = userState { 424 | switch(userState){ 425 | case .signedIn: // is Signed IN 426 | print("Logged In") 427 | print("Cognito Identity Id (authenticated): \(String(describing: AWSMobileClient.sharedInstance().identityId))") 428 | case .signedOut: // is Signed OUT 429 | print("Logged Out") 430 | print("Cognito Identity Id (unauthenticated): \(String(describing: AWSMobileClient.sharedInstance().identityId))") 431 | DispatchQueue.main.async { 432 | self.showSignIn() 433 | } 434 | default: 435 | AWSMobileClient.sharedInstance().signOut() 436 | } 437 | } else if let error = error { 438 | print(error.localizedDescription) 439 | } 440 | } 441 | ``` 442 | 443 | Last, we'll add the iOS SDK drop-in UI code in the `ViewController.swift` class to show our login UI if the user is not authenticated: 444 | 445 | ```swift 446 | // Use the iOS SDK Auth UI to show login options to user (Basic auth, Google, or Facebook) 447 | func showSignIn() { 448 | AWSMobileClient.sharedInstance().showSignIn(navigationController: self.navigationController!, { 449 | (userState, error) in 450 | if(error == nil){ // Successful signin 451 | DispatchQueue.main.async { 452 | print("User successfully logged in") 453 | } 454 | } 455 | }) 456 | } 457 | ``` 458 | 459 | >IMPORTANT: The drop-in UI requires the use of a navigation controller to anchor the view controller. Please make sure the app has an active navigation controller which is passed to the navigationController parameter. To add a Navigation Controller, select the Main.storyboard, select the yellow button at the top bar of the View Controller UI, then select 'Editor > Embed In > Navigation Controller. 460 | 461 | Now, we can run the app and see the Auth Drop in UI in action. This drop in UI provides a built-in UI giving users the ability to sign up, and sign in via Amazon Cognito User Pools. 462 | 463 | You now have authentication setup in your app! Go ahead and build (Command-B) and run the app. Based on the sample code above, the first time you launch the app, you should see the UI prompt for username, email, and password. Feel free to create an account and test it out. You'll know if you have successfully logged in when the log shows successful and you'll see the default white screen. 464 | 465 | Congratulations! You can now authenticate users. 466 | 467 | ## Update AppSync iOS SDK Client 468 | Now that we have our user authenticating via Cognito User Pools, we need to update the AppSync client configuarion in our iOS app. 469 | 470 | 471 | 472 | ## Update Authorization Type for GraphQL API 473 | 474 | Next, we need to update the AppSync API to use Cognito User Pools as the authorization type. Remember, we previously setup authorization via an API key for testing purposes. 475 | 476 | To switch our GraphQL API from API key to Cognito User Pools, we'll reconfigure the existing GraphQL API using the Amplify CLI by running this command from our Xcode project folder: 477 | 478 | ```sh 479 | amplify configure api 480 | ``` 481 | Please select from one of the below mentioned services: __GraphQL__ 482 | Choose an authorization type for the API: __Amazon Cognito User Pool__ 483 | 484 | Next, run `amplify push` to build out the new resources: 485 | 486 | ```sh 487 | amplify push 488 | ``` 489 | 490 | Once deployed, the AppSync GraphQL API can only be accessed via an authenticated User Pool user. 491 | 492 | ## Update the AppSync iOS Client for User Pools 493 | Now that we are using User Pools authorization for our GraphQL API, we need to modify the AppSync client configuration. 494 | 495 | REPLACE the existing `initializeAppSync()` function in the `ViewController` class with the following AppSync client configuration for User Pools authorization: 496 | 497 | ```swift 498 | // Use this AppSync client configuration when using Authorization Type: User Pools 499 | func initializeAppSync() { 500 | do { 501 | // You can choose the directory in which AppSync stores its persistent cache databases 502 | let cacheConfiguration = try AWSAppSyncCacheConfiguration() 503 | 504 | // Initialize the AWS AppSync configuration 505 | let appSyncConfig = try AWSAppSyncClientConfiguration(appSyncServiceConfig: AWSAppSyncServiceConfig(), 506 | userPoolsAuthProvider: { 507 | class MyCognitoUserPoolsAuthProvider : AWSCognitoUserPoolsAuthProviderAsync { 508 | func getLatestAuthToken(_ callback: @escaping (String?, Error?) -> Void) { 509 | AWSMobileClient.sharedInstance().getTokens { (tokens, error) in 510 | if error != nil { 511 | callback(nil, error) 512 | } else { 513 | callback(tokens?.idToken?.tokenString, nil) 514 | } 515 | } 516 | } 517 | } 518 | return MyCognitoUserPoolsAuthProvider() 519 | }(), cacheConfiguration: cacheConfiguration) 520 | 521 | // Initialize the AWS AppSync client 522 | appSyncClient = try AWSAppSyncClient(appSyncConfig: appSyncConfig) 523 | } catch { 524 | print("Error initializing appsync client. \(error)") 525 | } 526 | } 527 | ``` 528 | 529 | ## Advanced Use Case for Authenticated Users 530 | 531 | Next, let's look at how to use the identity of the user to associate items created in the database with the logged in user & then query the database using these credentials. We'll store the user's identity in the database table as userId & add a new index on the DynamoDB table to optimize our query by userId. 532 | 533 | ### Adding a New Index to the DynamoDB Table 534 | 535 | Next, we'll want to add a new GSI (global secondary index) in the table. We do this so we can query on the index to gain new data access pattern. 536 | 537 | To add the index, open the [AppSync Console](https://console.aws.amazon.com/appsync/home), choose your API & click on __Data Sources__. Next, click on the data source link. 538 | 539 | From here, click on the __Indexes__ tab & click __Create index__. 540 | 541 | For the __partition key__, input `userId` to create a `userId-index` Index name & click __Create index__. 542 | 543 | Next, we'll update the resolver for adding talks & querying for talks. 544 | 545 | ### Updating the AppSync Resolvers for Handling Auth Users 546 | To start passing in the userId into newly crated talks, we need to create two new request templates (resolvers) to handling the passing of the userId when adding new talks and used to retrieve talks only created by the UserId. 547 | 548 | In your Xcode project folder __amplify/backend/api/ConferenceAPI/resolvers__, create the following two NEW resolvers: 549 | 550 | - __Mutation.createTalk.req.vtl__ 551 | 552 | - __Query.listTalks.req.vtl__ 553 | 554 | Here's the __Mutation.createTalk.req.vtl__ code: 555 | 556 | ```vtl 557 | $util.qr($context.args.input.put("createdAt", $util.time.nowISO8601())) 558 | $util.qr($context.args.input.put("updatedAt", $util.time.nowISO8601())) 559 | $util.qr($context.args.input.put("__typename", "Talk")) 560 | $util.qr($context.args.input.put("userId", $ctx.identity.sub)) 561 | 562 | { 563 | "version": "2017-02-28", 564 | "operation": "PutItem", 565 | "key": { 566 | "id": $util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank($ctx.args.input.id, $util.autoId())) 567 | }, 568 | "attributeValues": $util.dynamodb.toMapValuesJson($context.args.input), 569 | "condition": { 570 | "expression": "attribute_not_exists(#id)", 571 | "expressionNames": { 572 | "#id": "id" 573 | } 574 | } 575 | } 576 | ``` 577 | 578 | Here's the __Query.listTalks.req.vtl__ code: 579 | 580 | ```vtl 581 | { 582 | "version" : "2017-02-28", 583 | "operation" : "Query", 584 | "index" : "userId-index", 585 | "query" : { 586 | "expression": "userId = :userId", 587 | "expressionValues" : { 588 | ":userId" : $util.dynamodb.toDynamoDBJson($ctx.identity.sub) 589 | } 590 | } 591 | } 592 | ``` 593 | 594 | Next, run the `amplify push` command to update the GraphQL API: 595 | 596 | ```sh 597 | amplify push 598 | ``` 599 | 600 | > Now that we've added authentication via Cognito User Pools to the GraphQL API, the users will need to log into the app (via basic auth) in order to perform mutations or queries. 601 | 602 | ### Testing the New Authentication in the AppSync Console 603 | For testing in the query feature of the AppSync Console, we'll need to authenticate a User Pool user via the `Login with User Pools` button in the queries section. The auth form requires a Client Id and basic auth credentials. You can find the App client Id `_clientWeb` under `App clients` of your User Pools settings in the [Cognito User Pools Console](https://console.aws.amazon.com/cognito/users). In the AppSync Console Query section, select and paste in the `_clientWeb` value into the ClienId field and then type your User Pool `username` & `password` you created previously. If successfully logged in, you can now test mutations and queries directly from the AppSync Console! 604 | 605 | From now on, when new talks are created, the `userId` field will be populated with the `userId` of the authenticated (logged in) user. 606 | 607 | When we query for talks in the Console or mobile app, we will only receive the talk data for the items that were created by the authenticated user. 608 | 609 | ```graphql 610 | query listTalks { 611 | listTalks { 612 | items { 613 | id 614 | name 615 | description 616 | speakerName 617 | speakerBio 618 | } 619 | } 620 | } 621 | ``` 622 | 623 | ## Removing Categories from Amplify Project 624 | 625 | If at any time, or at the end of this workshop, you would like to delete a category from your project & your account, you can do this by running the `amplify remove` command: 626 | 627 | ```sh 628 | amplify remove auth 629 | 630 | amplify push 631 | ``` 632 | 633 | If you are unsure of what services you have enabled at any time, you can run the `amplify status` command: 634 | 635 | ```sh 636 | amplify status 637 | ``` 638 | 639 | `amplify status` will give you the list of resources that are currently enabled in your app. 640 | 641 | ## Deleting the Amplify Project 642 | 643 | ```sh 644 | amplify delete 645 | ``` 646 | -------------------------------------------------------------------------------- /amplify-swift-logo-cli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmennis/aws-appsync-ios-workshop/6141148a1fd9dd5bb28eb5a0ef556e2e6235ecd0/amplify-swift-logo-cli.png --------------------------------------------------------------------------------