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

GraphQL with JavaScript

GraphQL with JavaScript

My GraphQL presentation from JSTalks

Radoslav Stankov

November 15, 2015
Tweet

More Decks by Radoslav Stankov

Other Decks in Programming

Transcript

  1. Implementing
    GraphQL
    with

    JavaScript
    Radoslav Stankov 21/10/2015

    View full-size slide

  2. Radoslav Stankov
    @rstankov

    http://rstankov.com

    http://blog.rstankov.com

    http://github.com/rstankov

    View full-size slide

  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
    }

    View full-size slide

  4. GET /api/users/1
    {
    id: 1,
    name: 'User Name',
    handle: 'user_name',
    avatar_url: 'assets.producthunt.com/uuid'
    }

    View full-size slide

  5. Rest Client
    Rest Server

    View full-size slide

  6. Rest Client
    Rest Server
    /api/posts?date=2015-10-31

    View full-size slide

  7. Rest Client
    Rest Server
    /api/posts?date=2015-10-31
    /api/users/{x}
    (for X users)

    View full-size slide

  8. Rest Client
    Rest Server
    /api/posts?date=2015-10-31
    /api/users/{x}
    (for X users)

    View full-size slide

  9. …approach 2

    View full-size slide

  10. 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'
    }
    }

    View full-size slide

  11. 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'
    }]
    }

    View full-size slide

  12. 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',
    }]
    }

    View full-size slide

  13. …approach 3

    View full-size slide

  14. Rest Client
    Rest Server

    View full-size slide

  15. Rest Client
    Rest Server
    endpoint 1
    feature 1

    View full-size slide

  16. Rest Client
    Rest Server
    endpoint 1
    feature 1
    endpoint 2
    feature 2

    View full-size slide

  17. Rest Client
    Rest Server
    endpoint 1
    feature 1
    endpoint 2
    feature 2
    endpoint 3
    feature 3

    View full-size slide

  18. Rest Client
    Rest Server
    endpoint 1
    feature 1
    endpoint 2
    feature 2
    endpoint 3
    feature 3
    endpoint N
    feature N

    View full-size slide

  19. {
    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'
    }]
    }

    View full-size slide

  20. {
    id
    title
    tagline
    votes_count
    hunter {
    id
    avatar_url
    }
    makers {
    id
    avatar_url
    }
    }

    View full-size slide

  21. GET /graphql
    Request Body Response Body

    View full-size slide


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

    View full-size slide


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

    View full-size slide


  24. 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
    }
    ]
    }
    }
    }

    View full-size slide

  25. It’s that simple

    View full-size slide


  26. https://facebook.github.io/graphql


    View full-size slide

  27. 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.

    View full-size slide

  28. Architecture

    GraphQL Library

    (Per-Language)


    Type

    Definitions


    Application

    Code


    View full-size slide

  29. GraphQL
    • Single endpoint
    • Not just a library
    • Application-Layer Protocol
    • Server agnostic
    • Strongly-typed
    • Client-specified queries
    • Hierarchical

    View full-size slide

  30. Tries to solve
    • N+1 API queries
    • API response bloat
    • Documentation
    • Ad Hoc Endpoints
    • Structure issues

    View full-size slide

  31. 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);
    }
    },
    });

    View full-size slide

  32. 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);
    }
    },
    };
    }
    });

    View full-size slide

  33. 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]
    },
    }
    }
    });

    View full-size slide

  34. 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);
    }
    },
    };
    }
    });

    View full-size slide

  35. 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);
    }
    },
    };
    }
    });

    View full-size slide

  36. 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
    }
    ]
    }
    }
    }

    View full-size slide

  37. Mutation

    mutation {
    createUser(name: "Rado") {
    id
    }
    }
    {
    "data": {
    "createSpeaker": {
    "id": 2
    }
    }
    }

    View full-size slide

  38. 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);
    },
    },
    },
    });

    View full-size slide

  39. 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"
    }
    }
    }
    ]
    },

    View full-size slide

  40. {
    id
    hunter: {
    id
    name

    small_avatar_url: avatar_url(size: 100)

    big_avatar_url: avatar_url(size: 400)
    }
    }
    Cool tricks

    View full-size slide

  41. 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;
    }
    },
    };
    }
    });

    View full-size slide

  42. query withFragments {
    user(id: 4) {
    friends(first: 10) {
    ...friendFields
    }
    mutualFriends(first: 10) {
    ...friendFields
    }
    }
    }
    fragment friendFields on User {
    id
    name
    profilePic(size: 50)
    }
    Cool tricks

    View full-size slide


  43. https://facebook.github.io/react


    View full-size slide


  44. https://facebook.github.io/relay


    View full-size slide

  45. PostContainer = Relay.createContainer(Post, {
    fragments: {
    post: () => Relay.QL`
    fragment on Post {
    id
    title
    tagline
    votes_count
    }
    `,
    },
    });
    Relay

    View full-size slide

  46. Issues
    • New, just a draft specification
    • Mutations are weird
    • Best practices and solutions
    • Large datasets

    View full-size slide

  47. https://speakerdeck.com/rstankov/introduction-to-graphql

    View full-size slide

  48. https://github.com/rstankov/talks-code

    View full-size slide

  49. @rstankov
    Thanks :)

    View full-size slide