GraphQL / Apollo Federation 🚀
Created by Facebook in 2012
Â
Open sourced in 2015
Â
Â
Created by Facebook in 2012
 Â
Open sourced in 201
GraphQL is a query language for your API
GraphQL is a PATTERNÂ not a technology
GraphQL doesn't store data
GraphQL is a replacement of REST
Created by Facebook in 2012
 Â
Open sourced in 201
Â
GraphQL is a replacement of REST
Â
Â
Â
Let's take an example
Instarwarsgram
Â
Let's take an example
Instarwarsgram
{
"data": {
"person": {
"name": "Darth Vader",
"birthYear": "41.9BBY",
"planet": {
"name": "Tatooine"
},
"movies": [
{ "title": "A New Hope" },
{ "title": "The Empire Strikes Back" },
{ "title": "Return of the Jedi" },
{ "title": "Revenge of the Sith" }
]
}
}
}
Instarwarsgram
People
Movies
Planet
GET - /person/42
GET - /movies/{id}
GET - /planets/{id}
{
"data": {
"person": {
"name": "Darth Vader",
"birthYear": "41.9BBY",
"planetId": 53,
"movieIds": [1, 2, 3, 6],
"saberColor"..
}
}
}
Instarwarsgram
People
Movies
Planet
GET - /person/42
GET - /movies/1
GET - /movies/2
GET - /movies/3
GET - /movies/5
GET - /movies/6
GET - /planets/53
{
"data": {
"person": {
"name": "Darth Vader",
"birthYear": "41.9BBY",
"planetId": 53,
"movieIds": [1, 2, 3, 6],
"saberColor"..
}
}
}
{
"data": {
"planet": {
"name": "Tatooine",
"positionX": "234.323",
"positionY...
},
}
}
{
"data": {
"movie": {
"title": "A New Hope",
},
}
}
{
"data": {
"movie": {
"title": "A New Hope",
},
}
}
{
"data": {
"movie": {
"title": "A New Hope",
},
}
}
{
"data": {
"movie": {
"id": 6
"title": "A New Hope",
"date": "19/10/1983",
"personIds"...
},
}
}
Pros and Cons?
Rest "Tailor Made"
Instarwarsgram
People
Movies
Planet
GET - /person/{id}
GET - /movies/{id}
GET - /planets/{id}
Rest "Tailor made"
People
Movies
Planet
Profile
GET - /profile/{id}
{
"data": {
"person": {
"name": "Darth Vader",
"birthYear": "41.9BBY",
"planet": {
"name": "Tatooine"
},
"movies": [
{ "title": "A New Hope" },
{ "title": "The Empire Strikes Back" },
{ "title": "Return of the Jedi" },
{ "title": "Revenge of the Sith" }
]
}
}
}
Pros and Cons?
GraphQL
GraphQL is WYSIWYG
query {
}
GraphQL is WYSIWYG
query {
person(id: 42)
}
GraphQL is WYSIWYG
query {
person(id: 42) {
name
birthYear
}
}
GraphQL is WYSIWYG
query {
person(id: 42) {
name
birthYear
planet {
name
}
movies {
title
}
}
}
GraphQL is WYSIWYG
query {
person(id: 42) {
name
birthYear
planet {
name
}
movies {
title
}
}
}
{
"person": {
"name": "Darth Vader",
"birthYear": "41.9BBY",
"planet": {
"name": "Tatooine"
},
"movies": [
{ "title": "A New Hope" },
{ "title": "The Empire Strikes Back" },
{ "title": "Return of the Jedi" },
{ "title": "Revenge of the Sith" }
]
}
}
Mmh in Vscode maybe?
query {
person(id: 42) {
name
birthYear
planet {
name
}
movies {
title
}
}
}
type Query {
person(id: ID!): Person
}
type Mutation {
destroyPlanet(planet: ID!): Boolean
}
type Person {
id: ID!
name: String!
birthYear: Int!
picture: String!
planet: Planet!
movies: [Movies]
}
type Planet {
id: ID!
name: String!
positionX: Int!
positionY: Int!
}
type Movie {
id: ID!
title: String!
date: DateTime
actors: [Person]
}
Front
const resolvers = {
Query: {
person: (_, args) => {
return PersonService.find(args.id);
}
},
Mutation: {},
Person: {},
Planet: {},
Movie: {},
}
Back
Well .. my app is getting bigger, I want to split it in microservices...
Monolith
People
Movies
Planet
http://sw.com
Microservices
People
Movies
Planet
http://people.com
http://movie.com
http://planets.com
Rest "Tailor made" (Monolith)
Â
People
Movies
Planet
Profile
GET - /profile/{id}
Text
Rest "Tailor made" (Microservices)
People
Movies
Planet
Profile
GET - /profile/{id}
Graphql
People
Movies
Planet
Profile
type Planet {
id: ID!
name: String!
positionX: Int!
positionY: Int!
}
type Movie {
id: ID!
title: String!
date: DateTime
actors: [Person]
}
type Person {
id: ID!
name: String!
birthYear: Int!
picture: String!
planet: Planet!
movies: [Movies]
}
type Query {
person(id: ID!): Person
}
People
Movies
Planet
Apollo Federation
Graphql
type Planet {
id: ID!
name: String!
positionX: Int!
positionY: Int!
}
type Movie {
id: ID!
title: String!
date: DateTime
actors: [Person]
}
type Person {
id: ID!
name: String!
birthYear: Int!
picture: String!
planet: Planet!
movies: [Movies]
}
type Query {
person(id: ID!): Person
}
Apollo Federation... How it works?
import { buildFederatedSchema } from '@apollo/federation';
import { ApolloServer, gql } from 'apollo-server';
const peopleServer = new ApolloServer({
schema: buildFederatedSchema({ typeDefs, resolvers})
});
peopleServer.listen(5001)
People
Â
import { ApolloGateway } from '@apollo/gateway';
const gateway = new ApolloGateway({
serviceList: [
{ name: 'people', url: 'http://localhost:5001' },
{ name: 'movies', url: 'http://localhost:5002' },
{ name: 'planet', url: 'http://localhost:5003' },
],
});
const gatewayServer = new ApolloServer({
gateway,
subscriptions: false,
});
type Person @key(fields: "id") {
id: ID!
name: String!
birthYear: Int!
picture: String!
}
type Person @key(fields: "name") @key(fields: "birthYear") {
name: String!
birthYear: Int!
picture: String!
}
 @key directive defines the entity's primary key.
Entity is an object type that you define in one implementing service and can then reference and extend in other implementing services.
Entity
type Person @key(fields: id) {
id: ID!
name: String!
birthYear: Int!
picture: String!
planet: Planet!
}
extend type Planet @key(fields: id) {
id: ID! @external
}
After you define an entity in one implementing service, other implementing services can then reference that entity.Â
type Planet {
id: ID!
name: String!
}
People microservices
Planet microservices
Referencing
type Person @key(fields: id) {
id: ID!
name: String!
birthYear: Int!
picture: String!
planet: Planet!
}
exten type Planet @key(fields: id) {
id: ID! @external
}
type Planet {
id: ID!
name: String!
}
{
People: {
planet(people) {
return {
__typename: "Planet",
id: people.planet_id
};
}
}
}
{
Planet: {
__resolveReference(reference) {
return PlanetService.findOne(reference.id);
}
}
}
Apollo Federation
type Person @key(fields: id) {
id: ID!
name: String!
birthYear: Int!
picture: String!
}
type Planet {
id: ID!
name: String!
}
extend type People @key(fields: id) {
id: ID! @external
planet: Planet
}
People microservices
Planet microservices
Extending
{
People: {
planet(reference) {
return reference.planet;
}
}
}
Apollo Federation
type Person @key(fields: id) {
id: ID!
name: String!
birthYear: Int!
picture: String!
}
type Planet {
id: ID!
name: String!
}
extend type People @key(fields: id) {
id: ID! @external
planet: Planet
}
type Saber {
id: ID!
color: String!
}
extend type People @key(fields: id) {
id: ID! @external
size: String @external
weight: String @external
birthYear: String @external
saber: String @requires(fields: "size weight birthYear")
}
Extending an entity with computed fields
Learning to scale. With GraphQL
By Luc MOMAL
Learning to scale. With GraphQL
- 214