สร้าง GraphQL API ด้วยโหนด
เผยแพร่แล้ว: 2022-12-20GraphQL เป็นคำศัพท์ใหม่ในการพัฒนา API ในขณะที่ RESTful API ยังคงเป็นวิธีที่ได้รับความนิยมสูงสุดในการเปิดเผยข้อมูลจากแอปพลิเคชัน แต่ก็มีข้อจำกัดมากมายที่ GraphQL มุ่งแก้ไข
GraphQL เป็นภาษาคิวรีที่สร้างโดย Facebook ซึ่งเปลี่ยนเป็นโครงการโอเพ่นซอร์สในปี 2558 มีไวยากรณ์ที่ใช้งานง่ายและยืดหยุ่นสำหรับการอธิบายและเข้าถึงข้อมูลใน API
คู่มือนี้จะสำรวจวิธีสร้างโปรเจ็กต์ GraphQL Node.js เราจะใช้ GraphQL เพื่อสร้างแอปพลิเคชัน Todo ในเฟรมเวิร์กเว็บ Express.js สำหรับ Node
GraphQL คืออะไร?
จากเอกสารอย่างเป็นทางการ: “GraphQL เป็นภาษาคิวรีสำหรับ API และรันไทม์สำหรับตอบสนองการสืบค้นเหล่านั้นด้วยข้อมูลที่มีอยู่ของคุณ GraphQL ให้คำอธิบายที่สมบูรณ์และเข้าใจได้ของข้อมูลใน API ของคุณ ช่วยให้ลูกค้าสามารถขอสิ่งที่ต้องการได้อย่างแท้จริงและไม่มีอะไรมากไปกว่านั้น ทำให้การพัฒนา API ง่ายขึ้นเมื่อเวลาผ่านไป และเปิดใช้งานเครื่องมือสำหรับนักพัฒนาที่ทรงพลัง”
GraphQL เป็นรันไทม์ฝั่งเซิร์ฟเวอร์สำหรับการดำเนินการค้นหาโดยใช้ระบบประเภทที่คุณกำหนดไว้สำหรับข้อมูลของคุณ นอกจากนี้ GraphQL ไม่ได้เชื่อมโยงกับฐานข้อมูลหรือเครื่องมือจัดเก็บข้อมูลใด ๆ แต่ได้รับการสนับสนุนโดยโค้ดและที่เก็บข้อมูลที่มีอยู่ของคุณแทน คุณสามารถรับการเปรียบเทียบโดยละเอียดของเทคโนโลยีเหล่านี้ได้จากคู่มือ GraphQL เทียบกับ RESTful API
หากต้องการสร้างบริการ GraphQL ให้เริ่มต้นด้วยการกำหนดประเภทสคีมาและสร้างฟิลด์โดยใช้ประเภทเหล่านั้น ถัดไป คุณจัดเตรียมตัวแก้ไขฟังก์ชันที่จะดำเนินการในแต่ละฟิลด์และพิมพ์เมื่อใดก็ตามที่ฝั่งไคลเอ็นต์ร้องขอข้อมูล
คำศัพท์ GraphQL
ระบบประเภท GraphQL ใช้เพื่ออธิบายว่าข้อมูลใดสามารถสอบถามและข้อมูลใดที่คุณสามารถจัดการได้ เป็นแกนหลักของ GraphQL มาหารือเกี่ยวกับวิธีต่างๆ ที่เราสามารถอธิบายและจัดการข้อมูลใน GraphQ
ประเภท
ประเภทออบเจกต์ GraphQL เป็นโมเดลข้อมูลที่มีฟิลด์ที่มีการพิมพ์สูง ควรมีการแมปแบบ 1 ต่อ 1 ระหว่างโมเดลและประเภท GraphQL ของคุณ ด้านล่างนี้เป็นตัวอย่างของประเภท GraphQL:
type User { id: ID! # The "!" means required firstname: String lastname: String email: String username: String todos: [Todo] # Todo is another GraphQL type }
แบบสอบถาม
GraphQL Query กำหนดการสืบค้นทั้งหมดที่ไคลเอนต์สามารถเรียกใช้บน GraphQL API คุณควรกำหนด RootQuery ที่จะมีข้อความค้นหาที่มีอยู่ทั้งหมดตามแบบแผน
ด้านล่างเรากำหนดและแมปการสืบค้นกับ RESTful API ที่สอดคล้องกัน:
type RootQuery { user(id: ID): User # Corresponds to GET /api/users/:id users: [User] # Corresponds to GET /api/users todo(id: ID!): Todo # Corresponds to GET /api/todos/:id todos: [Todo] # Corresponds to GET /api/todos }
การกลายพันธุ์
หาก GraphQL Query เป็นคำขอ GET การกลายพันธุ์จะเป็น คำขอ POST , PUT , PATCH และ DELETE ที่จัดการ API ของ GraphQL
เราจะรวมการกลายพันธุ์ทั้งหมดไว้ใน RootMutation เดียวเพื่อสาธิต:
type RootMutation { createUser(input: UserInput!): User # Corresponds to POST /api/users updateUser(id: ID!, input: UserInput!): User # Corresponds to PATCH /api/users removeUser(id: ID!): User # Corresponds to DELETE /api/users createTodo(input: TodoInput!): Todo updateTodo(id: ID!, input: TodoInput!): Todo removeTodo(id: ID!): Todo }
คุณสังเกตเห็นการใช้ -input ประเภทสำหรับการกลายพันธุ์เช่น UserInput , TodoInput แนวทางปฏิบัติที่ดีที่สุดคือกำหนดประเภทอินพุตสำหรับสร้างและอัปเดตทรัพยากรของคุณเสมอ
คุณสามารถกำหนดประเภท I nput ดังต่อไปนี้:
input UserInput { firstname: String! lastname: String email: String! username: String! }
ตัวแก้ไข
ตัวแก้ไขจะบอก GraphQL ว่าต้องทำอย่างไรเมื่อมีการร้องขอการสืบค้นหรือการกลายพันธุ์แต่ละครั้ง เป็นฟังก์ชันพื้นฐานที่ทำงานหนักในการกดปุ่มเลเยอร์ฐานข้อมูลเพื่อดำเนินการ CRUD (สร้าง อ่าน อัปเดต ลบ) กดปุ่มจุดสิ้นสุด RESTful API ภายใน หรือเรียกไมโครเซอร์วิสเพื่อตอบสนองคำขอของลูกค้า
คุณสามารถสร้างไฟล์ Solvers.js ใหม่และเพิ่มรหัสต่อไปนี้:
import sequelize from '../models'; export default function resolvers () { const models = sequelize.models; return { // Resolvers for Queries RootQuery: { user (root, { id }, context) { return models.User.findById(id, context); }, users (root, args, context) { return models.User.findAll({}, context); } }, User: { todos (user) { return user.getTodos(); } }, } // Resolvers for Mutations RootMutation: { createUser (root, { input }, context) { return models.User.create(input, context); }, updateUser (root, { id, input }, context) { return models.User.update(input, { ...context, where: { id } }); }, removeUser (root, { id }, context) { return models.User.destroy(input, { ...context, where: { id } }); }, // ... Resolvers for Todos go here } }; }
สคีมา
GraphQL schema คือสิ่งที่ GraphQL เปิดเผยต่อโลก ดังนั้น ประเภท การสืบค้น และการกลายพันธุ์จะรวมอยู่ในสคีมาที่จะเปิดเผยต่อโลก
ด้านล่างนี้คือวิธีการเปิดเผยประเภท การสืบค้น และการกลายพันธุ์สู่โลก:
schema { query: RootQuery mutation: RootMutation }
ในสคริปต์ด้านบน เราได้รวม RootQuery และ RootMutation ที่เราสร้างไว้ก่อนหน้าเพื่อให้เปิดเผยต่อโลก
GraphQL ทำงานร่วมกับ Nodejs และ Expressjs อย่างไร
GraphQL จัดเตรียมการใช้งานสำหรับภาษาโปรแกรมหลักทั้งหมด และ Node.js ไม่ได้รับการยกเว้น บนเว็บไซต์อย่างเป็นทางการของ GraphQL มีส่วนสำหรับการสนับสนุน JavaScript และยังมีการใช้งาน GraphQL อื่นๆ เพื่อทำให้การเขียนและการเข้ารหัสใน GraphQL เป็นเรื่องง่าย
GraphQL Apollo ให้การใช้งานสำหรับ Node.js และ Express.js และทำให้ง่ายต่อการเริ่มต้นใช้งาน GraphQL
คุณจะได้เรียนรู้วิธีสร้างและพัฒนาแอปพลิเคชัน GraphQL แรกของคุณในเฟรมเวิร์กส่วนหลังของ Nodes.js และ Express.js โดยใช้ GraphQL Apollo ในส่วนถัดไป
การตั้งค่า GraphQL ด้วย Express.js
การสร้างเซิร์ฟเวอร์ GraphQL API ด้วย Express.js นั้นง่ายมากในการเริ่มต้น ในส่วนนี้ เราจะสำรวจวิธีสร้างเซิร์ฟเวอร์ GraphQL
เริ่มต้นโครงการด้วย Express
ก่อนอื่น คุณต้องติดตั้งและตั้งค่าโปรเจ็กต์ Express.js ใหม่
สร้างโฟลเดอร์สำหรับโครงการของคุณและติดตั้ง Express.js โดยใช้คำสั่งนี้:
cd <project-name> && npm init -y npm install express
คำสั่งด้านบนสร้างไฟล์ package.json ใหม่และติดตั้งไลบรารี Express.js ในโครงการของคุณ
ต่อไปเราจะจัดโครงสร้างโครงการของเราตามที่แสดงในภาพด้านล่าง มันจะมีโมดูลต่าง ๆ สำหรับคุณสมบัติของโครงการ เช่น ผู้ใช้ สิ่งที่ต้องทำ ฯลฯ
เริ่มต้น GraphQL
เริ่มต้นด้วยการติดตั้งการอ้างอิง GraphQL Express.js เรียกใช้คำสั่งต่อไปนี้เพื่อติดตั้ง:
npm install apollo-server-express graphql @graphql-tools/schema --save
การสร้างสคีมาและประเภท
ต่อไป เราจะสร้างไฟล์ index.js ภายในโฟลเดอร์ modules และเพิ่มข้อมูลโค้ดต่อไปนี้:
const { gql } = require('apollo-server-express'); const users = require('./users'); const todos = require('./todos'); const { GraphQLScalarType } = require('graphql'); const { makeExecutableSchema } = require('@graphql-tools/schema'); const typeDefs = gql` scalar Time type Query { getVersion: String! } type Mutation { version: String! } `; const timeScalar = new GraphQLScalarType({ name: 'Time', description: 'Time custom scalar type', serialize: (value) => value, }); const resolvers = { Time: timeScalar, Query: { getVersion: () => `v1`, }, }; const schema = makeExecutableSchema({ typeDefs: [typeDefs, users.typeDefs, todos.typeDefs], resolvers: [resolvers, users.resolvers, todos.resolvers], }); module.exports = schema;
คำแนะนำแบบใช้โค้ด
มาทำงานผ่านข้อมูลโค้ดและแยกย่อย:
ขั้นตอนที่ 1
ขั้นแรก เรานำเข้าไลบรารีที่จำเป็นและสร้างประเภทการค้นหาและการกลายพันธุ์ที่เป็นค่าเริ่มต้น การค้นหาและการกลายพันธุ์จะตั้งค่าเวอร์ชันของ GraphQL API เท่านั้นในตอนนี้ อย่างไรก็ตาม เราจะขยายการสืบค้นและการกลายพันธุ์เพื่อรวมสคีมาอื่นๆ เมื่อเราดำเนินการต่อไป
ขั้นตอนที่ 2:
จากนั้นเราได้สร้างประเภทสเกลาร์ใหม่สำหรับเวลาและตัวแก้ไขแรกของเราสำหรับการสืบค้นและการกลายพันธุ์ที่สร้างขึ้นด้านบน นอกจากนี้ เรายังสร้างสคีมาโดยใช้ฟังก์ชัน makeExecutableEchema
สคีมาที่สร้างขึ้นประกอบด้วยสคีมาอื่นๆ ทั้งหมดที่เรานำเข้า และจะรวมเพิ่มเติมเมื่อเราสร้างและนำเข้าสคีมา
ข้อมูลโค้ดด้านบนแสดงให้เห็นว่าเรานำเข้า schema ต่างๆ เข้าสู่ฟังก์ชัน makeExecutableEchema วิธีการนี้ช่วยเราในการจัดโครงสร้างแอปพลิเคชันสำหรับความซับซ้อน ต่อไป เราจะสร้าง Todo และ User schema ที่เรานำเข้า
การสร้าง Todo Schema
Todo schema แสดงการดำเนินการ CRUD อย่างง่ายที่ผู้ใช้แอปพลิเคชันสามารถทำได้ ด้านล่างนี้เป็นสคีมาที่ใช้การดำเนินการ Todo CRUD
const { gql } = require('apollo-server-express'); const createTodo = require('./mutations/create-todo'); const updateTodo = require('./mutations/update-todo'); const removeTodo = require('./mutations/delete-todo'); const todo = require('./queries/todo'); const todos = require('./queries/todos'); const typeDefs = gql` type Todo { id: ID! title: String description: String user: User } input CreateTodoInput { title: String! description: String isCompleted: Boolean } input UpdateTodoInput { title: String description: String isCompleted: Boolean } extend type Query { todo(id: ID): Todo! todos: [Todo!] } extend type Mutation { createTodo(input: CreateTodoInput!): Todo updateTodo(id: ID!, input: UpdateTodoInput!): Todo removeTodo(id: ID!): Todo } `; // Provide resolver functions for your schema fields const resolvers = { // Resolvers for Queries Query: { todo, todos, }, // Resolvers for Mutations Mutation: { createTodo, updateTodo, removeTodo, }, }; module.exports = { typeDefs, resolvers };
คำแนะนำแบบใช้โค้ด
มาทำงานผ่านข้อมูลโค้ดและแยกย่อย:
ขั้นตอนที่ 1:
ขั้นแรก เราสร้างสคีมาสำหรับ Todo โดยใช้ GraphQL type , input , และ expand คำหลัก ขยาย ใช้เพื่อสืบทอดและเพิ่มการสืบค้นและการกลายพันธุ์ใหม่ไปยังการสืบค้นรูทและการกลายพันธุ์ที่เราสร้างขึ้นด้านบน
ขั้นตอนที่ 2:
ต่อไป เราสร้างตัวแก้ไข ซึ่งใช้เพื่อดึงข้อมูลที่ถูกต้องเมื่อมีการเรียกการสืบค้นหรือการกลายพันธุ์เฉพาะ
เมื่อใช้ฟังก์ชันตัวแก้ไข เราสามารถสร้างวิธีการเฉพาะสำหรับตรรกะทางธุรกิจและการจัดการฐานข้อมูลดังที่แสดงในตัวอย่าง create-todo.js
สร้างไฟล์ create-user.js ในโฟลเดอร์ <code>./mutations</code> และเพิ่มตรรกะทางธุรกิจเพื่อสร้าง Todo ใหม่ในฐานข้อมูลของคุณ
const models = require('../../../models'); module.exports = async (root, { input }, context) => { return models.todos.push({ ...input }); };
ข้อมูลโค้ดด้านบนเป็นวิธีที่ง่ายในการสร้าง Todo ใหม่ในฐานข้อมูลของเราโดยใช้ Sequelize ORM คุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับ Sequelize และวิธีตั้งค่าด้วย Node.js
คุณสามารถทำตามขั้นตอนเดียวกันเพื่อสร้างสคีมาจำนวนมากขึ้นอยู่กับแอปพลิเคชันของคุณ หรือคุณสามารถโคลนโครงการทั้งหมดจาก GitHub
ต่อไป เราจะตั้งค่าเซิร์ฟเวอร์ด้วย Express.js และเรียกใช้แอปพลิเคชัน Todo ที่สร้างขึ้นใหม่ด้วย GraphQL และ Node.js
การตั้งค่าและ ใช้งานเซิร์ฟเวอร์
สุดท้าย เราจะตั้งค่าเซิร์ฟเวอร์ของเราโดยใช้ไลบรารี apollo-server-express ที่ เราติดตั้งก่อนหน้านี้และกำหนดค่า
apollo-server-express เป็น wrapper อย่างง่ายของ Apollo Server สำหรับ Express.js ขอแนะนำเนื่องจากได้รับการพัฒนาให้เหมาะกับการพัฒนา Express.js
ใช้ตัวอย่างที่เรากล่าวถึงข้างต้น มากำหนดค่าเซิร์ฟเวอร์ Express.js ให้ทำงานร่วมกับ apollo-server-express ที่เพิ่งติดตั้งใหม่
สร้างไฟล์ server.js ในไดเร็กทอรี root และวางโค้ดต่อไปนี้:
const express = require('express'); const { ApolloServer } = require('apollo-server-express'); const schema = require('./modules'); const app = express(); async function startServer() { const server = new ApolloServer({ schema }); await server.start(); server.applyMiddleware({ app }); } startServer(); app.listen({ port: 3000 }, () => console.log(`Server ready at http://localhost:3000`) );
ในโค้ดด้านบน คุณได้สร้างเซิร์ฟเวอร์ CRUD GraphQL แรกสำหรับ Todos และ Users เรียบร้อยแล้ว คุณสามารถเริ่มเซิร์ฟเวอร์การพัฒนาและเข้าถึง Playground ได้โดยใช้ http://localhost:3000/graphql หากทุกอย่างสำเร็จ คุณจะเห็นหน้าจอด้านล่าง:
สรุป
GraphQL เป็นเทคโนโลยีสมัยใหม่ที่สนับสนุนโดย Facebook ซึ่งช่วยลดความซับซ้อนของงานที่น่าเบื่อหน่ายที่เกี่ยวข้องกับการสร้าง API ขนาดใหญ่ด้วยรูปแบบสถาปัตยกรรม RESTful
คู่มือนี้ได้อธิบาย GraphQL และแสดงวิธีพัฒนา GraphQL API แรกของคุณด้วย Express.js
แจ้งให้เราทราบว่าคุณสร้างอะไรโดยใช้ GraphQL