GraphQLReal WorldDanilo Assis
Danilo Assis
@daniloab
@daniloab_
Tech Lead - Fullstack Developer

Overview

GraphQL
What GraphQL Solves
Backend
Types
SDL First vs Code First
GraphQL Services BaaS
Testing
Frontend
Frameworks
Testing

GraphQL

  • launched by facebook
  • created on 2012 and open-sourced on 2015
  • it was created to resolve mobile team issues on Facebook
  • It is a Query language to read and mutate data
  • Based on three types: Query, Mutation and Subscription

What GraphQL Solves

  • Collocation of data requirements
  • Over-Fetching and Under-Fetching
  • Evolve APIs without versions
  • Strong type system
  • Creates a source of truth from the backend

TalkDeck App

Types

  • Schema
  • Query
  • Mutation
  • Subscription

Schema Type

  • Entry Point
  • Embraces the three types
  • Source of Truth

Query Type

  • Represents a data
  • Read
  • JSON
  • "I want a User and his/her name"

Query Example

Mutation Type

  • Mutate a data
  • Write followed by a Read
  • JSON
  • "I want to create a new User"
  • "Please, return the name at the end of creation"

Mutation Example

Subscription Type

  • Listen an event
  • Pub and Sub
  • JSON
  • "You receive a new like in your talk"

TalkDeck Types

SDL First vs Code First

SDL First vs Code First

  • Defines the GraphQL Schema Types
  • Works as a contract between frontend and backend
  • Schema first: we define the schema and make the code match with it
  • Code first: we code first and then the code generates our schema
  • Both schemas are generated with SDL (System Definition Language)
  • The choice is opinionated

SDL First - schema.graphql

input CreateUserInput {
name: String
}
type CreateUserPayload {
user: User
}
type Mutation {
"""Create a new user"""
CreateUser(input: CreateUserInput): CreateUserPayload
}
type Query {
version: String
me: User
users: [User]
user(id: ID!): User
talks: [Talk]
talk(id: ID!): Talk
}
type Like {
count: Int!
}
type LikeNewPayload {
like: Like
}
type Subscription {
LikeNew: LikeNewPayload
}
type Talk {
name: String!
description: String!
speaker: User!
host: User!
}
type User {
name: String!
}

Mutation

Code First - schema.ts

import { GraphQLSchema } from "graphql";
import { MutationType } from "./MutationType";
import { QueryType } from "./QueryType";
import SubscriptionType from "./SubscriptionType";
export const schema = new GraphQLSchema({
query: QueryType,
mutation: MutationType,
subscription: SubscriptionType,
});

Schema

Code First - QueryType

const host = {
id: "1",
name: "Daniel Cavalcante",
};
const speaker = {
id: "2",
name: "Danilo Assis",
};
const users = [speaker, host];
const talk = {
name: "GraphQL - Real World",
description: "Meetup Paraiba Js",
speaker: {
...speaker,
},
host: {
...host,
},
};
const talks = [talk];
export const QueryType = new GraphQLObjectType<
Record<string, unknown>,
GraphQLContext
>({
name: "Query",
fields: () => ({
version: {
type: GraphQLString,
resolve: () => version,
},
me: {
type: UserType,
resolve: () => ({
...speaker,
}),
},
users: {
type: GraphQLList(UserType),
resolve: (_) => {
return users;
},
},
user: {
type: UserType,
args: {
id: {
type: GraphQLNonNull(GraphQLID),
},
},
resolve: (_, args) => {
const user = users.find((user) => user.id === args.id);
return {
...user,
};
},
},
talks: {
type: GraphQLList(TalkType),
resolve: (_) => {
return talks;
},
},
talk: {
type: TalkType,
args: {
id: {
type: GraphQLNonNull(GraphQLID),
},
},
resolve: (_, args) => {
const talk = talks.find((talk) => talk.id === args.id);
return {
...talk,
};
},
},
}),
});

Query Type

HTTP Servers

Feel free to check

  • Express - https://expressjs.com/
  • Koa - https://koajs.com/
  • Apollo Server - https://www.apollographql.com/docs/apollo-server/
  • GraphQL Helix - https://github.com/contrawork/graphql-helix

Frontend Clients

  • Relay - https://relay.dev
  • Apollo - https://www.apollographql.com/docs/react/
  • urql - https://formidable.com/open-source/urql/
  • graphqlurql - https://github.com/hasura/graphqurl

GraphQL BaaS

  • Apollo Studio - https://www.apollographql.com/docs/studio/
  • AWS AppSync - https://aws.amazon.com/pt/appsync/
  • Back4App - https://www.back4app.com/
  • Hasura - https://hasura.io/

Handling Errors

  • Avoid status codes
  • Specific field for server errors
  • Specific Field for query, mutation, subscription error

GraphQL Error Example

Tests

  • Jest
  • Common scenarios: Queries, Node Queries, Mutation
  • Do a normally request passing into the body graphql string
  • Mock you database
  • Common scenarios: Queries, Node Queries, Mutation

Test Example - Query

it("should return a list of users", async () => {
const user = await createUser({ name: "user" });
const userB = await createUser({
name: "User B",
username: "user_xd_B",
email: "userB@test.com",
});
const userC = await createUser({
name: "User C",
username: "user_xd_C",
email: "userC@test.com",
});
const query = `
query Q {
users (first: 10) {
edges {
node {
name
username
email
}
}
}
}
`;
const variables = {};
const rootValue = {};
const context = await getContext({ user });
const result = await graphql(schema, query, rootValue, context, variables);
expect(result.errors).toBeUndefined();
expect(result.data.users.edges.length).toBe(3);
expect(result.data.users.edges[0].node.name).toBe(userC.name);
expect(result.data.users.edges[1].node.name).toBe(userB.name);
expect(result.data.users.edges[2].node.name).toBe(user.name);
});

Test Scenario Name

Language Support

The Documentary

References

  • https://smartbear.com/blog/what-is-graphql/
  • https://dev.to/juliansci/graphql-what-is-it-and-what-does-it-solve-15p1
  • https://blog.logrocket.com/code-first-vs-schema-first-development-graphql/
  • https://docs.gdc.cancer.gov/API/Users_Guide/GraphQL_Examples/
  • https://blog.graphqleditor.com/graphql-schemafirst-codefirst
  • https://graphql.org/blog/subscriptions-in-graphql-and-relay/
Be my Patreon:
https://www.patreon.com/daniloab
Social Medias
https://linktr.ee/daniloab
Give me a Feedback:
https://entria.feedback.house/danilo
Thanks!
We are hiring!
Join Us