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

API Days Paris 2018 – GraphQL server development

API Days Paris 2018 – GraphQL server development

Johannes Schickling

December 12, 2018
Tweet

More Decks by Johannes Schickling

Other Decks in Programming

Transcript

  1. Agenda 2 Introduction to Nexus + Demo 1 Overview: GraphQL

    server development 3 Type-safe DB access with Prisma + Demo
  2. Auto-generated, type-safe database client library Prisma Client ACCESS Visual database

    tooling and management Prisma Admin MANAGE Declarative data modeling and migrations Prisma Migrate MIGRATE
  3. • HTTP Server – Extracts GraphQL query and invokes GraphQL

    engine • GraphQL Exec Engine – Calls resolvers in right order & builds response • Schema & Resolvers – Defined and implemented by user to fetch data How GraphQL servers work RECAP
  4. TLDR: How to build a GraphQL server 2 Main task:

    Define and implement schema 1 Pick a GraphQL server framework
  5. What’s a GraphQL schema? • Defines the structure of your

    GraphQL API (Ask: What can I query for?) • Foundation for resolver functions • Intuitive representation as GraphQL SDL • Defined programmatically or declaratively type Query { posts: [Post!]! } type Post { id: ID! title: String! content: String! }
  6. graphql-js type Query { posts: [Post!]! } type Post {

    id: ID! title: String! content: String! }
  7. graphql-js const Query = new GraphQLObjectType({ name: "Query", fields: ()

    => ({ posts: { type: new GraphQLNonNull( new GraphQLList( new GraphQLNonNull(Post) ) ) } }) }) const Post = new GraphQLObjectType({ name: "Post", fields: () => ({ id: { type: new GraphQLNonNull(GraphQLID) }, title: { type: new GraphQLNonNull(GraphQLString) }, content: { type: new GraphQLNonNull(GraphQLString) } }) }) type Query { posts: [Post!]! } type Post { id: ID! title: String! content: String! }
  8. graphql-js GraphQL reference implementation for JavaScript AST-like API to construct

    schema → foundation for tooling Verbose API when building applications
  9. Schema-first Handwritten expressive schema as “contract" for resolvers Schema (SDL)

    SOURCE OF TRUTH EXAMPLES Apollo Server (JS), graphql-java, gqlgen (Go) type Query { posts: [Post] } type Post { id: ID! slug: String! content: String! } const resolvers = { Query: { posts: () => [{ ... }] }, Post: { id: parent => parent.id, title: parent => parent.title, content: parent => parent.content } } Resolvers have to match SDL
  10. const resolvers = { Query: { posts: (parent, args, context)

    => { return context.prisma.posts({ where: { published: true } }) }, }, Post: { author: ({ id }, args, context) => { return context.prisma.post({ id }).author() }, }, User: { posts: ({ id }, args, context) => { return context.prisma.user({ id }).posts() }, }, } schema.graphql resolvers.js type Query { posts: [Post!]! } type Post { title: String! content: String published: Boolean! author: User! } type User { email: String! name: String posts: [Post!]! }
  11. const resolvers = { Query: { posts: (parent, args, context)

    => { return context.prisma.posts({ where: { published: true } }) }, }, Post: { author: ({ id }, args, context) => { return context.prisma.post({ id }).author() }, }, User: { posts: ({ id }, args, context) => { return context.prisma.user({ id }).posts() }, }, } type Query { feed: [Post!]! } type Post { title: String! content: String published: Boolean! author: User! } type User { email: String! name: String posts: [Post!]! } Inconsistencies between SDL and Resolvers
  12. schema { query: Query mutation: Mutation subscription: Subscription } #

    The query type, represents all of the entry points into our object graph type Query { hero(episode: Episode): Character reviews(episode: Episode!): [Review] search(text: String): [SearchResult] character(id: ID!): Character droid(id: ID!): Droid human(id: ID!): Human starship(id: ID!): Starship } # The mutation type, represents all updates we can make to our data type Mutation { createReview(episode: Episode, review: ReviewInput!): Review } # The subscription type, represents all subscriptions we can make to our data type Subscription { reviewAdded(episode: Episode): Review How to deal with large schemas?
  13. Schema-first problems & tools to fix them Inconsistencies: graphqlgen, graphql-code-generator,

    … Modularization: graphql-modules, schema stitching, … Importing: graphql-import, … Code reuse: Schema directives, … Tooling/IDE support: gql-tag, … Solution: Programming languages
  14. Lessons learned: Resolver-first GraphQL released with graphql.js 2015 Schema-first with

    graphql-tools 2016 Schema-first “workarounds” 2017 / 2018 Resolver-first frameworks 2018 / 2019
  15. Resolver-first Schema derived from language type-system or annotations Resolvers (code)

    SOURCE OF TRUTH EXAMPLES Nexus (JS/TS), Sangira (Scala), Graphene (Python) const Post = objectType('Post', t => { t.id('id') t.string(‘title') t.string(‘content') }) type Post { id: ID! slug: String! content: String! } SDL is auto-generated
  16. Features of Nexus Smart schema-building (i.e. no-circular dependencies) Full type-safety

    in TypeScript & JavaScript (using VSC) Enables powerful module & plugin system
  17. Schema building with Nexus • Concise & intuitive API •

    Type references expressed as type-safe strings (“literals”) • Supports custom scalars interfaces, unions & mixins const Query = objectType('Query', t => { t.field('posts', 'Post', { list: true }) }) const Post = objectType('Post', t => { t.id('id') t.string('title') t.string('content') })
  18. Type-safety in Nexus • Provides predictability and extends GraphQL’s type

    system • Speeds up development (even in prototyping stage) • Based on built-in, self-updating type generation (disabled in prod) • Type-safe “areas” • Resolvers: Parent values, arguments, context, return values • Type <> Model mapping • Nexus API: Configuration & schema building
  19. End-to-end type-safety ✨ Holy Grail ✨ Map safely from one

    system/language into another. Ideally from row in database up to props in React component. GOAL Use code-generation to avoid type mismatches. STRATEGY
  20. Removes one of the most common causes of downtime Fixes

    biggest bottleneck: API <> DB mapping Makes most DB integration tests obsolete Why type-safe DB access?
  21. Access any DB from any language DB introspection-based or user-defined

    Auto-generated, type-safe client library High performance query engine
  22. Key Takeaways 3 Type-safe DB access prevents downtime and speeds

    up development with great DX Schema-first vs resolver-first 1 2 Nexus: Resolver-first GraphQL framework