paint-brush
Nâng cao kỹ năng GraphQL của tôi: Đăng ký theo thời gian thựctừ tác giả@johnjvester
418 lượt đọc
418 lượt đọc

Nâng cao kỹ năng GraphQL của tôi: Đăng ký theo thời gian thực

từ tác giả John Vester10m2024/09/18
Read on Terminal Reader

dài quá đọc không nổi

Đi sâu hơn một chút để khám phá các đăng ký dữ liệu thời gian thực bằng cách sử dụng GraphQL để tự động nhận các bản cập nhật phía máy chủ với sự trợ giúp từ trình duyệt WebSocket.
featured image - Nâng cao kỹ năng GraphQL của tôi: Đăng ký theo thời gian thực
John Vester HackerNoon profile picture

Trong vài năm trở lại đây, tôi đã cố gắng xác định các khuôn khổ, sản phẩm và dịch vụ cho phép các nhà công nghệ duy trì sự tập trung vào việc mở rộng giá trị sở hữu trí tuệ của họ. Đây vẫn là một hành trình tuyệt vời đối với tôi, chứa đầy những cơ hội học tập độc đáo.


Kỹ sư trong tôi gần đây tự hỏi liệu có tình huống nào mà tôi có thể tìm ra lợi ích thứ cấp cho một khái niệm hiện có mà tôi đã nói đến trước đây không. Nói cách khác, tôi có thể xác định một lợi ích khác có cùng mức tác động như giải pháp gốc ban đầu đã được công nhận trước đó không?


Đối với bài viết này, tôi muốn đi sâu hơn vào GraphQL để xem tôi có thể tìm thấy những gì.


Trong bài viết “ Khi nào là lúc để REST nghỉ ngơi ”, tôi đã nói về những tình huống thực tế khi GraphQL được ưa chuộng hơn dịch vụ RESTful. Chúng tôi đã hướng dẫn cách xây dựng và triển khai API GraphQL bằng Apollo Server.


Trong bài đăng tiếp theo này, tôi dự định nâng cao kiến thức của mình về GraphQL bằng cách hướng dẫn qua các đăng ký để truy xuất dữ liệu theo thời gian thực. Chúng tôi cũng sẽ xây dựng một dịch vụ WebSocket để sử dụng các đăng ký.

Tóm tắt: Trường hợp sử dụng Customer 360

Bài viết trước của tôi tập trung vào trường hợp sử dụng Customer 360, trong đó khách hàng của doanh nghiệp hư cấu của tôi duy trì các bộ sưu tập dữ liệu sau:


  • Thông tin khách hàng
  • Thông tin địa chỉ
  • Phương pháp liên lạc
  • Thuộc tính tín dụng


Một lợi ích lớn khi sử dụng GraphQL là một yêu cầu GraphQL duy nhất có thể truy xuất tất cả dữ liệu cần thiết cho mã thông báo (nhận dạng duy nhất) của khách hàng.


 type Query { addresses: [Address] address(customer_token: String): Address contacts: [Contact] contact(customer_token: String): Contact customers: [Customer] customer(token: String): Customer credits: [Credit] credit(customer_token: String): Credit }


Sử dụng phương pháp RESTful để truy xuất chế độ xem đơn (360) của khách hàng sẽ yêu cầu nhiều yêu cầu và phản hồi được ghép lại với nhau. GraphQL cung cấp cho chúng ta một giải pháp hoạt động tốt hơn nhiều.

Mục tiêu nâng cấp

Để thăng tiến trong bất kỳ khía cạnh nào của cuộc sống, người ta phải đạt được những mục tiêu mới. Đối với mục tiêu của riêng tôi ở đây, điều này có nghĩa là:


  • Hiểu và triển khai đề xuất giá trị đăng ký trong GraphQL.
  • Sử dụng triển khai WebSocket để sử dụng đăng ký GraphQL.


Ý tưởng sử dụng đăng ký thay vì truy vấn và đột biến trong GraphQL là phương pháp được ưu tiên khi đáp ứng các điều kiện sau:


  • Những thay đổi nhỏ, gia tăng đối với các đối tượng lớn
  • Cập nhật thời gian thực, độ trễ thấp (chẳng hạn như ứng dụng trò chuyện)


Điều này rất quan trọng vì việc triển khai đăng ký bên trong GraphQL không hề đơn giản. Không chỉ máy chủ cơ sở cần được cập nhật mà ứng dụng sử dụng cũng cần được thiết kế lại.


May mắn thay, trường hợp sử dụng mà chúng tôi đang theo đuổi với ví dụ Customer 360 của mình rất phù hợp với đăng ký. Ngoài ra, chúng tôi sẽ triển khai phương pháp WebSocket để tận dụng các đăng ký đó.


Giống như trước đây, tôi sẽ tiếp tục sử dụng Apollo trong tương lai.

Nâng cấp với tín dụng đăng ký

Đầu tiên, chúng ta cần cài đặt các thư viện cần thiết để hỗ trợ đăng ký với máy chủ Apollo GraphQL của tôi:


 npm install ws npm install graphql-ws @graphql-tools/schema npm install graphql-subscriptions


Sau khi cài đặt các mục đó, tôi tập trung vào việc cập nhật index.ts từ kho lưu trữ gốc của mình để mở rộng hằng số typedefs như sau:


 type Subscription { creditUpdated: Credit }


Tôi cũng đã thiết lập một hằng số để chứa một thể hiện PubSub mới và tạo một đăng ký mẫu mà chúng ta sẽ sử dụng sau:


 const pubsub = new PubSub(); pubsub.publish('CREDIT_BALANCE_UPDATED', { creditUpdated: { } });


Tôi đã dọn dẹp các trình phân giải hiện có và thêm một Subscription mới cho trường hợp sử dụng mới này:


 const resolvers = { Query: { addresses: () => addresses, address: (parent, args) => { const customer_token = args.customer_token; return addresses.find(address => address.customer_token === customer_token); }, contacts: () => contacts, contact: (parent, args) => { const customer_token = args.customer_token; return contacts.find(contact => contact.customer_token === customer_token); }, customers: () => customers, customer: (parent, args) => { const token = args.token; return customers.find(customer => customer.token === token); }, credits: () => credits, credit: (parent, args) => { const customer_token = args.customer_token; return credits.find(credit => credit.customer_token === customer_token); } }, Subscription: { creditUpdated: { subscribe: () => pubsub.asyncIterator(['CREDIT_BALANCE_UPDATED']), } } };


Sau đó, tôi đã thiết kế lại cấu hình máy chủ và giới thiệu thiết kế đăng ký:


 const app = express(); const httpServer = createServer(app); const wsServer = new WebSocketServer({ server: httpServer, path: '/graphql' }); const schema = makeExecutableSchema({ typeDefs, resolvers }); const serverCleanup = useServer({ schema }, wsServer); const server = new ApolloServer({ schema, plugins: [ ApolloServerPluginDrainHttpServer({ httpServer }), { async serverWillStart() { return { async drainServer() { serverCleanup.dispose(); } }; } } ], }); await server.start(); app.use('/graphql', cors(), express.json(), expressMiddleware(server, { context: async () => ({ pubsub }) })); const PORT = Number.parseInt(process.env.PORT) || 4000; httpServer.listen(PORT, () => { console.log(`Server is now running on http://localhost:${PORT}/graphql`); console.log(`Subscription is now running on ws://localhost:${PORT}/graphql`); });


Để mô phỏng các bản cập nhật do khách hàng thúc đẩy, tôi đã tạo phương pháp sau để tăng số dư tín dụng thêm 50 đô la sau mỗi năm giây trong khi dịch vụ đang chạy. Khi số dư đạt (hoặc vượt quá) giới hạn tín dụng là 10.000 đô la, tôi đặt lại số dư về 2.500 đô la, mô phỏng việc thanh toán số dư đang được thực hiện.


 function incrementCreditBalance() { if (credits[0].balance >= credits[0].credit_limit) { credits[0].balance = 0.00; console.log(`Credit balance reset to ${credits[0].balance}`); } else { credits[0].balance += 50.00; console.log(`Credit balance updated to ${credits[0].balance}`); } pubsub.publish('CREDIT_BALANCE_UPDATED', { creditUpdated: credits[0] }); setTimeout(incrementCreditBalance, 5000); } incrementCreditBalance();


Bạn có thể tìm thấy tệp index.ts đầy đủ tại đây .

Triển khai tới Heroku

Khi dịch vụ đã sẵn sàng, đã đến lúc chúng ta triển khai dịch vụ để có thể tương tác với nó. Vì Heroku hoạt động rất tốt lần trước (và tôi cũng dễ sử dụng), chúng ta hãy tiếp tục với cách tiếp cận đó.


Để bắt đầu, tôi cần chạy các lệnh Heroku CLI sau:


 $ heroku login $ heroku create jvc-graphql-server-sub Creating ⬢ jvc-graphql-server-sub... done https://jvc-graphql-server-sub-1ec2e6406a82.herokuapp.com/ | https://git.heroku.com/jvc-graphql-server-sub.git


Lệnh này cũng tự động thêm kho lưu trữ được Heroku sử dụng làm kho lưu trữ từ xa:


 $ git remote heroku origin


Như tôi đã lưu ý trong bài viết trước, Apollo Server vô hiệu hóa Apollo Explorer trong môi trường sản xuất. Để Apollo Explorer luôn sẵn sàng cho nhu cầu của chúng tôi, tôi cần đặt biến môi trường NODE_ENV thành development. Tôi đặt biến đó bằng lệnh CLI sau:


 $ heroku config:set NODE_ENV=development Setting NODE_ENV and restarting ⬢ jvc-graphql-server-sub... done, v3 NODE_ENV: development


Tôi đã sẵn sàng triển khai mã của mình lên Heroku:


 $ git commit --allow-empty -m 'Deploy to Heroku' $ git push heroku


Nhìn nhanh vào Bảng điều khiển Heroku cho thấy Máy chủ Apollo của tôi đang chạy mà không có bất kỳ sự cố nào:


Trong phần Cài đặt, tôi tìm thấy URL ứng dụng Heroku cho phiên bản dịch vụ này:


https://jvc-graphql-server-sub-1ec2e6406a82.herokuapp.com/


Xin lưu ý – liên kết này sẽ không còn hoạt động vào thời điểm bài viết này được xuất bản.


Hiện tại, tôi có thể thêm GraphQL vào URL này để khởi chạy Apollo Server Studio. Điều này cho phép tôi thấy các đăng ký hoạt động như mong đợi:


Lưu ý các phản hồi Đăng ký ở phía bên phải màn hình.

Nâng cấp với WebSocket Skillz

Chúng ta có thể tận dụng hỗ trợ WebSocket và khả năng của Heroku để tạo ra một triển khai sử dụng gói đăng ký mà chúng ta đã tạo.


Trong trường hợp của tôi, tôi đã tạo một tệp index.js với nội dung sau. Về cơ bản, tệp này đã tạo một máy khách WebSocket và cũng thiết lập một dịch vụ HTTP giả mà tôi có thể sử dụng để xác thực máy khách đang chạy:


 import { createClient } from "graphql-ws"; import { WebSocket } from "ws"; import http from "http"; // Create a dummy HTTP server to bind to Heroku's $PORT const PORT = process.env.PORT || 3000; http.createServer((req, res) => res.end('Server is running')).listen(PORT, () => { console.log(`HTTP server running on port ${PORT}`); }); const host_url = process.env.GRAPHQL_SUBSCRIPTION_HOST || 'ws://localhost:4000/graphql'; const client = createClient({ url: host_url, webSocketImpl: WebSocket }); const query = `subscription { creditUpdated { token customer_token credit_limit balance credit_score } }`; function handleCreditUpdated(data) { console.log('Received credit update:', data); } // Subscribe to the creditUpdated subscription client.subscribe( { query, }, { next: (data) => handleCreditUpdated(data.data.creditUpdated), error: (err) => console.error('Subscription error:', err), complete: () => console.log('Subscription complete'), } );


Bạn có thể tìm thấy tệp index.js đầy đủ tại đây .


Chúng ta cũng có thể triển khai ứng dụng Node.js đơn giản này lên Heroku, đảm bảo đặt biến môi trường GRAPHQL_SUBSCRIPTION_HOST thành URL ứng dụng Heroku mà chúng ta đã sử dụng trước đó.


Tôi cũng đã tạo Procfile sau để hướng dẫn Heroku cách khởi động ứng dụng của tôi:


 web: node src/index.js


Tiếp theo, tôi tạo một ứng dụng Heroku mới:


 $ heroku create jvc-websocket-example Creating ⬢ jvc-websocket-example... done https://jvc-websocket-example-62824c0b1df4.herokuapp.com/ | https://git.heroku.com/jvc-websocket-example.git


Sau đó, tôi đặt biến môi trường GRAPHQL_SUBSCRIPTION_HOST để trỏ đến máy chủ GraphQL đang chạy của tôi:


 $ heroku --app jvc-websocket-example \ config:set \ GRAPHQL_SUBSCRIPTION_HOST=ws://jvc-graphql-server-sub-1ec2e6406a82.herokuapp.com/graphql


Tại thời điểm này, chúng ta đã sẵn sàng triển khai mã của mình lên Heroku:


 $ git commit --allow-empty -m 'Deploy to Heroku' $ git push heroku


Khi máy khách WebSocket khởi động, chúng ta có thể thấy trạng thái của nó trong Bảng điều khiển Heroku:


Bằng cách xem nhật ký trong Heroku Dashboard cho phiên bản jvc-websocket-example , chúng ta có thể thấy nhiều bản cập nhật cho thuộc tính balance của dịch vụ jvc-graphql-server-sub . Trong bản demo của mình, tôi thậm chí có thể nắm bắt được trường hợp sử dụng khi số dư giảm xuống bằng không, mô phỏng rằng đã thực hiện thanh toán:


Trong terminal, chúng ta có thể truy cập các bản ghi đó bằng lệnh CLI heroku logs.


 2024-08-28T12:14:48.463846+00:00 app[web.1]: Received credit update: { 2024-08-28T12:14:48.463874+00:00 app[web.1]: token: 'credit-token-1', 2024-08-28T12:14:48.463875+00:00 app[web.1]: customer_token: 'customer-token-1', 2024-08-28T12:14:48.463875+00:00 app[web.1]: credit_limit: 10000, 2024-08-28T12:14:48.463875+00:00 app[web.1]: balance: 9950, 2024-08-28T12:14:48.463876+00:00 app[web.1]: credit_score: 750 2024-08-28T12:14:48.463876+00:00 app[web.1]: }


Chúng tôi không chỉ có dịch vụ GraphQL với triển khai đăng ký đang chạy mà còn có máy khách WebSocket sử dụng các bản cập nhật đó.

Phần kết luận

Độc giả của tôi có thể nhớ lại tuyên bố sứ mệnh cá nhân của tôi, mà tôi cảm thấy có thể áp dụng cho bất kỳ chuyên gia CNTT nào:


“Tập trung thời gian của bạn vào việc cung cấp các tính năng/chức năng mở rộng giá trị sở hữu trí tuệ của bạn. Tận dụng các khuôn khổ, sản phẩm và dịch vụ cho mọi thứ khác.” — J. Vester


Trong bài phân tích sâu này về đăng ký GraphQL, chúng tôi đã sử dụng thành công các bản cập nhật từ Apollo Server chạy trên Heroku bằng cách sử dụng một dịch vụ khác cũng chạy trên Heroku—một ứng dụng dựa trên Node.js sử dụng WebSockets. Bằng cách tận dụng các đăng ký nhẹ, chúng tôi đã tránh gửi các truy vấn cho dữ liệu không thay đổi mà chỉ cần đăng ký để nhận các bản cập nhật số dư tín dụng khi chúng xảy ra.


Trong phần giới thiệu, tôi đã đề cập đến việc tìm kiếm một nguyên tắc giá trị bổ sung bên trong một chủ đề mà tôi đã viết trước đây. Đăng ký GraphQL là một ví dụ tuyệt vời về những gì tôi nghĩ đến vì nó cho phép người tiêu dùng nhận được các bản cập nhật ngay lập tức, mà không cần phải thực hiện các truy vấn đối với dữ liệu nguồn. Điều này sẽ khiến người tiêu dùng của dữ liệu Customer 360 rất phấn khích, biết rằng họ có thể cập nhật trực tiếp khi chúng xảy ra.


Heroku là một ví dụ khác tiếp tục tuân thủ tuyên bố sứ mệnh của tôi bằng cách cung cấp một nền tảng cho phép tôi nhanh chóng tạo nguyên mẫu các giải pháp bằng CLI và các lệnh Git chuẩn. Điều này không chỉ giúp tôi dễ dàng giới thiệu trường hợp sử dụng đăng ký của mình mà còn triển khai người dùng bằng WebSockets.


Nếu bạn quan tâm đến mã nguồn của bài viết này, hãy xem kho lưu trữ của tôi trên GitLab:



Tôi cảm thấy tự tin khi nói rằng tôi đã nâng cao thành công kỹ năng GraphQL của mình thông qua nỗ lực này. Hành trình này mới mẻ và đầy thử thách đối với tôi… và cũng rất thú vị!


Tôi dự định sẽ tìm hiểu sâu hơn về xác thực, hy vọng sẽ cung cấp thêm cơ hội để nâng cao trình độ với GraphQL và Apollo Server. Hãy theo dõi nhé!


Chúc bạn một ngày thật tuyệt vời!