GraphQL Server 微實作

什麼是 GraphQL?

A query language for APIs

GraphQL

SQL

{

    user(id: 1) {

        name

        birthday

}

SELECT name, birthday FROM users

WHERE id = 1;

A Query Language

For APIs

Client

Server

Relational Database

SQL

(API)

GraphQL

GraphQL

1.  One URL

2. Post Method

Restful API

1.  Multiple URLs

2. Get, Post, Patch, Put, Delete, ...

Rest

https://www.howtographql.com/basics/1-graphql-is-the-better-rest/

GraphQL

https://www.howtographql.com/basics/1-graphql-is-the-better-rest/

更少 requests,更多抓資料的彈性

用 apollo-server

實作

需要做什麼?

import { ApolloServer } from 'apollo-server';

const typeDefs = ...;

const resolvers = ...;

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

server.listen({ port: 3000 });

server.js

定義 objects、寫 resolvers、架 server

type User {
  name: String!
  age: Int
}

type Article {

  authors: [User]
  title: String
  content: String
}

定義 Objects

Int
Float
String
Boolean
ID

(Default) Scalar Types

Object Types

Array

Non-Null

GraphQL Schema

    type User {

        id: ID

        name: String

    }

    type Query {

        me: User!

    }

~ Get

~ Post, Put, Patch, Delete

{

    query: Query

    mutation: Mutation

    subscription: Subscription

}

程式碼

import { gql, ApolloServer } from 'apollo-server';

const typeDefs = gql`

  type User {
    id: ID
    name: String
  }

  type Query {
    me: User
  }
`;

const server = new ApolloServer({
  typeDefs,
});

server.listen({ port: 3000 });

Schema Definition Language (SDL)

import { gql, ApolloServer } from 'apollo-server';

const typeDefs = gql`

  type User {
    id: ID
    name: String
  }

  type Query {
    me: User
  }
`;

const resolvers = {
  User: {
    id: () => '1',
    name: () => '名字',
  },
  Query: {
    me: () => ({}),
  },
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

server.listen({ port: 3000 });

query {

        me {

                id

                name

        }

}

{

    "data": {

        "me": {

             "id": 1,

             "name": "名字"

         }

    }

}

import { gql, ApolloServer } from 'apollo-server';

const typeDefs = gql`

  type User {
    id: ID
    name: String
  }

  type Query {
    me: User
  }
`;

const resolvers = {
  User: {},
  Query: {
    me: () => ({
      id: '1',
      name: '名字',
    }),
  },
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

server.listen({ port: 3000 });

query {

        me {

                id

                name

        }

}

{

    "data": {

        "me": {

             "id": 1,

             "name": "名字"

         }

    }

}

query {

        me {

               id

               name

        }

}

 

( 1 ) user = meResolver()

( 2 ) id = idResolver ? idResolver() : user.id

( 2 ) name = nameResolver ? nameResolver() : user.name

1.  會幫你設 default resolver

2. default resolver 看得到上一層 resolver 返回的 Object

有點像這樣:

Resolver 接受的參數

function resolver(parent, args, context, info) {

    ...

}

parent: 上一層 resolver 返回的 object

args: 這個 field 本身接受的參數

context: 通常包含這個 HTTP request 的一些訊息例如 header 的內容

info: 包含整個 schema、這次 graphql 查詢的全部內容、現在在哪個位置

https://www.prisma.io/blog/graphql-server-basics-the-schema-ac5e2950214e/

都在 parent 處理?


function User(options) {
  this.id = options.id;
  this.name = options.name;
}

User.prototype.getRecommendedProducts = function ...

const typeDefs = gql`

  type Product {
    id: ID
    name: String
  }

  type User {
    id: ID
    name: String
    recomendedProducts: [Product]
  }

  type Query {
    me: User
  }
`;

const resolvers = {
  User: {
    recommendedProducts: user => user.getRecommendedProducts(),
  },
  Query: {
    me: () => {
      const user = ...

      return user;
    },
  },
};

惰性求值

// Not lazy
var value = 1 + 1  // immediately evaluates to 2

// Lazy
var lazyValue = () => 1 + 1  // Evaluates to 2 when lazyValue is *invoked*

default resolver 像:


const resolver = (parent, args, context, info) => {
  if ( typeof parent.field === 'function') {
      return parent.field(args, context, info);
  }

  return parent.field;
}

function User(options) {
  this.id = options.id;
  this.name = options.name;
}

User.prototype.recommendedProducts = function ...

const typeDefs = gql`

  type Product {
    id: ID
    name: String
  }

  type User {
    id: ID
    name: String
    recomendedProducts: [Product]
  }

  type Query {
    me: User
  }
`;

const resolvers = {
  User: {},
  Query: {
    me: () => {
      const user = ...

      return user;
    },
  },
};

Circular References

type User {

        id: ID

        name: String

        friends: [User]

        books: [Book]

}

type Book {

        id: ID

        title: String

        authors: [User]

}

query {

    me {

        friends {

            friends {

                books {

                    authors {

                        friends {

                            id

                            name

                        }

                     }

                 }

             }

         }

    }

}

type User {

        id: ID

        name: String

        friends: [User]

        books: [Book]

}

type Book {

        id: ID

        title: String

        authors: [User]

}

Thanks

GraphQL Server 微實作

By luyunghsien

GraphQL Server 微實作

  • 573