- vừa được xem lúc

Hướng dẫn tạo và deploy GraphQL server KHÔNG CẦN SERVER với Cloudflare

0 0 11

Người đăng: Nguyễn Hữu Kim

Theo Viblo Asia

👋👋👋 Hello hello, xin chào tất cả anh em. Anh em nào đã lỡ vào đây rồi thì comment chào nhau một cái nhé cho đông vui nhé!

Ngày hôm nay, mình sẽ chia sẻ tới các bạn một chủ đề mới cũng không kém phần thú vị so với bài Giới thiệu về Microservices Architecture vừa rồi. Với các bạn quan tâm tới GraphQL và Serverless thì bài viết này là dành cho bạn.

👉️ Prerequisites

  • Đã nắm được cơ bản về GraphQL: query, mutation
  • Biết về Apollo Server thì càng tốt (optional)
  • Biết về Cloudflare Workers thì càng tốt (optional)

Trong bài viết này, mình sẽ hướng dẫn cách build và deploy một GraphQL server lên Cloudflare Workers. Bạn không tốn một đồng chi phí server nào cả do dùng Cloudflare Workers với Free plan: 100,000 requests / ngày.

👉️ Apollo Server

GraphQL Server mình dùng trong bài viết này là Apollo Server. Apollo Server là một trong số các library thông dụng của Node.js để dựng GraphQL Server. Một số điểm nổi bật đó là:

  • Dựng GraphQL server nhanh chóng
  • Dễ dàng mở rộng, làm việc trong đội hình nhiều team
  • Implement sẵn các cơ chế cache trên cả server và client side
  • Hỗ trợ cơ chế Federation, giúp tách GraphQL server thành nhiều GraphQL server nhỏ hơn (gọi là sub-graph)
  • Document cung cấp rõ ràng, tutorial hệ thống hóa chi tiết và dễ tiếp cận

(Hình 1: Apollo Federation - Nguồn: ApolloGraphQL)

Ra mắt từ khá lâu, Apollo Server mới release v4 vào tháng 10 năm 2022 (mình nhớ không nhầm thì vậy), với một số breaking change. Trong đó thì các phần tích hợp Apollo Server vào các framework như: Express, H3, Cloudflare, AWS Lambda... bị xóa bỏ hoàn toàn khỏi official package của Apollo Server.

Thời điểm đó Cloudflare cũng chưa có nhận phát triển lại phần integration. Cộng với việc mình đang maintain một repo-template để chạy Apollo Server v3 trên Cloudflare nên mình đã phát triển luôn một phiên bản integration để tích hợp Cloudflare Workers và Apollo Server v4.

👉️ Template Repository

Bài viết này sử dụng Apollo Server v4 và một phiên bản tích hợp với package apollo-server-integrations-cloudflare-workers do chính mình phát triển. Hiện tại package này mới được publish trên NPM dưới namespace @as-integrations/cloudfare-workers. Tạm thời đang để v0.1.0 do mình chưa có thời gian viết bổ sung tests.

https://www.npmjs.com/package/@as-integrations/cloudflare-workers

Các bạn yêu thích thì vào repo thả cho mình một star với nhé! 😉

Để cài đặt vào project Cloudflare Workers đã có sẵn, sử dụng NPM như sau:

npm install @apollo/server graphql @as-integrations/cloudflare-workers

Trong bài viết này, mình demo bằng cách sử dụng một source code được mình setup sẵn dưới dạng một Template Repo trên Github. Bạn chỉ cần nhấn nút xanh lá cây Use this template là dùng thôi:

(Hình 2: Khởi tạo source code với Github Template)

Link repo: https://github.com/kimyvgy/worker-apollo-server-template


👉️ Viết code GraphQL Server

Tạo file schema.graphql

Không giống như REST, các request lên server sẽ chia làm hai loại cơ bản là QueryMutation:

  • Query: Client muốn lấy dữ liệu về một resource nào đó về. VD: GetAuthor(username: "huukimit")
  • Mutation: Client muốn thực hiện action sửa đổi/update dữ liệu. VD: FollowAuthor(username: "huukimit")

Các mô tả về Query và Mutation được khai báo trong file schema.graphql. Cả client và server đều sử dụng file này để generate ra code khai báo Type của từng Resource tương ứng.

Trong ví dụ này, mình sẽ tạo schema như sau:

type Query { example: String! pokemon(id: ID!): Pokemon
} type PokemonSprites { front_default: String! front_shiny: String! front_female: String! front_shiny_female: String! back_default: String! back_shiny: String! back_female: String! back_shiny_female: String!
} type Pokemon { id: ID! name: String! height: Int! weight: Int! sprites: PokemonSprites!
}

Hiểu đơn giản là phía server cung cấp 2 query:

  • example: Không cần tham số, trả về một string
  • pokemon: Truy vấn thông tin một Pokemon theo một ID xác định, với các trường nhất định. Bạn đọc chắc là cũng hiểu ngay.

Các thông tin về pokemon mình sẽ viết resolver lấy từ service https://pokeapi.co/api/v2/.

GraphQL codegen

Cloudflare chạy JavaScript nên mình sử dụng các công cụ của graphql-codegen để tự động tạo các kiểu dữ liệu để dùng cho TypeScript + React. File cấu hình này cũng đã được tạo sẵn trong repo.

schema: "./src/schema.graphql" generates: ./src/@types/schema.generated.ts: plugins: - typescript - typescript-resolvers config: enumsAsConst: true namingConvention: enumValues: keep

Chạy lệnh sau để chạy codegen:

npm run generate

Command thực ra là alias của:

npx graphql-codegen --config codegen.yml

Chạy GraphQL Server

Để tạo server, mình khởi tạo instance cho Apollo Server cũng khá đơn giản, với vài dòng như sau:

const server = new ApolloServer<ContextValue>({ typeDefs, resolvers, introspection: true, plugins: [ ApolloServerPluginLandingPageLocalDefault({ footer: false }), ],
});

Full source code tích hợp với Cloudflare Wokers bằng integration @as-integrations/cloudflare-workers sẽ như sau:

import type { CloudflareWorkersHandler } from '@as-integrations/cloudflare-workers'; import { ApolloServer } from '@apollo/server';
import { startServerAndCreateCloudflareWorkersHandler } from '@as-integrations/cloudflare-workers';
import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin/landingPage/default'; interface ApolloDataSources { pokemonAPI: PokemonAPI;
} interface ContextValue { token: string; dataSources: ApolloDataSources;
}; const server = new ApolloServer<ContextValue>({ typeDefs, resolvers, introspection: true, plugins: [ ApolloServerPluginLandingPageLocalDefault({ footer: false }), ],
}); const handleGraphQLRequest: CloudflareWorkersHandler = startServerAndCreateCloudflareWorkersHandler(server, { context: async ({ request }) => { const token = request.headers.token || ''; const cache = server.cache; const dataSources: ApolloDataSources = { pokemonAPI: new PokemonAPI({ cache, token }), }; return { dataSources, token }; },
}); addEventListener((e) => handleGraphQLRequest(e.request as Request));

Trong đó:

  • Hàm chạy chính của graphql server là startServerAndCreateCloudflareWorkersHandler. Nó sẽ chạy apollo server trên Cloudflare Workers, sau đó trả về một handler có kiểu CloudflareWorkersHandler.
  • CloudflareWorkersHandler là một function, nhận vào tham số kiểu Request và trả về Response để dùng trực tiếp trong Cloudflare Workers.

Viết resolver

File schema chỉ là mô tả về các Query, còn query đó xử lý logic như nào thì chúng ta cần viết thêm resolvers cho Apollo Server. Trong ví dụ này mình viết đơn giản như sau:

import { Resolvers } from "./@types/schema.generated"; const resolvers: Resolvers<ApolloContext> = { Query: { example: () => { return 'Hello world!'; }, pokemon: (_source, { id }, { dataSources }) => { return dataSources.pokemonAPI.getPokemon(id); }, }
} export default resolvers;

Trong đó:

  • example: mình trả về câu "Hello world!"
  • pokemon: mình sẽ dùng REST datasource để gửi request tới PokemonAPI.

Đối với REST Datasource, mình đã implement sẵn KV Cache để cache lại response vào Cloudflare KV. Cách sử dụng bạn tham khảo thêm trong source code và repo nhé. 😉

Development

Dưới local, chạy lệnh npm run dev để build và start GraphQL.

npm run dev

Lệnh này thực hiện 2 việc:

  • Chạy lại codegen khi schema file thay đổi
  • Rebuild lại worker khi source code thay đổi

Truy cập http://localhost:8787 để vào trang Sandbox test thử GraphQL:

(Apollo GraphQL Sandbox)

Deploy

Sử dụng wrangler v2 để deploy source code lên Cloudflare.

npm run deploy
yarn run v1.22.19
$ wrangler publish ⛅️ wrangler 2.1.9
-------------------
Running custom build: npm run generate && npm run build > generate
> graphql-codegen --config codegen.yml ✔ Parse Configuration
✔ Generate outputs > build
> NODE_ENV=production node worker.build.js Your worker has access to the following bindings:
- KV Namespaces: - GRAPHQL_CACHE: dbdc624f2c684f1bb88fa38ab249a13e
- Vars: - GRAPHQL_BASE_ENDPOINT: "/" - GRAPHQL_KV_CACHE: "true"
Total Upload: 1520.16 KiB / gzip: 285.68 KiB
Uploaded worker-apollo-server (2.71 sec)
Published worker-apollo-server (0.28 sec) https://worker-apollo-server.webee-asia.workers.dev
Done in 7.29s.

CI/CD

Trong repo template, mình cũng đã setup sẵn Github Actions để tự động deploy. Bạn cần cung cấp API Token + Account ID của tài khoản Cloudflare vào cho github action là OK.

(Thêm repo secrets cho CI/CD để auto deploy)

(Github Actions Pipeline)

Tổng kết

Trên đây là bài viết chia sẻ cách tích hợp và deploy Apollo Server với Cloudflare Workers. Chi tiết tham khảo:


⚠️ CHỖ NÀY PHẢI CHÚ Ý:

  • Nếu bạn quan tâm tới chủ đề này và muốn mình ra thêm các bài viết tương tự, hãy comment xuống dưới nhé!
  • Đừng quên cho mình một upvote / bookmark / follow để ủng hộ mình và có nhận được thông báo khi có bài viết mới nha.
  • Donate cho mình nếu bạn thấy nội dung này hữu ích và muốn mình làm thêm về các topic bạn mong đợi: Mono, Paypal, Bank
  • => Link donate: https://kimyvgy.webee.asia

Bình luận

Bài viết tương tự

- vừa được xem lúc

GraphQL SDL - Schema Definition Language Phần 2

Nối tiếp Phần một về Schema Difinition Language của GraphQL, bài viết này trình bày tiếp các khái niệm được sử dụng để định nghĩa GraphQL Schema. 1. Interfaces. .

0 0 64

- vừa được xem lúc

GraphQL SDL - Schema Definition Language Phần 1

1. GraphQL Schema Difinition Language là gì. SDL là một ngôn ngữ có cú pháp rất đơn giản, dễ hiểu đồng thời cũng rất mạnh mẽ và trực quan giúp định nghĩa schema một các cô đọng nhất. id: String.

0 0 47

- vừa được xem lúc

Mini Apollo GraphQL React client - server

Chào anh em, lại là mình đây . Hôm nay mình lại tiếp tục đi đến một chủ đề khá thú vị, cực kì phù hợp cho các anh em thích nghịch ngợm và cũng đơn giản để có thiển triển khai các pet project trong tương lai.

0 0 22

- vừa được xem lúc

Dgraph Graph Database in 100 Seconds

Learn the fundamentals of Dgraph - an open-source Graph Database that implements GraphQL as its query language https://bit.ly/3qc2Nac. . #database #graphql #100SecondsOfCode.

0 0 27

- vừa được xem lúc

Thực thi truy vấn GraphQL trên Server

1. Giới thiệu chung. . .

0 0 90

- vừa được xem lúc

Hasura in 100 Seconds

Learn how Hasura can instantly turn your SQL database into a GraphQL API. https://github.com/hasura/graphql-engine. .

0 0 28