Hướng dẫn cho người mới bắt đầu về GraphQL

Một trong những thuật ngữ được thảo luận phổ biến nhất hiện nay là API. Rất nhiều người không biết chính xác API là gì. Về cơ bản, API là viết tắt của Application Programming Interface. Như tên đã nói, nó là một giao diện mà mọi người - nhà phát triển, người dùng, người tiêu dùng - có thể tương tác với dữ liệu.

Bạn có thể coi API như một người pha chế. Bạn yêu cầu người pha chế đồ uống và họ đưa cho bạn thứ bạn muốn. Đơn giản. Vậy tại sao đó là một vấn đề?

Kể từ khi bắt đầu có web hiện đại, việc xây dựng các API đã không còn khó như người ta vẫn tưởng. Nhưng việc học và hiểu các API là như vậy. Các nhà phát triển tạo thành phần lớn những người sẽ sử dụng API của bạn để xây dựng thứ gì đó hoặc chỉ sử dụng dữ liệu. Vì vậy, API của bạn phải sạch sẽ và trực quan nhất có thể. Một API được thiết kế tốt rất dễ sử dụng và học hỏi. Nó cũng trực quan, một điểm tốt cần ghi nhớ khi bạn bắt đầu thiết kế API của mình.

Chúng tôi đã sử dụng REST để xây dựng các API trong một thời gian dài. Cùng với đó là một số vấn đề. Khi xây dựng một API bằng thiết kế REST, bạn sẽ gặp phải một số vấn đề như:

1) bạn sẽ có rất nhiều điểm cuối

2) các nhà phát triển sẽ khó học và hiểu API của bạn hơn nhiều

3) có thông tin tìm nạp quá mức và thiếu

Để giải quyết những vấn đề này, Facebook đã tạo ra GraphQL. Ngày nay, tôi nghĩ GraphQL là cách tốt nhất để xây dựng các API. Bài viết này sẽ cho bạn biết lý do tại sao bạn nên bắt đầu tìm hiểu nó ngay hôm nay.

Trong bài viết này, bạn sẽ tìm hiểu cách hoạt động của GraphQL. Tôi sẽ chỉ cho bạn cách tạo một API được thiết kế rất tốt, hiệu quả, mạnh mẽ bằng GraphQL.

Bạn có thể đã nghe nói về GraphQL, vì rất nhiều người và công ty đang sử dụng nó. Vì GraphQL là mã nguồn mở, cộng đồng của nó đã phát triển rất lớn.

Bây giờ, đã đến lúc bạn bắt đầu tìm hiểu thực tế về cách hoạt động của GraphQL và tất cả những điều kỳ diệu của nó.

GraphQL là gì?

GraphQL là một ngôn ngữ truy vấn mã nguồn mở được phát triển bởi Facebook. Nó cung cấp cho chúng tôi một cách hiệu quả hơn để thiết kế, tạo và sử dụng các API của chúng tôi. Về cơ bản, nó là sự thay thế cho REST.

GraphQL có rất nhiều tính năng, như:

  1. Bạn ghi dữ liệu bạn muốn và bạn nhận được chính xác dữ liệu bạn muốn. Không còn tìm nạp quá nhiều thông tin như chúng ta đã quen với REST.
  2. Nó cung cấp cho chúng tôi một điểm cuối duy nhất , không còn phiên bản 2 hoặc phiên bản 3 cho cùng một API.
  3. GraphQL được gõ mạnh và bạn có thể xác thực một truy vấn trong hệ thống kiểu GraphQL trước khi thực thi. Nó giúp chúng tôi xây dựng các API mạnh mẽ hơn.

Đây là phần giới thiệu cơ bản về GraphQL - tại sao nó lại mạnh mẽ như vậy và tại sao nó ngày càng trở nên phổ biến. Nếu bạn muốn tìm hiểu thêm về nó, tôi khuyên bạn nên truy cập trang web GraphQL và xem thử.

Bắt đầu

Mục tiêu chính trong bài viết này không phải là tìm hiểu cách thiết lập máy chủ GraphQL, vì vậy hiện tại chúng tôi chưa đi sâu vào vấn đề đó. Mục tiêu là tìm hiểu cách hoạt động của GraphQL trong thực tế, vì vậy chúng tôi sẽ sử dụng một máy chủ GraphQL không cấu hình có tên là ☄️ Graphpack.

Để bắt đầu dự án của mình, chúng ta sẽ tạo một thư mục mới và bạn có thể đặt tên cho nó bất cứ thứ gì bạn muốn. Tôi sẽ đặt tên cho nó graphql-server:

Mở thiết bị đầu cuối của bạn và nhập:

mkdir graphql-server

Bây giờ, bạn nên cài đặt npm hoặc sợi trong máy của mình. Nếu bạn không biết những gì đang có, NPMsợi là các nhà quản lý trọn gói cho các ngôn ngữ lập trình JavaScript. Đối với Node.js, trình quản lý gói mặc định là npm .

Bên trong thư mục đã tạo của bạn, gõ lệnh sau:

npm init -y

Hoặc nếu bạn sử dụng sợi:

yarn init 

npm sẽ tạo một package.jsontệp cho bạn và tất cả các phần phụ thuộc mà bạn đã cài đặt và các lệnh của bạn sẽ ở đó.

Vì vậy, bây giờ, chúng tôi sẽ cài đặt phụ thuộc duy nhất mà chúng tôi sẽ sử dụng.

☄️Graphpack cho phép bạn tạo một máy chủ GraphQL với cấu hình bằng không . Vì chúng tôi chỉ mới bắt đầu với GraphQL, điều này sẽ giúp chúng tôi rất nhiều để tiếp tục và tìm hiểu thêm mà không phải lo lắng về cấu hình máy chủ.

Trong thiết bị đầu cuối, bên trong thư mục gốc, hãy cài đặt nó như sau:

npm install --save-dev graphpack

Hoặc, nếu bạn sử dụng sợi, bạn nên đi như sau:

yarn add --dev graphpack

Sau khi Graphpack được cài đặt, hãy chuyển đến tập lệnh của chúng tôi trong package.jsontệp và đặt mã sau vào đó:

"scripts": { "dev": "graphpack", "build": "graphpack build" }

Chúng ta sẽ tạo một thư mục có tên src, và nó sẽ là thư mục duy nhất trong toàn bộ máy chủ của chúng ta.

Tạo một thư mục có tên src, sau đó, bên trong thư mục của chúng ta, chúng ta sẽ chỉ tạo ba tệp.

Bên trong srcthư mục của chúng tôi, tạo một tệp có tên schema.graphql. Bên trong tệp đầu tiên này, hãy đặt mã sau:

type Query { hello: String }

Trong schema.graphqltệp này sẽ là toàn bộ lược đồ GraphQL của chúng ta. Nếu bạn không biết nó là gì, tôi sẽ giải thích sau - đừng lo lắng.

Bây giờ, bên trong srcthư mục của chúng ta , hãy tạo một tệp thứ hai. Gọi nó resolvers.jsvà bên trong tệp thứ hai này, hãy đặt mã sau:

import { users } from "./db"; const resolvers = { Query: { hello: () => "Hello World!" } }; export default resolvers;

Đây resolvers.jstập tin sẽ là cách chúng tôi cung cấp các hướng dẫn để biến một hoạt động GraphQL vào dữ liệu.

Và cuối cùng, bên trong srcthư mục của bạn , hãy tạo một tệp thứ ba. Gọi cái này db.jsvà bên trong tệp thứ ba này, hãy đặt mã sau:

export let users = [ { id: 1, name: "John Doe", email: "[email protected]", age: 22 }, { id: 2, name: "Jane Doe", email: "[email protected]", age: 23 } ];

In this tutorial we’re not using a real-world database. So this db.js file is going to simulate a database, just for learning purposes.

Now our src folder should look like this:

src |--db.js |--resolvers.js |--schema.graphql

Now, if you run the command npm run dev or, if you’re using yarn, yarn dev, you should see this output in your terminal:

You can now go to localhost:4000 . This means that we’re ready to go and start writing our first queries, mutations, and subscriptions in GraphQL.

You see the GraphQL Playground, a powerful GraphQL IDE for better development workflows. If you want to learn more about GraphQL Playground, click here.

Schema

GraphQL has its own type of language that’s used to write schemas. This is a human-readable schema syntax called Schema Definition Language (SDL). The SDL will be the same, no matter what technology you’re using — you can use this with any language or framework that you want.

This schema language its very helpful because it’s simple to understand what types your API is going to have. You can understand it just by looking right it.

Types

Types are one of the most important features of GraphQL. Types are custom objects that represent how your API is going to look. For example, if you’re building a social media application, your API should have types such as Posts, Users, Likes, Groups.

Types have fields, and these fields return a specific type of data. For example, we’re going to create a User type, we should have some name, email, and age fields. Type fields can be anything, and always return a type of data as Int, Float, String, Boolean, ID, a List of Object Types, or Custom Objects Types.

So now to write our first Type, go to your schema.graphql file and replace the type Query that is already there with the following:

type User { id: ID! name: String! email: String! age: Int }

Each User is going to have an ID, so we gave it an ID type. User is also going to have a name and email, so we gave it a String type, and an age, which we gave an Int type. Pretty simple, right?

But, what about those ! at the end of every line? The exclamation point means that the fields are non-nullable, which means that every field must return some data in each query. The only nullable field that we’re going to have in our User type will be age.

In GraphQL, you will deal with three main concepts:

  1. queries — the way you’re going to get data from the server.
  2. mutations — the way you’re going to modify data on the server and get updated data back (create, update, delete).
  3. subscriptions — the way you’re going to maintain a real-time connection with the server.

I’m going to explain all of them to you. Let’s start with Queries.

Queries

To explain this in a simple way, queries in GraphQL are how you’re going to get data. One of the most beautiful things about queries in GraphQL is that you are just going to get the exact data that you want. No more, no less. This has a huge positive impact in our API — no more over-fetching or under-fetching information as we had with REST APIs.

We’re going to create our first type Query in GraphQL. All our queries will end up inside this type. So to start, we’ll go to our schema.graphql and write a new type called Query:

type Query { users: [User!]! }

It’s very simple: the usersquery will return to us an array of one or more Users. It will not return null, because we put in the ! , which means it’s a non-nullable query. It should always return something.

But we could also return a specific user. For that we’re going to create a new query called user. Inside our Query type, put the following code:

user(id: ID!): User! 

Now our Query type should look like this:

type Query { users: [User!]! user(id: ID!): User! }

As you see, with queries in GraphQL we can also pass arguments. In this case, to query for a specific user, we’re going to pass its ID.

But, you may be wondering: how does GraphQL know where get the data? That’s why we should have a resolvers.js file. That file tells GraphQL how and where it's going to fetch the data.

First, go to our resolvers.js file and import the db.js that we just created a few moments ago. Your resolvers.js file should look like this:

import { users } from "./db"; const resolvers = { Query: { hello: () => "Hello World!" } }; export default resolvers;

Now, we’re going to create our first Query. Go to your resolvers.js file and replace the hello function. Now your Query type should look like this:

import { users } from "./db"; const resolvers = { Query: { user: (parent, { id }, context, info) => { return users.find(user => user.id === id); }, users: (parent, args, context, info) => { return users; } } }; export default resolvers;

Now, to explain how is it going to work:

Each query resolver has four arguments. In the user function, we’re going to pass id as an argument, and then return the specific user that matches the passed id. Pretty simple.

In the users function, we’re just going to return the users array that already exists. It’ll always return to us all of our users.

Now, we’re going to test if our queries are working fine. Go to localhost:4000 and put in the following code:

query { users { id name email age } }

It should return to you all of our users.

Or, if you want to return a specific user:

query { user(id: 1) { id name email age } }

Now, we’re going to start learning about mutations, one of the most important features in GraphQL.

Mutations

In GraphQL, mutations are the way you’re going to modify data on the server and get updated data back. You can think like the CUD (Create, Update, Delete) of REST.

We’re going to create our first type mutation in GraphQL, and all our mutations will end up inside this type. So, to start, go to our schema.graphql and write a new type called mutation:

type Mutation { createUser(id: ID!, name: String!, email: String!, age: Int): User! updateUser(id: ID!, name: String, email: String, age: Int): User! deleteUser(id: ID!): User! }

As you can see, we’re going to have three mutations:

createUser: we should pass an ID, name, email, and age. It should return a new user to us.

updateUser: we should pass an ID, and a new name, email, or age. It should return a new user to us.

deleteUser: we should pass an ID. It should return a new user to us.

Now, go to our resolvers.js file and below the Query object, create a new mutation object like this:

Mutation: { createUser: (parent, { id, name, email, age }, context, info) => { const newUser = { id, name, email, age }; users.push(newUser); return newUser; }, updateUser: (parent, { id, name, email, age }, context, info) => { let newUser = users.find(user => user.id === id); newUser.name = name; newUser.email = email; newUser.age = age; return newUser; }, deleteUser: (parent, { id }, context, info) => { const userIndex = users.findIndex(user => user.id === id); if (userIndex === -1) throw new Error("User not found."); const deletedUsers = users.splice(userIndex, 1); return deletedUsers[0]; } }

Now, our resolvers.js file should look like this:

import { users } from "./db"; const resolvers = { Query: { user: (parent, { id }, context, info) => { return users.find(user => user.id === id); }, users: (parent, args, context, info) => { return users; } }, Mutation: { createUser: (parent, { id, name, email, age }, context, info) => { const newUser = { id, name, email, age }; users.push(newUser); return newUser; }, updateUser: (parent, { id, name, email, age }, context, info) => { let newUser = users.find(user => user.id === id); newUser.name = name; newUser.email = email; newUser.age = age; return newUser; }, deleteUser: (parent, { id }, context, info) => { const userIndex = users.findIndex(user => user.id === id); if (userIndex === -1) throw new Error("User not found."); const deletedUsers = users.splice(userIndex, 1); return deletedUsers[0]; } } }; export default resolvers;

Now, we’re going to test if our mutations are working fine. Go to localhost:4000 and put in the following code:

mutation { createUser(id: 3, name: "Robert", email: "[email protected]", age: 21) { id name email age } }

It should return a new user to you. If you want to try making new mutations, I recommend you to try for yourself! Try to delete this same user that you created to see if it’s working fine.

Finally, we’re going to start learning about subscriptions, and why they are so powerful.

Subscriptions

As I said before, subscriptions are the way you’re going to maintain a real-time connection with a server. That means that whenever an event occurs in the server and whenever that event is called, the server will send the corresponding data to the client.

By working with subscriptions, you can keep your app updated to the latest changes between different users.

A basic subscription is like this:

subscription { users { id name email age } }

You will say it’s very similar to a query, and yes it is. But it works differently.

When something is updated in the server, the server will run the GraphQL query specified in the subscription, and send a newly updated result to the client.

We’re not going to work with subscriptions in this specific article, but if you want to read more about them click here.

Conclusion

Như bạn đã thấy, GraphQL là một công nghệ mới thực sự mạnh mẽ. Nó cung cấp cho chúng tôi sức mạnh thực sự để xây dựng các API tốt hơn và được thiết kế tốt. Đó là lý do tại sao tôi khuyên bạn nên bắt đầu tìm hiểu nó ngay bây giờ. Đối với tôi, nó cuối cùng sẽ thay thế REST.

Cảm ơn vì đã đọc bài viết.

Theo dõi tôi trên Twitter!

Theo dõi tôi trên GitHub!

Tôi đang tìm kiếm một cơ hội từ xa, vì vậy nếu có bất kỳ điều gì tôi muốn nghe về nó, vui lòng liên hệ với tôi tại Twitter của tôi !