Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rapid Development Techniques for APIs with GraphQL on AWS [Graph Meetup @ Milan]

Rapid Development Techniques for APIs with GraphQL on AWS [Graph Meetup @ Milan]

36ca8ae7e19067021d0e39c0b72acc2a?s=128

Alex Casalboni

May 07, 2019
Tweet

Transcript

  1. Alex Casalboni Technical Evangelist, AWS @alex_casalboni Rapid Development Techniques for

    APIs with GraphQL on AWS @ 2019, Amazon Web Services, Inc. or its Affiliates. All rights reserved bit.ly/graphql-aws-milano
  2. About me • Software Engineer & Web Developer • Worked

    in a startup for 4.5 years • ServerlessDays Organizer • AWS Customer since 2013
  3. This talk is for developers < frontend | backend >

  4. How do you prototype an API? bit.ly/graphql-aws-milano

  5. Congratulations! You’ve just been hired.

  6. Today’s mobile experience is lacking Mobile website, no native apps

    Slow to book, low conversion rates Backend built for high-speed desktops !
  7. Your job is to define tomorrow’s experience Digital agency hired

    for design First prototype in 4 weeks Must use real data, no mockup !
  8. Our Goal Enable backend services for prototype Allow design to

    evolve Keeping up with day-to-day job !
  9. { "_id": 3, "name": "ElastiLodge South Zanetown", "image": "https://placehold.it/300x300.png", "description":

    ” ... ", "location": "South Zanetown", "manager": { "name": ”Marco Rossi", "email": ”marco.rossi@elastilodge.com" }, "timeZone": "US/Central", "phoneNumber": "802-918-3262", "category": 5, "address": { "street": "410 Simonis Forest", "zip": "07545-2308", "city": "South Zanetown", "country": "Virgin Islands, British" }, "deskHours": "24 hours", "amenities": [ ... ], "restaurants": [ ... ] } Legacy REST API
  10. REST API challenges bit.ly/graphql-aws-milano

  11. /posts /comments /authors REST API Chatty & Over fetching {

    "posts" : [ { "id" : 1, "content" : "the quick brown fox jumps over the…", "author" : "/authors/123", "created" : 1550486509, "comments" : "/posts/1/comments", ... }, { "id" : 2, "content" : "the quick brown fox jumps over…", "author" : "/authors/123" "created" : 1550486509, "comments" : "/posts/2/comments", ... } ] }
  12. Why GraphQL bit.ly/graphql-aws-milano

  13. GraphQL is a query language for your API, and a

    server-side runtime for executing queries by using a type system you define for your data. https://graphql.org
  14. Why GraphQL? posts comments authors GraphQL API Type safe Contract-driven

    Efficient Easy to test Realtime
  15. How does GraphQL work? type Query { getTodos: [Todo] }

    type Todo { id: ID! name: String description: String priority: Int duedate: String } Model data with application schema query { getTodos { id name priority } } Client requests what it needs { "id": "1", "name": "Get Milk", "priority": "1" }, { "id": "2", "name": "Go to gym", "priority": "5" },… Only that data is returned
  16. GraphQL Operations Queries Read data Mutations Write data Subscriptions Listen

    for data query { search(q: “harry potter”) { title } } mutation { create(title: “new book”) { id } } subscription { onCreate { id title } }
  17. Is REST dead then? When data drives UI Structured data

    Query-driven Client-driven development Use GraphQL When you leverage HTTP Caching, Content types Hypermedia For resources (e.g. Amazon S3) Use REST Pick the appropriate protocol for your use case
  18. How to deploy a GraphQL API? bit.ly/graphql-aws-milano

  19. Welcome AWS AppSync! Managed & serverless Multiple data sources Data-sync,

    real-time, and offline Conflict detection in the cloud Enterprise security features
  20. Data Sources REST Endpoint /graphql Amazon Cognito Amazon DynamoDB AWS

    Lambda Amazon Elasticsearch Amazon RDS AWS Lambda
  21. Resolvers Amazon DynamoDB /graphql Request Resolver Maps payload to underlying

    data source via Velocity Template to execute query / mutation. Response Resolver Maps response from data source to GraphQL response via Velocity Template.
  22. KEEP CALM and WATCH the DEMO

  23. Let’s prototype! Phase #1: Hotel Detail bit.ly/graphql-aws-milano

  24. Hotel Detail: Design What data is required? Can we use

    existing data sources? How can we enable via AppSync? Challenges? Missing data?
  25. Mapping to Legacy API { "_id": 3, "image": "https://placehold.it/300x300.png", "name":

    "EL Resort & Spa", "description": "...", "location": "Fiji", "manager": { "name": "Florentino Jacobi", "email": "florentino.jacobi@elastilodge.com" }, "timeZone": "US/Central", "address": { "street": "123 Main St", ”postalcode": "07545", "city": "Momi Bay", "country": "Fiji" }, "phoneNumber": "1-888-123-4567", "category": 5, "deskHours": "24 hours", "amenities": [ ... ], "restaurants": [ ... ] }
  26. Hotel Detail: GraphQL Schema type Hotel { hotelId: ID! name:

    String! image: String location: String! phoneNumber: AWSPhone! address: Address! ... } type Query { listHotels(offset: String, limit: Int) getHotel(hotelId: ID!) }
  27. Hotel Detail: Resolvers ## Resolver: Request Mapping ## { "version":

    "2018-05-29", "method": "GET", "resourcePath": "/hotels/${ctx.args.hotelId}", "params": { "headers": { "Content-Type": "application/json" } }, } ## Resolver: Response Mapping ## #if($ctx.result.statusCode == 200) ## If response is 200, return the body. ## Could also filter result... $ctx.result.body #else ## If not 200, append response to error $utils.appendError($ctx.result.body) #end
  28. Hotel Detail: Result query { getHotel(hotelId: 3) { name location

    image phoneNumber address { street city } amenities } } { "name": "ElastiLodge North Rodgerstad", "location": "North Rodgerstad", "image": "/300x300.png", "phoneNumber": "(214) 210-4674", "address": { "street": "123 Main St", "city": "North Rodgerstad" }, "amenities": [ ... ] } (from 8KB to 312B -> 93% lighter response)
  29. Mobile Code – Initialize App Sync Client do { //

    create app sync configuration (cache, service config etc) let config = … // client initialization let appSyncClient = try AWSAppSyncClient(appSyncConfig: config) } catch { fatalError("Error initializing appsync client. \(error)") }
  30. Mobile Code – Run a Query // call a GraphQL

    Query appSyncClient?.fetch(query: GetHotelQuery(hotelId: hotelId), cachePolicy: .fetchIgnoringCacheData) {(result, error) in guard let r = result, error == nil else { print(error?.localizedDescription ?? "") return } // use the data in the GUI self.hotelDetails = r.data?.getHotel … }
  31. KEEP CALM and WATCH the DEMO

  32. Let’s prototype! Phase #2: Reservations bit.ly/graphql-aws-milano

  33. Reservations: Design What data is required? Can we use existing

    data sources? How can we enable via AppSync? Challenges?
  34. Reservations: GraphQL Schema type Reservation { confirmationNumber: ID! hotel: Hotel!

    guest: User! startDate: AWSDate! endDate: AWSDate! rate: Int! } type Query { ... reservations(guestId : ID!):[Reservation] } type Mutation { createReservation(input:ReservationInput) deleteReservation(confNum: ID!) }
  35. Reservations: Query Resolver - Input #set( $todayString = $util.time.nowISO8601().substring(0, 10)

    ) { "version": "2017-02-28", "operation": "Query", "query": { "expression": "guestId = :gId AND startDate > :startDate", "expressionValues": { ":gId": $util.dynamodb.toDynamoDBJson($ctx.identity.sub), ":startDate": $util.dynamodb.toDynamoDBJson($todayString) } } }
  36. Reservations: Query Resolver - Output $util.toJson($ctx.result.items)

  37. Reservations: Result query { guestReservations { confirmationNumber hotel { hotelId

    name image phoneNumber } startDate endDate } }
  38. Extending Reservation Workflow Legacy System /graphql Subscription (MQTT) Mutate reservation

    record, modifying record in DynamoDB and triggering subscription DynamoDB Stream: Put event in queue for processing AWS Lambda AWS Lambda Amazon DynamoDB Amazon SNS Amazon SNS
  39. Subscription Query subscription ReservationSubscription { createReservationEvent(guestId:1) { confirmationNumber } }

  40. Mobile Code – Subscribe to changes let sub = CreateReservationEventSubscription(guestId:

    userId) newReservationSubscription = try appSyncClient?.subscribe(subscription: sub, resultHandler: { (result, transaction, error) in // check for error // store a reference to the new booking into our cache transaction?.update(query: GuestReservationsQuery(guestId: userId)) { (data: inout GuestReservationsQuery.Data) in data.guestReservations?.append(bookingToAdd) // consume the data in the UI self.bookingDetails?.append(bookingToAdd) } }
  41. KEEP CALM and WATCH the DEMO

  42. Let’s prototype! Phase #3: Adaptive rates bit.ly/graphql-aws-milano

  43. Adaptive Rates: Design R&D is building an adaptive rate capability

    Delivered via Amazon SageMaker API How do we add today’s rate to our existing API?
  44. How to evolve our GraphQL API GraphQL supports multiple data

    sources per query: 1. Add new field 2. Configure new Data Source and Resolvers
  45. Adaptive Rates: GraphQL Types and Resolvers type Hotel { hotelId:

    ID! name: String! location: String! ... rate: Rate } type Rate { hotelId: ID! rate: Int! currency: String! date: AWSDate! } ## rate Field Resolver: Request Mapping ## { "version": "2018-05-29", "method": "GET", "resourcePath": "/rd/rates/${ctx.source.hotelId}", "params": { "headers": { "Content-Type": "application/json" } } }
  46. Adaptive Rates: Result query { getHotel(hotelId: 3) { name location

    image phoneNumber address { street city } amenities rate { currency rate } } } { "name": "ElastiLodge North Rodgerstad", "location": "North Rodgerstad", "image": "https://placehold.it/300x300.png", "phoneNumber": "(214) 210-4674", "address": { "street": “...", "city": “..." }, "amenities": [ ... ], "rate": { "currency": "USD", "rate": 312 } }
  47. KEEP CALM and WATCH the DEMO

  48. What did we just do? bit.ly/graphql-aws-milano

  49. What did we accomplish today? Built a rich, flexible, mobile-ready

    API Incorporated legacy, new, and prototype features in a single endpoint Evolved API as requirements changed No coding required! Well, there were a few Velocity Templates AWS Console includes starter / boilerplate templates
  50. AWS Amplify CLI Toolchain for developers Enables you to prototype

    and build quickly Built-in GraphQL Transformer Converts schema to CloudFormation templates and builds cloud resources $ amplify api add # create GraphQL schema # for example: type Hotel @model @searchable { name: String! location: String! ... } github.com/aws-amplify/amplify-cli
  51. Backend Dev: Hmm. So you’re saying this “GraphQL” will allow

    any web/mobile developer to arbitrarily query basically any field in any backend service, recursively, however they want, without any backend developers involved? Frontend Dev: Yeah, right? It’s amazing! […silence…] Backend Dev: Guards, seize this person.
  52. Real-world pitfalls Cost of queries on the backend Authentication and

    authorization
  53. Code presented today github.com/sebsto/reinvent2018-mob320

  54. Alex Casalboni Technical Evangelist, AWS @alex_casalboni @ 2019, Amazon Web

    Services, Inc. or its Affiliates. All rights reserved Thank you! bit.ly/graphql-aws-milano