12/08/2018, 17:30

Xây dựng một simple GraphQL API Server với NodeJS và Express - Part 1

GraphQL là một ngôn ngữ truy vấn cho các API cung cấp dữ liệu khai báo đang khai thác. Nó cho phép các clients yêu cầu chính xác các dữ liệu mà mình cần từ một web server và không thêm gì nhiều hơn nữa. Được phát triển vào năm 2012 bởi Facebook, GraphQL API hiện đang được sử dụng in-house bởi ...

GraphQL là một ngôn ngữ truy vấn cho các API cung cấp dữ liệu khai báo đang khai thác. Nó cho phép các clients yêu cầu chính xác các dữ liệu mà mình cần từ một web server và không thêm gì nhiều hơn nữa. Được phát triển vào năm 2012 bởi Facebook, GraphQL API hiện đang được sử dụng in-house bởi Facebook và các công ty khác như Yelp, Shopify và Github. GraphQL spec được phát hành vào năm 2015 và hiện đã khả dụng ở nhiều môi trường và được sử dụng bởi các team thuộc mọi quy mô. GraphQL là mã nguồn mở và được duy trì bởi Facebook.

Trong khi các REST API thường gửi request tới nhiều endpoint, thì GraphQL API cho phép bạn chỉ gửi một request đến một endpoint để có được dữ liệu cần thiết cho ứng dụng của bạn. GraphQL rất phù hợp cho các kết nối mạng di động chậm bởi vì nó chỉ cần một round-trip đến server để lấy các dữ liệu cần thiết. Sử dụng GraphQL, các lập trình viên front-end có thể xây dựng một query dựa trên các fields mà họ cần từ endpoint chứ không phải là overfetching của REST API.

Version của API có thể là vấn đề đau đầu cho các nhóm phát triển nhưng với GraphQL bạn không phải lo lắng. GraphQL cho phép bạn thêm các fields và types mới (sẽ được thảo luận sau) vào GraphQL API của bạn mà không ảnh hưởng đến các query hiện có. Các fields cũ hơn và không sử dụng có thể gây xung đột và bị ẩn trong các API clients. Bằng cách sử dụng một version duy nhất, GraphQL API cho phép ứng dụng của bạn liên tục truy cập vào các API mới hơn, giúp cho code clean và dễ bảo trì hơn.

Prerequisite

Trước khi bắt đầu, hãy chắc chắn rằng bạn đã cài đặt Node v6 hoặc hơn. Mở command-line hoặc terminal của bạn và gõ lệnh dưới đây để kiểm tra phiên bản của Node:

node -v

Nếu bạn chưa cài đặt Node thì bạn có thể vào trang chủ của Node (https://nodejs.org/en/) để xem và cài đặt Node.

Setting up GraphQL and Express

Một cách đơn giản để tạo một server GraphQL API là sử dụng Express, một framework phổ biến cho Node.js. Để cài và chạy Express bạn sẽ cần phải cài đặt nó, bằng cách sử dụng npm:

//Tạo thêm 1 file package.json
npm init 
npm install express --save

Sau đó, cài đặt graphql và express-graphql dependencies như sau:

npm install graphql express-graphql --save 

Từ khóa mở rộng -save là để thêm nó như là một dependency trong ứng dụng của bạn, để bất cứ ai cài đặt ứng dụng của bạn thì cũng tự động cài đặt các dependency này khi chạy npm install. Cấu trúc ban đầu của thư mục sẽ giống như sau:

|---- node_modules  // Folder chứa các package đã cài đặt
|---- package.json  //Chứa thông tin về ứng dụng

Basic GraphQL API Implementation

Chúng ta sẽ sử dụng buildSchema object từ graphql để tạo một schema. Tạo một file example.js trong thư mục gốc và thêm đoạn code này:

// example.js
const express = require('express');
const { buildSchema } = require('graphql');
const graphqlHTTP = require('express-graphql');
let port = 3000;

/* Đây là ví dụ schema đã được khởi tạo */

let schema = buildSchema(`
  type Query {
    postTitle: String,
    blogTitle: String
  }
`);

// Root provides a resolver function for each API endpoint
let root = {
  postTitle: () => {
    return 'Build a Simple GraphQL Server With Express and NodeJS';
  },
  blogTitle: () => {
    return 'scotch.io';
  }
};

const app = express();
app.use('/', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true //Set to false if you don't want graphiql enabled
}));

app.listen(port);
console.log('GraphQL API server running at localhost:'+ port);

example.js chứa một cấu trúc cơ bản của graphql. API này được thực hiện bằng cách sử dụng GraphQL schema language. Express không cần thiết để thực thi tập tin này mà bạn chỉ cần chạy lệnh node example.js:

node example.js

Đây chỉ là ví dụ nhanh về một GraphQL API. Một tính năng chính khi sử dụng graphiql là nó cho phép bạn kiểm tra API của bạn trong trình duyệt, autocomplete và đưa ra các gợi ý cho bạn dựa trên các types và các fields có sẵn trong schema đã định nghĩa của bạn.

alt

Bây giờ chúng ta hãy truy vấn schema cho blogTitle:

alt

Vậy là chúng ta đã truy vấn được GrapQL API của bạn.

Introduction

Bây giờ bạn cần phải có hiểu biết về cách GraphQL hoạt động. Hãy bắt đầu với việc xây dựng một Express GraphQL server. Trong thư mục gốc tạo một thư mục src, bên trong thư mục src tạo ra một file và lưu với tên schema.js. Bây giờ mở file này và thêm đoạn code này:

const Authors = require('./data/authors'); // This is to make available authors.json file
const Posts = require('./data/posts'); // This is to make available post.json file

/* Here a simple schema is constructed without using the GraphQL query language. 
  e.g. using 'new GraphQLObjectType' to create an object type 
*/

let {
  // These are the basic GraphQL types need in this tutorial
  GraphQLString,
  GraphQLList,
  GraphQLObjectType,
  // This is used to create required fileds and arguments
  GraphQLNonNull,
  // This is the class we need to create the schema
  GraphQLSchema,
} = require('graphql');

Tạo thư mục data bên trong thư mục src và sao chép nội dung của các file authors.json và posts.json tại đây.

Types in GraphQL

GraphQL có một graphql/type module được sử dụng trong định nghĩa kiểu. Các type có thể được import từ module graphql/type hoặc từ module graphql gốc. Các type cơ bản bao gồm ID, String, Int, Float và Boolean. Chúng ta sẽ thêm Author type vào file schema.js:

const AuthorType = new GraphQLObjectType({
  name: "Author",
  description: "This represent an author",
  fields: () => ({
    id: {type: new GraphQLNonNull(GraphQLString)},
    name: {type: new GraphQLNonNull(GraphQLString)},
    twitterHandle: {type: GraphQLString}
  })
});

Điều này là để tạo ra một object của một GraphQLObjectType. Name và Description tự mô tả chính nó. Fields chứa các thuộc tính của Author Schema như id, name và twitterHandle của author, tất cả các kiểu đã được định nghĩa. Để được giải thích thêm về các types xem thêm tại graphql.org/graphql-js/type/

Tạo PostType:

const PostType = new GraphQLObjectType({
  name: "Post",
  description: "This represent a Post",
  fields: () => ({
    id: {type: new GraphQLNonNull(GraphQLString)},
    title: {type: new GraphQLNonNull(GraphQLString)},
    body: {type: GraphQLString},
    author: {
      type: AuthorType,
      resolve: function(post) {
        return _.find(Authors, a => a.id == post.author_id);
      }
    }
  })
});

Thêm nó vào schema.js, điều này sẽ tạo ra một đối tượng PostType được sử dụng trong Root Query.

Root Query

Root Query là một entry point đến server GraphQL API của bạn. Nó được sử dụng để expose các resources có sẵn cho clients của ứng dụng. Chúng ta sẽ tạo ra hai resources sẵn có là: các author và post.

Thêm đoạn code sau vào file schema.js:

// This is the Root Query
const BlogQueryRootType = new GraphQLObjectType({
  name: 'BlogAppSchema',
  description: "Blog Application Schema Query Root",
  fields: () => ({
    authors: {
      type: new GraphQLList(AuthorType),
      description: "List of all Authors",
      resolve: function() {
        return Authors
      }
    },
    posts: {
      type: new GraphQLList(PostType),
      description: "List of all Posts",
      resolve: function() {
        return Posts
      }
    }
  })
});

Root Query ở đây được định nghĩa là BlogQueryRootType. name và description là tự mô tả. Nếu bạn nhận thấy thì có một kiểu mới khai báo: new GraphQLList (). GraphQLList làm gì để tạo một wrapper kiểu xung quanh các loại khác đại diện cho một danh sách các loại đó. Root query ở đây được định nghĩa là BlogQueryRootType. tên và mô tả là tự mô tả. Nếu bạn nhận thấy, có một kiểu mới khai báo: new GraphQLList (). GraphQLList là để tạo một wrapper type xung quanh các type khác, đại diện cho một danh sách các type đó.

Defining a Schema

Schema xác định cách bạn muốn hình thành dữ liệu trong ứng dụng và cách bạn muốn dữ liệu liên quan với nhau. Defination Schema ảnh hưởng đến cách dữ liệu sẽ được lưu trữ trong (các) database của bạn. Trong định nghĩa Schema, bạn cũng sẽ xác định những query, mutations và subscriptions nào sẽ được cung cấp cho phía front-end.

Thêm file schema:

const BlogAppSchema = new GraphQLSchema({
  query: BlogQueryRootType
  // If you need to create or updata a datasource, 
  // you use mutations. Note:
  // mutations will not be explored in this post.
  // mutation: BlogMutationRootType 
});

Ở đây, query được assign bởi BlogQueryRootType object để sử dụng làm root query của API.

Vì bài viết hơi dài nên mình sẽ chia làm 2. Hẹn gặp lại các bạn trong part-2 (tháng sau nhé (yaoming)).

References

https://scotch.io/@codediger/build-a-simple-graphql-api-server-with-express-and-nodejs

0