GraphQL
APIs mais robustas e flexíveis
@brunolemos
Sobre mim
➔Desenvolvedor Web desde ~2005
➔Formado na USP de São Carlos
➔Full Stack Developer na startup Easy Carros
➔Hacka...
O que iremos abordar?
1. Motivação // que problemas resolve?
2. Características // query language, ...
3. Queries & Mutati...
1.Motivação
Imagine uma aplicação na qual você pode:
1. Adicionar amigos
2. Publicar posts
3. Curtir páginas
1. Motivação
Como você pegaria o último post de cada amigo seu?
1. Motivação
Usando REST
GET /v1/me { _id: 1, friends: [2,
3, 4,5] }
GET /v1/users/2/posts/last {_id: ‘post_2a’}
GET /v1/users/3/posts/...
GET /v1/myFriendsLastPosts [{_id: 1, lastPost: {...}, {_id: 2, lastPost:
{...}]
Usando “REST”
E se eu quiser obter as pági...
E se eu quiser obter as páginas que meus amigos curtiram e os últimos posts?
GET /v1/myFriendsLikedPages [{_id: 1, pages: ...
GET /v1/myFriendsLikedPages [{_id: 1, pages: [...]}, {_id: 2, pages: [...]}]
GET /v1/myFriendsLastPosts [{_id: 1, lastPost...
No REST, é fácil você se encontrar criando endpoints para retornos específicos.
Isto não é escalável.
1. Motivação
Além disso…
Ao fazer um GET em um endpoint, que dados serão retornados? #surprise
Como descobrir:
1. Fazer uma requisição ...
“Analisamos alternativas, como o REST. (...) Ficamos frustados com as diferenças entre os
dados que queríamos e as request...
GraphQL é criado pelo Facebook
Usado apenas internamente
2012
1. Motivação
GraphQL liberado para o público (open source)
2015
1. Motivação
Características
O client declara os dados que precisa e a resposta é um espelho da entrada
“Retorne isto. Nada mais, nada menos.”
Declarat...
Funções “resolve”
Visão geral
Características
Resposta em JSON
no mesmo formato
da entrada
Entrada dos dados
que precisa
C...
Na função resolve, você é livre para pegar o dado de onde quiser
// Funções “resolve” são as responsáveis por dizer onde p...
Sintaxe
Query
Queries são como o GET do REST:
Você usa para obter dados, não podendo fazer mutações.
Query
Sintaxe
query {
user(_id: “xxx”) {
_id
name
}
}
{
"data": {
"user": {
"_id": "xxx",
"name": "Bruno Lemos"
}
}
}
Query: Várias ao mesmo tempo
Sintaxe
query {
user(_id: “xxx”) {
_id
name
}
vehicle(_id: “tesla_model_s”) {
brand
model
}
}...
Query: Várias ao mesmo tempo
Sintaxe
query {
user(_id: “xxx”) {
_id
name
}
user(_id: “xxx”) {
github
}
}
{
"data": {
?
}
}
Query: Várias ao mesmo tempo
Sintaxe
query {
user(_id: “xxx”) {
_id
name
}
user(_id: “xxx”) {
github
}
}
{
"data": {
"user...
Query: Várias ao mesmo tempo
Sintaxe
query {
user(_id: “xxx”) {
_id
name
}
user(_id: “xxx_2”) {
github
}
}
{
"data": {
?
}...
Query: Várias ao mesmo tempo
Sintaxe
query {
user(_id: “xxx”) {
_id
name
}
user(_id: “xxx_2”) {
github
}
}
{
"errors": [{
...
Query: Alias
Sintaxe
query {
dan: user(_id: “dan_id”) {
_id
name
}
arunoda: user(_id: “arunoda_id”) {
_id
name
}
}
{
"data...
Query: Nested
Sintaxe
query {
user(_id: “xxx”) {
_id
name
friends(limit: 1) {
name
}
}
}
{
"data": {
"user": {
"_id": "xxx...
Query: Nested!!!
Sintaxe
query {
user(_id: “xxx”) {
_id
name
friends(limit: 1) {
name
friends(limit: 1) {
name
}
}
}
}
{
"...
Query: Nested (exemplo inicial)
Sintaxe
{
"data": {
"user": {
"name": "Bruno Lemos",
"friends": [{
"name": "Sashko Stubail...
Query: Nested + Utils
Sintaxe
query {
user(_id: “xxx”) {
thumbnail: image(size: 100) {
url
width
height
}
fullPicture: ima...
Query: Nested + Utils
Sintaxe
query {
user(_id: “xxx”) {
createdAt {
format(format: "DD/MM/YYYY HH:mm")
timezone
iso
times...
Query: Nested + Utils
Sintaxe
query {
user(_id: “xxx”) {
createdAt(timezone: “America/New_York”) {
format(format: "DD/MM/Y...
Query
Ok, o campo name é sempre String, o campo age é sempre Int, …
E se eu tiver um campo que possa retornar mais de um t...
query {
me {
__typename
... on Admin {
name
}
... on User {
name
age
}
}
}
Query: Múltiplos tipos
Sintaxe
{
"data": {
"me"...
query {
me {
__typename
... on Admin {
name
}
... on User {
name
age
}
}
}
Query: Múltiplos tipos
Sintaxe
{
"data": {
"me"...
Ok, chega de query
Se as queries são como o GET do REST, como fazer o POST / PUT / DELETE?
Mutation
Mutations são como o POST / PUT / DELETE do REST:
Você usa quando haverá alteração nos dados.
[POST] /v1/users
[P...
Mutation
Sintaxe
mutation {
addUser(name: “Bruno Lemos”) {
_id
name
}
}
{
"data": {
"addUser": {
"_id": "xxx_2",
"name": "...
Mutation
Sintaxe
mutation {
deleteUser(_id: “xxx”)
}
{
"data": {
"deleteUser": true
}
}
Mutation
Sintaxe
mutation {
deleteUser(_id: “id_nao_existente”)
}
{
"data": {
?
}
}
Mutation
Sintaxe
mutation {
deleteUser(_id: “id_nao_existente”)
}
{
"data": {
"deleteUser": null
},
"errors": [
{
"message...
Variáveis
Sintaxe
mutation($name: String!) {
addUser(name: $name) {
_id
name
}
}
//QUERY VARIABLES
{
"name": "Bruno Lemos"...
Fragment
Sintaxe
{
"data": {
"user": {
"_id": "xxx",
"name": "Bruno Lemos",
"github": "brunolemos"
}
}
}
query {
user(_id:...
Na prática
Adicionando GraphQL à uma API já existente
Vamos criar uma query que receba um argumento _id e retorne o usuário
correspondente.
Na prática
// Vamos usar Node.js
// Dependências:
$ npm i -S express graphql express-graphql
Antes de tudo...
Servidor
index.js
const express = require('express');
const app = express();
const server = app.listen(process.env.PORT || 3000, ()...
./user/type.js
export default new GraphQLObjectType({
name: 'User',
fields: {
_id: { type: new GraphQLNonNull(GraphQLID) }...
./user/query.js
Cada Query é um objeto comum
Define o tipo de retorno, os argumentos de entrada e a função “resolve”
Crian...
schema.js
export default new GraphQLSchema({
query: new GraphQLObjectType({
name: 'RootQuery',
fields: {
user: UserQuery, ...
Autenticação
Autenticação
query {
login(email: “x@gmail.com”, password: “123”) {
token
_id
name
}
}
{
"data": {
"login": {
"token": "AB...
Autenticação
query {
viewer(token: “ABCDEF”) {
me {
_id
name
}
}
}
{
"data": {
"viewer": {
"me": {
"_id": "xxx",
"name": "...
Autenticação
mutation {
viewer(token: “ABCDEF”) {
deleteUser(_id: “xxx”)
}
}
{
"data": {
"viewer": {
"deleteUser": true
}
...
Autenticação
mutation {
viewer(token: “ABCDEF”) {
deleteUser(_id: “id_de_outro_usuario”)
}
}
{
"data": {
"viewer": {
"dele...
./viewer/query.js
export default {
ViewerRootQuery, // todas as queries que estarão dentro da query viewer
args: {
token: ...
GraphiQL
GraphiQL
http://localhost:3000/graphql
http://localhost:3000/graphql
GraphiQL
Documentação automática
GraphiQL
Documentação automática
http://localhost:3000/graphql
GraphiQL
Documentação automática, execução de queries
http://localhost:3000/graphql
GraphiQL
Documentação automática, execução de queries
http://localhost:3000/graphql
GraphiQL
Documentação automática, execução de queries, autocomplete
http://localhost:3000/graphql
GraphiQL =
Documentação automática, execução de queries, autocomplete, …
http://localhost:3000/graphql
GraphiQL =
Documentação automática, execução de queries, autocomplete, … É como ter um Graph API Explorer próprio!
https:/...
Client
No React, cada parte da aplicação é um Component
Cada Component sabe os dados que precisa
Como obter estes dados do GraphQ...
Client: Relay
Client: Relay
Client: Relay
class UserProfile extends Component {
render() {
var { name, avatar } = this.props.user;
return (
<div>
<img...
Client: Relay
Relay
UserProfile = Relay.createContainer(UserProfile, {
fragments: {
user: () => Relay.QL`
fragment on User...
Libs
Server
GraphQL não é apenas para Node.js.
Existem implementações para Ruby, PHP, Go, Python, Haskell, ...
Client
Relay (re...
Libs
Utils
Graffiti (usar schema do Mongoose)
Model Visualizer (converta seu schema em um diagrama)
Services
Reindex (back...
Próximos passos
Não abordamos:
Cache / DataLoader
Client a fundo (Como fazer mutations, …)
Do GraphQL:
Subscriptions / realtime
Directives...
GraphQL é o futuro?
Obrigado
@brunolemos
Próximos SlideShares
Carregando em…5
×

GraphQL - APIs mais robustas e flexíveis

1.094 visualizações

Publicada em

Será que o GraphQL pode ser tornar a nova forma padrão de escrever APIs, substituindo o REST que domina o mercado desde a década de 90?

Publicada em: Tecnologia

GraphQL - APIs mais robustas e flexíveis

  1. 1. GraphQL APIs mais robustas e flexíveis @brunolemos
  2. 2. Sobre mim ➔Desenvolvedor Web desde ~2005 ➔Formado na USP de São Carlos ➔Full Stack Developer na startup Easy Carros ➔Hackathons ◆ 1º lugar - Hackathon Globo 2016 ◆ 1º lugar - MasterCard Code4Inclusion Miami ◆ 2º lugar - Masters of Code São Paulo ◆ 1º lugar - Destination Hack ◆ 1º lugar - API Hackday SP @brunolemos
  3. 3. O que iremos abordar? 1. Motivação // que problemas resolve? 2. Características // query language, ... 3. Queries & Mutations // query { user(id: 1) { name } } 4. Na prática // adicionando GraphQL à uma API já existente 5. Autenticação // segurança 6. Client & Libs // relay, apollo, … 7. Próximos passos // o que não abordamos + futuro do graphql
  4. 4. 1.Motivação
  5. 5. Imagine uma aplicação na qual você pode: 1. Adicionar amigos 2. Publicar posts 3. Curtir páginas 1. Motivação
  6. 6. Como você pegaria o último post de cada amigo seu? 1. Motivação
  7. 7. Usando REST GET /v1/me { _id: 1, friends: [2, 3, 4,5] } GET /v1/users/2/posts/last {_id: ‘post_2a’} GET /v1/users/3/posts/last {_id: ‘post_3a’} GET /v1/users/4/posts/last {_id: ‘post_4a’} GET /v1/users/5/posts/last {_id: ‘post_5a’} 1. Motivação Muitas requisições… Já sei, vou criar um endpoint para isso.
  8. 8. GET /v1/myFriendsLastPosts [{_id: 1, lastPost: {...}, {_id: 2, lastPost: {...}] Usando “REST” E se eu quiser obter as páginas que meus amigos curtiram? 1. Motivação
  9. 9. E se eu quiser obter as páginas que meus amigos curtiram e os últimos posts? GET /v1/myFriendsLikedPages [{_id: 1, pages: [...]}, {_id: 2, pages: [...]}] Usando “REST” 1. Motivação
  10. 10. GET /v1/myFriendsLikedPages [{_id: 1, pages: [...]}, {_id: 2, pages: [...]}] GET /v1/myFriendsLastPosts [{_id: 1, lastPost: {...}}, {_id: 2, lastPost: {...}}] Usando “REST” 1. Motivação // faço o merge dos resultados no client [{_id: 1, lastPost: {...}, pages: [...]}, ...] // já sei! que tal um novo endpoint? GET /v1/myFriendsLastPostsAndPages 👎👎👎👎👎👎
  11. 11. No REST, é fácil você se encontrar criando endpoints para retornos específicos. Isto não é escalável. 1. Motivação
  12. 12. Além disso… Ao fazer um GET em um endpoint, que dados serão retornados? #surprise Como descobrir: 1. Fazer uma requisição de teste 2. Ler a documentação (pode estar desatualizada) 3. Ler o código Dados retornados: 1. Provavelmente muito mais do que você precisa 1. Motivação
  13. 13. “Analisamos alternativas, como o REST. (...) Ficamos frustados com as diferenças entre os dados que queríamos e as requests que eram necessárias para obtê-los.” 2012 Lee Byron, Facebook Software Engineer 1. Motivação
  14. 14. GraphQL é criado pelo Facebook Usado apenas internamente 2012 1. Motivação
  15. 15. GraphQL liberado para o público (open source) 2015 1. Motivação
  16. 16. Características
  17. 17. O client declara os dados que precisa e a resposta é um espelho da entrada “Retorne isto. Nada mais, nada menos.” Declarative query language //REQUEST query { user(_id: “xxx”) { _id name email } } //RESPONSE { "data": { "user": { "_id": "xxx", "name": "Bruno Lemos", "email": "brunohplemos@gmail.com" } } } Características
  18. 18. Funções “resolve” Visão geral Características Resposta em JSON no mesmo formato da entrada Entrada dos dados que precisa Camada do GraphQL Diferentes clients Bancos de dadosServidor Retorno da função “resolve” com os dados desejados
  19. 19. Na função resolve, você é livre para pegar o dado de onde quiser // Funções “resolve” são as responsáveis por dizer onde pegar os dados. // Podem retornar dados de qualquer lugar, desde que retorne o valor final ou uma Promise. // Exemplos para query { user(_id: “xxx”) { name } } resolve: (root, args, context) => ({ name: ‘Bruno Lemos’, outroCampo: ‘X’ }), // Dado arbitrário resolve: (root, args, context) => User.findById(args._id), // Método que retorna uma promise resolve: (root, args, context) => fetch(‘http://api.site.com/v1/user’), // API externa Características Funções “resolve”
  20. 20. Sintaxe
  21. 21. Query Queries são como o GET do REST: Você usa para obter dados, não podendo fazer mutações.
  22. 22. Query Sintaxe query { user(_id: “xxx”) { _id name } } { "data": { "user": { "_id": "xxx", "name": "Bruno Lemos" } } }
  23. 23. Query: Várias ao mesmo tempo Sintaxe query { user(_id: “xxx”) { _id name } vehicle(_id: “tesla_model_s”) { brand model } } { "data": { "user": { "_id": "xxx", "name": "Bruno Lemos" }, "vehicle": { "brand": "Tesla", "model": "Model S" } } }
  24. 24. Query: Várias ao mesmo tempo Sintaxe query { user(_id: “xxx”) { _id name } user(_id: “xxx”) { github } } { "data": { ? } }
  25. 25. Query: Várias ao mesmo tempo Sintaxe query { user(_id: “xxx”) { _id name } user(_id: “xxx”) { github } } { "data": { "user": { "_id": "xxx", "name": "Bruno Lemos", "github": "brunolemos" }, } }
  26. 26. Query: Várias ao mesmo tempo Sintaxe query { user(_id: “xxx”) { _id name } user(_id: “xxx_2”) { github } } { "data": { ? } }
  27. 27. Query: Várias ao mesmo tempo Sintaxe query { user(_id: “xxx”) { _id name } user(_id: “xxx_2”) { github } } { "errors": [{ "message": "Fields "user" conflict because they have differing arguments. use different aliases on the fields to fetch both if this was intentional." }] }
  28. 28. Query: Alias Sintaxe query { dan: user(_id: “dan_id”) { _id name } arunoda: user(_id: “arunoda_id”) { _id name } } { "data": { "dan": { "_id": "dan_id", "name": "Dan Abramov", }, "arunoda": { "_id": "arunoda_id", "name": "Arunoda Susiripala", } } }
  29. 29. Query: Nested Sintaxe query { user(_id: “xxx”) { _id name friends(limit: 1) { name } } } { "data": { "user": { "_id": "xxx", "name": "Bruno Lemos", "friends": [{ "name": "Dan Abramov" ]} } } }
  30. 30. Query: Nested!!! Sintaxe query { user(_id: “xxx”) { _id name friends(limit: 1) { name friends(limit: 1) { name } } } } { "data": { "user": { "_id": "xxx", "name": "Bruno Lemos", "friends": [{ "name": "Dan Abramov", "friends": [{ "name": "Arunoda Susiripala" }], }], }, } }
  31. 31. Query: Nested (exemplo inicial) Sintaxe { "data": { "user": { "name": "Bruno Lemos", "friends": [{ "name": "Sashko Stubailo", "latestPost": { "title": "GraphQL is the future" }, "pages": [{ "name": "Apollo Client" }], }], }, } } query { user(_id: “xxx”) { name friends { name latestPost { title } pages { name } } } }
  32. 32. Query: Nested + Utils Sintaxe query { user(_id: “xxx”) { thumbnail: image(size: 100) { url width height } fullPicture: image { url width height } } } { "data": { "user": { "thumbnail": { "url": "thumbnail_100x100.jpg", "width": 100, "height": 100 }, "fullPicture": { "url": "picture.jpg", "width": 2048, "height": 2048 } } } }
  33. 33. Query: Nested + Utils Sintaxe query { user(_id: “xxx”) { createdAt { format(format: "DD/MM/YYYY HH:mm") timezone iso timestamp } } } { "data": { "user": { "createdAt": { "format": "01/09/2016 19:30", "timezone": "America/Sao_Paulo", "iso": "2016-09-01T22:30:00.000Z", "timestamp": "1472769000000" } } } }
  34. 34. Query: Nested + Utils Sintaxe query { user(_id: “xxx”) { createdAt(timezone: “America/New_York”) { format(format: "DD/MM/YYYY HH:mm") timezone } } } { "data": { "user": { "createdAt": { "format": "01/09/2016 18:30", "timezone": "America/New_York" } } } }
  35. 35. Query Ok, o campo name é sempre String, o campo age é sempre Int, … E se eu tiver um campo que possa retornar mais de um tipo? Exemplo: campo user que pode ser tanto do tipo User quanto Admin
  36. 36. query { me { __typename ... on Admin { name } ... on User { name age } } } Query: Múltiplos tipos Sintaxe { "data": { "me": { "__typename": "Admin", "name": "Bruno Lemos" } } } A query ‘me’ pode retornar um tipo diferente dependendo de quem está logado no momento
  37. 37. query { me { __typename ... on Admin { name } ... on User { name age } } } Query: Múltiplos tipos Sintaxe { "data": { "me": { "__typename": "User", "name": "Bruno Lemos", "age": 23 } } } A query ‘me’ pode retornar um tipo diferente dependendo de quem está logado no momento
  38. 38. Ok, chega de query Se as queries são como o GET do REST, como fazer o POST / PUT / DELETE?
  39. 39. Mutation Mutations são como o POST / PUT / DELETE do REST: Você usa quando haverá alteração nos dados. [POST] /v1/users [PUT] /v1/users/1 [DELETE] /v1/users/1 addUser(name: “Mateus”) updateUser(_id: 1, name: “Matheus”) deleteUser(_id: 1)
  40. 40. Mutation Sintaxe mutation { addUser(name: “Bruno Lemos”) { _id name } } { "data": { "addUser": { "_id": "xxx_2", "name": "Bruno Lemos" } } }
  41. 41. Mutation Sintaxe mutation { deleteUser(_id: “xxx”) } { "data": { "deleteUser": true } }
  42. 42. Mutation Sintaxe mutation { deleteUser(_id: “id_nao_existente”) } { "data": { ? } }
  43. 43. Mutation Sintaxe mutation { deleteUser(_id: “id_nao_existente”) } { "data": { "deleteUser": null }, "errors": [ { "message": "Usuário não encontrado.", "path": [ "deleteUser" ], } ] }
  44. 44. Variáveis Sintaxe mutation($name: String!) { addUser(name: $name) { _id name } } //QUERY VARIABLES { "name": "Bruno Lemos" } { "data": { "addUser": { "_id": "xxx_3", "name": "Bruno Lemos" } } }
  45. 45. Fragment Sintaxe { "data": { "user": { "_id": "xxx", "name": "Bruno Lemos", "github": "brunolemos" } } } query { user(_id: “xxx”) { _id ...RetornoPadrao } } fragment RetornoPadrao on User { name github }
  46. 46. Na prática Adicionando GraphQL à uma API já existente
  47. 47. Vamos criar uma query que receba um argumento _id e retorne o usuário correspondente. Na prática
  48. 48. // Vamos usar Node.js // Dependências: $ npm i -S express graphql express-graphql Antes de tudo... Servidor
  49. 49. index.js const express = require('express'); const app = express(); const server = app.listen(process.env.PORT || 3000, () => { const { address, port } = server.address(); console.log(`Running at http://${address}:${port}`); }); Criando o servidor const graphqlHTTP = require('express-graphql'); const schema = require('./schema'); //será criado em breve app.use('/graphql', graphqlHTTP({ schema, graphiql: true }));
  50. 50. ./user/type.js export default new GraphQLObjectType({ name: 'User', fields: { _id: { type: new GraphQLNonNull(GraphQLID) }, name: { type: GraphQLString }, }, }); Precisamos criar o tipo Usuário, que será o retorno da query Tipos já existentes: ID, String, Int, Boolean, Object, Enum, List, … (ver lista completa) Criando o servidor
  51. 51. ./user/query.js Cada Query é um objeto comum Define o tipo de retorno, os argumentos de entrada e a função “resolve” Criando o servidor // bluebird converte uma funcao que pussui callback em uma promise const getUserAsync = Bluebird.promisify(myMethodFromOldApiThatUsesCallback); export default { type: UserType, // arquivo criado anteriormente args: { _id: { type: new GraphQLNonNull(GraphQLID) }, }, resolve: (root, args, context) => getUserAsync(args._id), // onde a mágica acontece };
  52. 52. schema.js export default new GraphQLSchema({ query: new GraphQLObjectType({ name: 'RootQuery', fields: { user: UserQuery, // arquivo criado anteriormente // users: ..., // aqui iria as outras queries // posts: ..., }, }), mutation: ..., // definirá todas as mutations existentes (mesma sintaxe acima) }); Schemas possuem uma RootQuery e uma RootMutation Criando o servidor
  53. 53. Autenticação
  54. 54. Autenticação query { login(email: “x@gmail.com”, password: “123”) { token _id name } } { "data": { "login": { "token": "ABCDEF", "_id": "xxx", "name": "Bruno Lemos" } } } Autenticação
  55. 55. Autenticação query { viewer(token: “ABCDEF”) { me { _id name } } } { "data": { "viewer": { "me": { "_id": "xxx", "name": "Bruno Lemos" } } } } Autenticação
  56. 56. Autenticação mutation { viewer(token: “ABCDEF”) { deleteUser(_id: “xxx”) } } { "data": { "viewer": { "deleteUser": true } } } Autenticação
  57. 57. Autenticação mutation { viewer(token: “ABCDEF”) { deleteUser(_id: “id_de_outro_usuario”) } } { "data": { "viewer": { "deleteUser": null } }, "errors": [ { "message": "Não autorizado.", "path": [ "deleteUser" ], } ] } Autenticação
  58. 58. ./viewer/query.js export default { ViewerRootQuery, // todas as queries que estarão dentro da query viewer args: { token: { type: GraphQLString }, }, resolve: (root, { token }, context) => { // context é global, acessível de todas as queries context.token = token; try { context.user = jwt.verify(token, config.jwtSecret) || {}; } catch (err) { context.user = {}; } return {}; }, }; Autenticação
  59. 59. GraphiQL
  60. 60. GraphiQL http://localhost:3000/graphql
  61. 61. http://localhost:3000/graphql GraphiQL Documentação automática
  62. 62. GraphiQL Documentação automática http://localhost:3000/graphql
  63. 63. GraphiQL Documentação automática, execução de queries http://localhost:3000/graphql
  64. 64. GraphiQL Documentação automática, execução de queries http://localhost:3000/graphql
  65. 65. GraphiQL Documentação automática, execução de queries, autocomplete http://localhost:3000/graphql
  66. 66. GraphiQL = Documentação automática, execução de queries, autocomplete, … http://localhost:3000/graphql
  67. 67. GraphiQL = Documentação automática, execução de queries, autocomplete, … É como ter um Graph API Explorer próprio! https://developers.facebook.com/tools/explorer
  68. 68. Client
  69. 69. No React, cada parte da aplicação é um Component Cada Component sabe os dados que precisa Como obter estes dados do GraphQL? Client
  70. 70. Client: Relay
  71. 71. Client: Relay
  72. 72. Client: Relay class UserProfile extends Component { render() { var { name, avatar } = this.props.user; return ( <div> <img src={avatar}/> <p>{name}</p> </div> ); } } // continua... Relay
  73. 73. Client: Relay Relay UserProfile = Relay.createContainer(UserProfile, { fragments: { user: () => Relay.QL` fragment on User { name, avatar, } `, }, });
  74. 74. Libs
  75. 75. Server GraphQL não é apenas para Node.js. Existem implementações para Ruby, PHP, Go, Python, Haskell, ... Client Relay (react) Apollo (react, angular, ios swift, ...) Libs
  76. 76. Libs Utils Graffiti (usar schema do Mongoose) Model Visualizer (converta seu schema em um diagrama) Services Reindex (backend as a service) Lista completa: Awesome GraphQL
  77. 77. Próximos passos
  78. 78. Não abordamos: Cache / DataLoader Client a fundo (Como fazer mutations, …) Do GraphQL: Subscriptions / realtime Directives (@defer, @export, …) Próximos passos
  79. 79. GraphQL é o futuro?
  80. 80. Obrigado @brunolemos

×