GraphQL vs RESTMaximilianos GJ Panas
Software Engineer@AgileActors@mgjp_
Stelios CharmpalisSoftware Engineer@AgileActors
@SteliosHarb
AgileActors Blog
REpresentational State TransferHTTP verbs(GET, POST, PUT, DELETE)Resource Based URLs - Endpoints (/ᴀ各lms/24)
REST(ful) API
22. GET /characters/34 23. { 24. "id": 34, 25. "name": "Luke Skywalker", 26. "birthYear": "1", 27. "eyeColor": "blue", 28. "gender": "male", 29. "hairColor": "blond", 30. "height": 172, 31. "mass": 77, 32. "skinColor": "fair" 33. } 34. 35.
18. [ 19. "/characters/34", 20. "/characters/35" 21. ]
36. 37. 38. 39. 40.
Retrieves the info about the `characters` with ID `34`
It is a period of civil war....
GET /films/1
{ "id": 1, "title": "A New Hope", "episodeID": 4, "openingCrawl": "It is a period...", "poster": "http://...", "releaseDate": "2002‐05‐16", "created": "2014‐12‐20T10:57:57.886Z", "edited": "2014‐12‐20T20:18:48.516Z" }
PM (Project Manager)
Film Card using a RESTful API
A New HopeEpisode 4
It is a period of civil war....
Characters
{ "id": 1 "title": "A New Hope", ... }
# 4 different queries 1. GET /films/1 2. GET /films/1/characters 3. GET /character/34 4. GET /character/35
# 1 Request ‐ Add boolean query string GET /films/1?include_character_details=true
# 1 Request ‐ New custom endpoint GET /films_with_character_details/1
Film Card using a RESTful API
A New HopeEpisode 4
Luke Skywalker
C3PO
/* JSON Response */ { "id": 1, "title": "A New Hope", "episodeID": 4, "openingCrawl": "It is a period...", "poster": "http://...", "releaseDate": "2002‐05‐16", "created": "2014‐12‐20T10:57:57.886Z", "edited": "2014‐12‐20T20:18:48.516Z", "characters": [ { "id": 35, "name": "C‐3PO", "birthYear": "112BBY", "eyeColor": "yellow", "gender": "n/a", "hairColor": "n/a", "height": 167, "mass": 75, "skinColor": "gold", "avatar": "http://..." }, { ... }] }
/* JSON Response */ { "title": "A New Hope", "episodeID": 4, "openingCrawl": "It is a period...", "poster": "http://...", "characters": [ { "name": "C‐3PO", "avatar": "http://..." }, { ... }] }
SIMPLIFY JSON RESPONSE
/* GraphQL Request */ { title episodeID openingCrawl poster characters { name avatar } }
/* JSON Response */ { "title": "A New Hope", "episodeID": 4, "openingCrawl": "It is a period...", "poster": "http://...", "characters": [ { "name": "C‐3PO", "avatar": "http://..." }, { ... }] }
A GRAPHQL REQUEST
Eliminate Overfetching
Eliminate Underfetching
Be Declarative
Increase Product Developer Autonomy
Natively Support Versioning
CORE GOALS
HELLO WORLD
{ bestFilm { title } }
{ "bestFilm": { "title": "The Empire Strikes Back" } }
ARGUMENTS
{ film(id: 1) { title } }
{ "film": { "title": "A New Hope" } }
COMPLEX QUERIES
{ film(id: 1) { title poster { width height url } } }
{ "film": { "title": "A New Hope", "poster": { "width": 300, "height": 300, "url": "https://..." } } }
NODES WITHIN NODES
{ film(id: 1) { title poster(size: 1000) { width height url } } }
{ "film": { "title": "A New Hope", "poster": { "width": 1000, "height": 1000, "url": "https://..." } } }
ALIASES
{ film(id: 1) { title regularPic: poster(size: 500) { width height url } retinaPic: poster(size: 1000) { width height url } } }
{ "film": { "title": "A New Hope", "normalPic": { "width": 500, "height": 500, "url": "https://..." }, "retinaPic": { "width": 1000, "height": 1000, "url": "https://..." } } }
NESTED QUERIES
{ film(id: 1) { title characters { name films { title characters { name } } } } }
{ "film": { "title": "A New Hope", "characters": [{ "name": "Yoda" "films": [{ "title": "The Empire Strikes Back", "characters": [{ "name": "Luke Skywalker" }, { "name": "Han Solo" }] }, { "title": "Return of the Jedi", "characters": [{ "name": "C‐3PO" }, { ... }] }]
}, {
HOW GRAPHQLWORKS
User-Deᴀ各ned type system - "schema"
Data Universe is deᴀ各ned and connected on the server
Multiple Back-end services exposed through a singlecontrolled API
The client requests for exactly what it wants
TYPE SYSTEM (SCHEMA)
type Root { bestFilm: Film film(id: Int!): Film }
type Film { title: String poster(size: Int = 300): Picture characters: [Person] }
type Person { name: String films: [Film] }
type Picture { width: Int height: Int url: String }
GRAPHQL-JS
const Root = new GraphQLObjectType({ name: 'Root', description: 'The starting point of your GraphQL query', fields: () => ({ bestFilm: { type: Film, resolve: (root, args, context) => api.getTop('film') .then(id => api.getFilm(id)), }, film: { type: Film, args: { id: { type: new GraphQLNonNull(GraphQLInt) } }, resolve: (root, args, context) => api.getFilm(args.id), }, }), });
Demo with GraphiQL
GraphQL is not bound by any client frameworkWays of using it on the client
Relay (Speciᴀ各cally for React)Lokka (Simplest lib, can be used with anything)Others (Apollo, XHR, etc.)
Queries can easily be broken apart andmerged togetheragainDeclare exactly what your data requirements are on thecomponent layer
THE CLIENT STORY
GraphQL is a speciᴀ各cation of a communication protocol, not a storagesystem, not a library
GraphQL is not tied to a speciᴀ各c language or framework
GraphQL does not allow clients to arbitrarily query your database(s)
GraphQL does not require a speciᴀ各c backend storage system
Security: Authentication is handled the same way as in REST
POSSIBLE MISCONCEPTIONS
Handling Resource intensive Queries on the Backend- facebook/Dataloader
Handling errors in resolvers- khadira/graphql-errors
Granular Control on querying- @defer, @async, @stream
Live Queries- Subscriptions
PRACTICAL PROBLEMS
GraphQL IntroductionGraphQLLearn GraphQLZero to GraphQL in 30 Minutes – Steven LuscherFrom REST to GraphQLValidation and User Errors in GraphQL Mutations
Presentation built with Spectacle
USEFUL LINKS
THANK YOU!Any questions?
Top Related