iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 3
1

介紹

ApolloData Server 主要有三個任務
第一個是解析 Client payload map 打進來的資料,並且符合 Type Query 與 Type Mutation 的定義(即開放的 API )
第二個是 Resolver 解析 , Resolver 解析要符合定義的 Schema Type
第三個是 是驗證功能

當然支援 GraphQL Spec 的 Server 還有很多 但是可以透過下面官方提供的比較表可以看到 ApolloData 是非常用心

https://ithelp.ithome.com.tw/upload/images/20171209/20103438Ri0Ueyrb5u.png

ApolloData Server 的運作方式
https://www.apollographql.com/docs/graphql-tools/

ApolloData 把原生的撰寫 Schema 方式調整過了所以寫作起來就好像在寫NOSQL的定義檔,
typeDefs 就是定義 Type 而Type 中可以返回另外一個 Type 像關連般的樣子,
如下面的 Author 底下的 posts:[POST] 定義 posts 為 POST 的 Type 並且為陣列,另外 id:Int! 的驚嘆號就是表示必須,其他基本型態就有 Int ,String,Boolean,也可以像 POST 那樣自定義 Type

官方範例


const typeDefs = `
  type Author {
    id: Int!
    firstName: String
    lastName: String
    posts: [Post] # the list of Posts by this author
  }

  type Post {
    id: Int!
    title: String
    author: Author
    votes: Int
  }

  # the schema allows the following query:
  type Query {
    posts: [Post]
    author(id: Int!): Author
  }

  # this schema allows the following mutation:
  type Mutation {
    upvotePost (
      postId: Int!
    ): Post
  }
`;

接下來可以看到 type Query 與 type Mutation 這兩個都是開放 Client 端可以操作的 API 所以 Client 是不能直接操作 Schema 必須透過開放的 API , 符合之後才能到 Resolver ,而這邊的
posts:[Post] 左邊的就是開放的 API 介面右邊的就是 Resolver 要符合的形態

 type Query {
    posts: [Post]
    author(id: Int!): Author
  }

再來看一個 author(id:Int!):Author 左邊的多了一個小()裡面的意思就是 API 開放的參數要是id並且是數子, Resolver 回傳形態則為是 Author

接下來會看到 Mutation 相對於 Query 是查詢 Mutation 則包含新增刪除修改 只要有異動資料庫的都叫做 Mutation
其他都跟query一樣

 type Mutation {
    upvotePost (
      postId: Int!
    ): Post
  }

Resolver 的部分官方範例 用假資料 Mock 起來 ,符合回傳形態沒有連結資料庫,這樣比較好說明


import { find, filter } from 'lodash';

// example data
const authors = [
  { id: 1, firstName: 'Tom', lastName: 'Coleman' },
  { id: 2, firstName: 'Sashko', lastName: 'Stubailo' },
  { id: 3, firstName: 'Mikhail', lastName: 'Novikov' },
];
const posts = [
  { id: 1, authorId: 1, title: 'Introduction to GraphQL', votes: 2 },
  { id: 2, authorId: 2, title: 'Welcome to Meteor', votes: 3 },
  { id: 3, authorId: 2, title: 'Advanced GraphQL', votes: 1 },
  { id: 4, authorId: 3, title: 'Launchpad is Cool', votes: 7 },
];

const resolvers = {
  Query: {
    posts: () => posts,
    author: (_, { id }) => find(authors, { id: id }),
  },
  Mutation: {
    upvotePost: (_, { postId }) => {
      const post = find(posts, { id: postId });
      if (!post) {
        throw new Error(`Couldn't find post with id ${postId}`);
      }
      post.votes += 1;
      return post;
    },
  },
  Author: {
    posts: (author) => filter(posts, { authorId: author.id }),
  },
  Post: {
    author: (post) => find(authors, { id: post.authorId }),
  },
};

Resolver 的部分要上面程式碼開放的 API 介面相符合 type Query 與 type Mutaion
Resolver 的格式 也是分成 Query 與 Mutaion ,寫法都一樣基本上會有三個參數

第一個是 PARENT 通常會用"_", 第二個是傳入的參數第三個通常是用來驗證身份使用
如果沒有參數傳入就直接像上方的 posts這樣直接打回去 posts (這邊是上面定義好的陣列形態就是post)

const resolvers = {
  Query: {
    posts: () => posts,
    author: (_, { id }) => find(authors, { id: id }),
  },
  

有參數要查詢的話就會至少要兩個參數如下,如果有加上驗證資訊的話就會放在第三個

author: (_, { id }) => find(authors, { id: id }),

另外我們可以在 Client 端使用 Nest 巢狀查詢
例如

{
 Post{
  title,
   Author{
      name
   }
 }
}

例如上方的 payload query 那是因為 Resolver 這邊有做一個關聯查詢會把Post的post.authorId當下一個Author的Id查詢條件,這樣就串起來了

  Post: {
    author: (post) => find(authors, { id: post.authorId }),
  },

Schema 跟 Resolver 基本的設定就完成了

ApolloData Server貼心的把邏輯開發分開並且簡化,接下來把它還原成原生的CODE

import { makeExecutableSchema } from 'graphql-tools';

const jsSchema = makeExecutableSchema({
  typeDefs,
  resolvers,
});

總結
ApolloData Server 貼心的幫忙開發者省下許多重複的工作並且把邏輯變得更清楚,讓開發更順暢 ,輕鬆上路了
day4 再來說明 Server 驗證的部分

官方網站有介紹與範例
https://www.apollographql.com/Servers/


上一篇
GraphQL Server & ApolloData Server
下一篇
ApolloData Server & Auth
系列文
GraphQL + ApolloData 入門30

尚未有邦友留言

立即登入留言