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

GraphQL with JavaScript

GraphQL with JavaScript

My GraphQL presentation from JSTalks

Avatar for Radoslav Stankov

Radoslav Stankov

November 15, 2015
Tweet

More Decks by Radoslav Stankov

Other Decks in Programming

Transcript

  1. GET /api/posts?date=2015-10-31 { id: 1, title: "Post title", tagline: "Post

    headline", votes_count: 1, comments_count: 1, url: '/category/slug', thumbnail_url: 'assets.producthunt.com/uuid', hunter_id: 1 }
  2. GET /api/users/1 { id: 1, name: 'User Name', handle: 'user_name',

    avatar_url: 'assets.producthunt.com/uuid' }
  3. GET /api/posts?date=2015-10-31 { id: 1, title: "Post title", tagline: "Post

    headline", votes_count: 1, comments_count: 1, url: '/category/slug', thumbnail_url: 'assets.producthunt.com/uuid', hunter: { id: 1, name: 'User Name', handle: 'user_name', avatar_url: 'assets.producthunt.com/uuid' } }
  4. GET /api/posts?date=2015-10-31 { id: 1, title: "Post title", tagline: "Post

    headline", votes_count: 1, comments_count: 1, url: '/category/slug', thumbnail_url: 'assets.producthunt.com/uuid', hunter: { id: 1, name: 'User Name', handle: 'user_name', avatar_url: 'assets.producthunt.com/uuid' }, makers: [{ id: 2, name: 'Second User', handle: 'second_user', avatar_url: 'assets.producthunt.com/uuid' }] }
  5. GET /api/posts?date=2015-10-31 { id: 1, title: "Post title", tagline: "Post

    headline", votes_count: 1, comments_count: 1, url: '/category/slug', thumbnail_url: 'assets.producthunt.com/uuid', hunter: { id: 1, name: 'User Name', handle: 'user_name', avatar_url: 'assets.producthunt.com/uuid' }, makers: [{ id: 2, name: 'Second User', handle: 'second_user', avatar_url: 'assets.producthunt.com/uuid' }], platform: [{ name: 'iPhone', }, { name: 'Mac', }, { name: 'Web', }] }
  6. Rest Client Rest Server endpoint 1 feature 1 endpoint 2

    feature 2 endpoint 3 feature 3 endpoint N feature N
  7. { id: 1, title: "Post title", tagline: "Post headline", votes_count:

    1, hunter: { id: 1, avatar_url: 'assets.producthunt.com/uuid' }, makers: [{ id: 2, avatar_url: 'assets.producthunt.com/uuid' }] }
  8. 
 query { post(id: 1){ id title tagline votes_count hunter

    { id avatar_url } makers { id avatar_url } } } GET /graphql Request Body Response Body
  9. 
 query { post(id: 1){ id title tagline votes_count hunter

    { id avatar_url } makers { id avatar_url } } } GET /graphql Request Body Response Body
  10. 
 query { post(id: 1){ id title tagline votes_count hunter

    { id avatar_url } makers { id avatar_url } } } GET /graphql Request Body Response Body { "data": { "post": { "id": 1, "title": "title", "tagline": "tagline", "votes_count": 0, "hunter": { "id": 1, "avatar_url": "assets.producthu }, "makers": [ { "id": 1, "avatar_url": "assets.product } ] } } }
  11. GraphQL is a query language created by Facebook in 2012

    which provides a common interface between the client and the server for data fetching and manipulations. The client asks for various data from the GraphQL server via queries.
  12. GraphQL • Single endpoint • Not just a library •

    Application-Layer Protocol • Server agnostic • Strongly-typed • Client-specified queries • Hierarchical
  13. Tries to solve • N+1 API queries • API response

    bloat • Documentation • Ad Hoc Endpoints • Structure issues
  14. Code var RootQueryType = new GraphQLObjectType({ name: 'RootQueryType', fields: {

    post: { type: PostType, description: 'Find post by id', args: { id: { description: 'Post id' type: new GraphQLNonNull(GraphQLInt) } }, resolve: function(_, params) { return data.posts.find(params.id); } }, });
  15. Code var PostType = new GraphQLObjectType({ name: 'Post', fields: function()

    { return { id: { type: GraphQLInt, }, title: { type: GraphQLString, }, user: { type: UserType, description: "Creator of the post", resolve: function(post) { return data.users.find(post.user_id); } }, }; } });
  16. Code var [TYPE] = new GraphQLObjectType({ name: [NAME],
 description: [DESCRIPTION],

    fields: function() { return { [FIELD_NAME]: { description: [DESCRIPTION], deprecation: [DEPRECATION MARKER], type: [TYPE],
 args: [LIST OF FIELD ARGUMENT],
 resolve: [FUNCTION] }, } } });
  17. Code var PostType = new GraphQLObjectType({ name: 'Post', fields: function()

    { return { id: { type: GraphQLInt,
 resolve: function(post) { return post.id; } }, user: { type: UserType, resolve: function(post) { return data.users.find(post.user_id); } }, }; } });
  18. Code var PostType = new GraphQLObjectType({ name: 'Post', fields: function()

    { return { id: { type: GraphQLInt }, user: { type: UserType, resolve: function(post) { return data.users.find(post.user_id); } }, }; } });
  19. Query 
 query { post(id: 1){ id title tagline votes_count

    hunter { id avatar_url } makers { id avatar_url } } } { "data": { "post": { "id": 1, "title": "title", "tagline": "tagline", "votes_count": 0, "hunter": { "id": 1, "avatar_url": "assets.producthun }, "makers": [ { "id": 1, "avatar_url": "assets.producth } ] } } }
  20. Mutation 
 mutation { createUser(name: "Rado") { id } }

    { "data": { "createSpeaker": { "id": 2 } } }
  21. Code var RootMutationType = new GraphQLObjectType({ name: 'RootMutationType', fields: {

    createPost: { type: PostType, args: { title: { type: new GraphQLNonNull(GraphQLString) }, tagline: { type: new GraphQLNonNull(GraphQLString) }, user_id: { type: new GraphQLNonNull(GraphQLInt) }, }, resolve: function(_, params) { if (!data.users.find(params.user_id)) { throw "Invalid user id - " + params.user_id; } return data.posts.create(params); }, }, }, });
  22. Documentation 
 query { __schema { types { name fields

    { name type { name kind ofType { name kind } } } } } } { "data": { "__schema": { "types": [ { "name": "Query", "fields": [ { "name": "user", "type": { "name": "Non-Null", "kind": "NON_NULL", "ofType": { "name": "User", "kind": "OBJECT" } } }, { "name": "post", "type": { "name": "Non-Null", "kind": "NON_NULL", "ofType": { "name": "Post", "kind": "OBJECT" } } } ] },
  23. Code var UserType = new GraphQLObjectType({ name: 'User', fields: function()

    { return { // ... some field definitions ... picture: { type: GraphQLString, args: { size: { type: GraphQLInt }, }, resolve: function(user, params) { var size = params.size || 400; return 'file.example.com/' + user.picture_uuid + "?size=" + size; } }, }; } });
  24. query withFragments { user(id: 4) { friends(first: 10) { ...friendFields

    } mutualFriends(first: 10) { ...friendFields } } } fragment friendFields on User { id name profilePic(size: 50) } Cool tricks
  25. PostContainer = Relay.createContainer(Post, { fragments: { post: () => Relay.QL`

    fragment on Post { id title tagline votes_count } `, }, }); Relay
  26. Issues • New, just a draft specification • Mutations are

    weird • Best practices and solutions • Large datasets