برنامه نویسی

ارتقاء سطح مهارت های GraphQL من: اشتراک در زمان واقعی

Summarize this content to 400 words in Persian Lang

چند سالی است که سعی کرده‌ام چارچوب‌ها، محصولات و خدماتی را شناسایی کنم که به فن‌آوران اجازه می‌دهد تمرکز خود را بر گسترش ارزش مالکیت معنوی خود حفظ کنند. این همچنان یک سفر فوق العاده برای من است، پر از فرصت های یادگیری منحصر به فرد.

مهندس درون من اخیراً به این فکر کرد که آیا موقعیتی وجود دارد که بتوانم یک مزیت ثانویه برای یک مفهوم موجود پیدا کنم که قبلاً در مورد آن صحبت کرده ام. به عبارت دیگر، آیا می‌توانم مزیت دیگری را با همان سطح تأثیر راه‌حل اصلی که قبلاً شناسایی شده بود شناسایی کنم؟

برای این مقاله، می‌خواستم عمیق‌تر به GraphQL بپردازم تا ببینم چه چیزی می‌توانم پیدا کنم.

در مقاله خود با عنوان «وقتی زمان استراحت است»، در مورد اینکه چگونه سناریوهای دنیای واقعی وجود دارد که GraphQL به یک سرویس RESTful ارجحیت دارد، صحبت کردم. نحوه ساخت و استقرار API GraphQL با استفاده از سرور آپولو را بررسی کردیم.

در این پست بعدی، من قصد دارم دانش خود را در مورد GraphQL با قدم زدن در اشتراک‌ها برای بازیابی اطلاعات در زمان واقعی ارتقا دهم. ما همچنین یک سرویس WebSocket برای مصرف اشتراک ها ایجاد خواهیم کرد.

خلاصه: Customer 360 Use Case

مقاله قبلی من حول یک مورد استفاده از Customer 360 متمرکز بود که در آن مشتریان کسب و کار خیالی من مجموعه داده های زیر را نگهداری می کنند:

اطلاعات مشتری
اطلاعات آدرس
روش های تماس
ویژگی های اعتباری

یک پیروزی بزرگ در استفاده از GraphQL این است که یک درخواست GraphQL می تواند تمام داده های لازم برای توکن مشتری (هویت منحصر به فرد) را بازیابی کند.

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
}

استفاده از یک رویکرد RESTful برای بازیابی نمای واحد (360) مشتری نیاز به چندین درخواست و پاسخ دارد. GraphQL راه حلی به ما می دهد که عملکرد بسیار بهتری دارد.

اهداف سطح بالا

برای ارتقاء سطح در هر جنبه ای از زندگی، فرد باید به اهداف جدیدی دست یابد. برای اهداف خودم در اینجا، این به این معنی است:

درک و پیاده سازی ارزش پیشنهادی اشتراک ها در GraphQL.
استفاده از پیاده سازی WebSocket برای مصرف اشتراک GraphQL.

ایده استفاده از اشتراک‌ها بر روی کوئری‌ها و جهش‌ها در GraphQL زمانی که شرایط زیر برآورده شود، روش ترجیحی است:

تغییرات کوچک و تدریجی در اجسام بزرگ
به‌روزرسانی‌های بی‌درنگ و با تأخیر کم (مانند برنامه چت)

این مهم است، زیرا پیاده‌سازی اشتراک‌ها در GraphQL بی‌اهمیت نیست. نه تنها سرور اصلی نیاز به به روز رسانی دارد، بلکه برنامه مصرف کننده نیز نیاز به طراحی مجدد دارد.

خوشبختانه، موردی که ما با نمونه مشتری 360 دنبال می کنیم، برای اشتراک ها مناسب است. همچنین، ما یک رویکرد WebSocket را برای استفاده از این اشتراک ها پیاده سازی خواهیم کرد.

مانند قبل، به استفاده از آپولو ادامه خواهم داد.

ارتقاء سطح با اعتبار اشتراک

ابتدا باید کتابخانه های لازم را برای پشتیبانی از اشتراک با سرور آپولو GraphQL خود نصب کنیم:

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

با نصب آن موارد، روی به روز رسانی آن تمرکز کردم index.ts از مخزن اصلی من برای گسترش typedefs ثابت با موارد زیر:

type Subscription {
creditUpdated: Credit
}

من همچنین یک ثابت برای خانه جدید تاسیس کردم PubSub نمونه و یک نمونه اشتراک ایجاد کردیم که بعداً از آن استفاده خواهیم کرد:

const pubsub = new PubSub();

pubsub.publish(‘CREDIT_BALANCE_UPDATED’, {
creditUpdated: {
}
});

من حل کننده های موجود را پاک کردم و یک جدید اضافه کردم Subscription برای این مورد استفاده جدید:

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’]),
}
}
};

سپس پیکربندی سرور را بازسازی کردم و طرح اشتراک را معرفی کردم:

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`);
});

برای شبیه‌سازی به‌روزرسانی‌های مبتنی بر مشتری، روش زیر را ایجاد کردم تا موجودی اعتبار را هر پنج ثانیه به میزان 50 دلار افزایش دهم در حالی که سرویس در حال اجرا است. هنگامی که موجودی به سقف اعتباری 10000 دلار رسید (یا از آن فراتر رفت، موجودی را به 2500 دلار بازنشانی کردم و پرداخت موجودی را شبیه سازی کردم.

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();

کامل index.ts فایل را می توانید در اینجا پیدا کنید.

به هروکو مستقر شوید

با آماده بودن سرویس، زمان آن فرا رسیده است که سرویس را مستقر کنیم تا بتوانیم با آن تعامل داشته باشیم. از آنجایی که Heroku دفعه قبل عالی عمل کرد (و استفاده از آن برای من آسان است)، بیایید به این رویکرد بمانیم.

برای شروع، من باید دستورات Heroku CLI زیر را اجرا کنم:

$ 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

این دستور همچنین به طور خودکار مخزن مورد استفاده توسط Heroku را به عنوان یک کنترل از راه دور اضافه می کند:

$ git remote
heroku
origin

همانطور که در مقاله قبلی خود اشاره کردم، آپولو سرور آپولو اکسپلورر را در محیط های تولید غیرفعال می کند. برای اینکه آپولو اکسپلورر را برای نیازهایمان در دسترس نگه دارم، باید آن را تنظیم کنم NODE_ENV متغیر محیطی برای توسعه من آن را با دستور CLI زیر تنظیم کردم:

$ heroku config:set NODE_ENV=development

Setting NODE_ENV and restarting ⬢ jvc-graphql-server-sub… done, v3
NODE_ENV: development

من آماده بودم تا کد خود را در Heroku مستقر کنم:

$ git commit –allow-empty -m ‘Deploy to Heroku’
$ git push heroku

یک نمای سریع از داشبورد Heroku نشان داد که سرور آپولو من بدون هیچ مشکلی در حال اجرا است:

در بخش تنظیمات، URL برنامه Heroku را برای این نمونه سرویس پیدا کردم:

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

لطفاً توجه داشته باشید – این پیوند تا زمان انتشار این مقاله دیگر در خدمت نخواهد بود.

فعلاً می‌توانم graphql را به این URL اضافه کنم تا Apollo Server Studio را راه‌اندازی کنم. این به من اجازه می دهد تا ببینم اشتراک ها همانطور که انتظار می رود کار می کنند:

به پاسخ های اشتراک در اندازه سمت راست صفحه توجه کنید.

ارتقاء سطح با WebSocket Skillz

ما می‌توانیم از پشتیبانی WebSocket و قابلیت‌های Heroku برای ایجاد پیاده‌سازی استفاده کنیم که اشتراکی را که ایجاد کرده‌ایم مصرف کند.

در مورد من، من یک فایل index.js با محتویات زیر ایجاد کردم. اساسا، این یک سرویس گیرنده WebSocket ایجاد کرد و همچنین یک سرویس HTTP ساختگی ایجاد کرد که می توانستم برای تأیید اعتبار کلاینت در حال اجرا استفاده کنم:

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’),
}
);

کامل index.js فایل را می توانید در اینجا پیدا کنید.

ما می‌توانیم این برنامه ساده Node.js را در Heroku نیز مستقر کنیم و مطمئن شویم که آن را تنظیم کرده‌ایم GRAPHQL_SUBSCRIPTION_HOST متغیر محیطی به URL برنامه Heroku که قبلا استفاده کردیم.

موارد زیر را نیز ایجاد کردم Procfile برای اینکه به Heroku بگویم چگونه برنامه من را راه اندازی کند:

web: node src/index.js

بعد من یک برنامه جدید Heroku ایجاد کردم:

$ 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

سپس، من را تنظیم کردم GRAPHQL_SUBSCRIPTION_HOST متغیر محیطی برای اشاره به سرور GraphQL در حال اجرا من:

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

در این مرحله، ما آماده هستیم تا کد خود را در Heroku مستقر کنیم:

$ git commit –allow-empty -m ‘Deploy to Heroku’
$ git push heroku

هنگامی که سرویس گیرنده WebSocket شروع به کار کرد، می توانیم وضعیت آن را در داشبورد Heroku مشاهده کنیم:

با مشاهده سیاهههای مربوط به داشبورد Heroku برای jvc-websocket-example به عنوان مثال، ما می توانیم به روز رسانی های متعدد را مشاهده کنیم balance دارایی از jvc-graphql-server-sub خدمات در نسخه ی نمایشی خود، من حتی توانستم مورد استفاده را ضبط کنم که در آن موجودی به صفر رسیده است، و شبیه سازی پرداخت انجام شده است:

در ترمینال، می‌توانیم با دستور CLI، به همان لاگ‌ها دسترسی پیدا کنیم.

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]: }

ما نه تنها یک سرویس GraphQL با اجرای اشتراک داریم، بلکه اکنون یک سرویس گیرنده WebSocket داریم که این به روز رسانی ها را مصرف می کند.

نتیجه گیری

خوانندگان من ممکن است بیانیه ماموریت شخصی من را به یاد بیاورند، که من احساس می کنم می تواند برای هر متخصص فناوری اطلاعات اعمال شود:

«زمان خود را روی ارائه ویژگی‌ها/عملکردهایی متمرکز کنید که ارزش مالکیت معنوی شما را افزایش می‌دهد. از چارچوب ها، محصولات و خدمات برای هر چیز دیگری استفاده کنید.”

– جی. وستر

در این بررسی عمیق در اشتراک‌های GraphQL، ما با استفاده از سرویس دیگری که بر روی Heroku اجرا می‌شود – یک برنامه مبتنی بر Node.js که از WebSockets استفاده می‌کند، به‌روزرسانی‌های سرور آپولو را که روی Heroku اجرا می‌شود، با موفقیت مصرف کردیم. با استفاده از اشتراک‌های سبک وزن، از ارسال درخواست برای داده‌های بدون تغییر اجتناب کردیم، اما صرفاً مشترک شدیم تا به‌روزرسانی‌های موجودی اعتبار را در صورت وقوع دریافت کنیم.

در مقدمه، به دنبال یک اصل ارزش اضافی در موضوعی که قبلاً در مورد آن نوشته‌ام، اشاره کردم. اشتراک‌های GraphQL نمونه‌ای عالی از چیزی است که من در ذهن داشتم، زیرا به مصرف‌کنندگان اجازه می‌دهد فوراً به‌روزرسانی‌ها را دریافت کنند، بدون اینکه نیازی به پرس و جو در مورد داده‌های منبع داشته باشند. این باعث می‌شود مصرف‌کنندگان داده‌های Customer 360 بسیار هیجان‌زده شوند، زیرا می‌دانند که می‌توانند به‌روزرسانی‌های زنده را در همان زمان انجام دهند.

Heroku نمونه دیگری است که با ارائه پلتفرمی که به من امکان می‌دهد با استفاده از یک CLI و دستورات استاندارد Git به سرعت راه‌حل‌ها را نمونه‌سازی کنم، به بیانیه ماموریت من پایبند است. این نه تنها به من یک راه آسان برای نمایش موارد استفاده از اشتراک‌هایم می‌دهد، بلکه برای پیاده‌سازی یک مصرف‌کننده با استفاده از WebSockets نیز.

اگر به کد منبع این مقاله علاقه مند هستید، مخازن من در GitLab را بررسی کنید:

اشتراک graphql-server-customer
websocket-example

وقتی می گویم با این تلاش مهارت های GraphQL خود را با موفقیت ارتقا داده ام، احساس اطمینان می کنم. این سفر برای من جدید و چالش برانگیز بود … و همچنین بسیار سرگرم کننده!

من قصد دارم در مرحله بعدی به احراز هویت بپردازم، که امیدوارم فرصت دیگری برای ارتقاء سطح با GraphQL و Apollo Server فراهم کند. با ما همراه باشید!

یک روز واقعا عالی داشته باشید!

تصویر مقاله

چند سالی است که سعی کرده‌ام چارچوب‌ها، محصولات و خدماتی را شناسایی کنم که به فن‌آوران اجازه می‌دهد تمرکز خود را بر گسترش ارزش مالکیت معنوی خود حفظ کنند. این همچنان یک سفر فوق العاده برای من است، پر از فرصت های یادگیری منحصر به فرد.

مهندس درون من اخیراً به این فکر کرد که آیا موقعیتی وجود دارد که بتوانم یک مزیت ثانویه برای یک مفهوم موجود پیدا کنم که قبلاً در مورد آن صحبت کرده ام. به عبارت دیگر، آیا می‌توانم مزیت دیگری را با همان سطح تأثیر راه‌حل اصلی که قبلاً شناسایی شده بود شناسایی کنم؟

برای این مقاله، می‌خواستم عمیق‌تر به GraphQL بپردازم تا ببینم چه چیزی می‌توانم پیدا کنم.

در مقاله خود با عنوان «وقتی زمان استراحت است»، در مورد اینکه چگونه سناریوهای دنیای واقعی وجود دارد که GraphQL به یک سرویس RESTful ارجحیت دارد، صحبت کردم. نحوه ساخت و استقرار API GraphQL با استفاده از سرور آپولو را بررسی کردیم.

در این پست بعدی، من قصد دارم دانش خود را در مورد GraphQL با قدم زدن در اشتراک‌ها برای بازیابی اطلاعات در زمان واقعی ارتقا دهم. ما همچنین یک سرویس WebSocket برای مصرف اشتراک ها ایجاد خواهیم کرد.

خلاصه: Customer 360 Use Case

مقاله قبلی من حول یک مورد استفاده از Customer 360 متمرکز بود که در آن مشتریان کسب و کار خیالی من مجموعه داده های زیر را نگهداری می کنند:

  • اطلاعات مشتری

  • اطلاعات آدرس

  • روش های تماس

  • ویژگی های اعتباری

یک پیروزی بزرگ در استفاده از GraphQL این است که یک درخواست GraphQL می تواند تمام داده های لازم برای توکن مشتری (هویت منحصر به فرد) را بازیابی کند.

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
}

استفاده از یک رویکرد RESTful برای بازیابی نمای واحد (360) مشتری نیاز به چندین درخواست و پاسخ دارد. GraphQL راه حلی به ما می دهد که عملکرد بسیار بهتری دارد.

اهداف سطح بالا

برای ارتقاء سطح در هر جنبه ای از زندگی، فرد باید به اهداف جدیدی دست یابد. برای اهداف خودم در اینجا، این به این معنی است:

  • درک و پیاده سازی ارزش پیشنهادی اشتراک ها در GraphQL.

  • استفاده از پیاده سازی WebSocket برای مصرف اشتراک GraphQL.

ایده استفاده از اشتراک‌ها بر روی کوئری‌ها و جهش‌ها در GraphQL زمانی که شرایط زیر برآورده شود، روش ترجیحی است:

  • تغییرات کوچک و تدریجی در اجسام بزرگ

  • به‌روزرسانی‌های بی‌درنگ و با تأخیر کم (مانند برنامه چت)

این مهم است، زیرا پیاده‌سازی اشتراک‌ها در GraphQL بی‌اهمیت نیست. نه تنها سرور اصلی نیاز به به روز رسانی دارد، بلکه برنامه مصرف کننده نیز نیاز به طراحی مجدد دارد.

خوشبختانه، موردی که ما با نمونه مشتری 360 دنبال می کنیم، برای اشتراک ها مناسب است. همچنین، ما یک رویکرد WebSocket را برای استفاده از این اشتراک ها پیاده سازی خواهیم کرد.

مانند قبل، به استفاده از آپولو ادامه خواهم داد.

ارتقاء سطح با اعتبار اشتراک

ابتدا باید کتابخانه های لازم را برای پشتیبانی از اشتراک با سرور آپولو GraphQL خود نصب کنیم:

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

با نصب آن موارد، روی به روز رسانی آن تمرکز کردم index.ts از مخزن اصلی من برای گسترش typedefs ثابت با موارد زیر:

type Subscription {
    creditUpdated: Credit
}

من همچنین یک ثابت برای خانه جدید تاسیس کردم PubSub نمونه و یک نمونه اشتراک ایجاد کردیم که بعداً از آن استفاده خواهیم کرد:

const pubsub = new PubSub();

pubsub.publish('CREDIT_BALANCE_UPDATED', {
    creditUpdated: {
    }
});

من حل کننده های موجود را پاک کردم و یک جدید اضافه کردم Subscription برای این مورد استفاده جدید:

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']),
        }
    }
};

سپس پیکربندی سرور را بازسازی کردم و طرح اشتراک را معرفی کردم:

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`);
});

برای شبیه‌سازی به‌روزرسانی‌های مبتنی بر مشتری، روش زیر را ایجاد کردم تا موجودی اعتبار را هر پنج ثانیه به میزان 50 دلار افزایش دهم در حالی که سرویس در حال اجرا است. هنگامی که موجودی به سقف اعتباری 10000 دلار رسید (یا از آن فراتر رفت، موجودی را به 2500 دلار بازنشانی کردم و پرداخت موجودی را شبیه سازی کردم.

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();

کامل index.ts فایل را می توانید در اینجا پیدا کنید.

به هروکو مستقر شوید

با آماده بودن سرویس، زمان آن فرا رسیده است که سرویس را مستقر کنیم تا بتوانیم با آن تعامل داشته باشیم. از آنجایی که Heroku دفعه قبل عالی عمل کرد (و استفاده از آن برای من آسان است)، بیایید به این رویکرد بمانیم.

برای شروع، من باید دستورات Heroku CLI زیر را اجرا کنم:

$ 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

این دستور همچنین به طور خودکار مخزن مورد استفاده توسط Heroku را به عنوان یک کنترل از راه دور اضافه می کند:

$ git remote
heroku
origin

همانطور که در مقاله قبلی خود اشاره کردم، آپولو سرور آپولو اکسپلورر را در محیط های تولید غیرفعال می کند. برای اینکه آپولو اکسپلورر را برای نیازهایمان در دسترس نگه دارم، باید آن را تنظیم کنم NODE_ENV متغیر محیطی برای توسعه من آن را با دستور CLI زیر تنظیم کردم:

$ heroku config:set NODE_ENV=development

Setting NODE_ENV and restarting ⬢ jvc-graphql-server-sub... done, v3
NODE_ENV: development

من آماده بودم تا کد خود را در Heroku مستقر کنم:

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

یک نمای سریع از داشبورد Heroku نشان داد که سرور آپولو من بدون هیچ مشکلی در حال اجرا است:

تصویر 1

در بخش تنظیمات، URL برنامه Heroku را برای این نمونه سرویس پیدا کردم:

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

لطفاً توجه داشته باشید – این پیوند تا زمان انتشار این مقاله دیگر در خدمت نخواهد بود.

فعلاً می‌توانم graphql را به این URL اضافه کنم تا Apollo Server Studio را راه‌اندازی کنم. این به من اجازه می دهد تا ببینم اشتراک ها همانطور که انتظار می رود کار می کنند:

تصویر 2

به پاسخ های اشتراک در اندازه سمت راست صفحه توجه کنید.

ارتقاء سطح با WebSocket Skillz

ما می‌توانیم از پشتیبانی WebSocket و قابلیت‌های Heroku برای ایجاد پیاده‌سازی استفاده کنیم که اشتراکی را که ایجاد کرده‌ایم مصرف کند.

در مورد من، من یک فایل index.js با محتویات زیر ایجاد کردم. اساسا، این یک سرویس گیرنده WebSocket ایجاد کرد و همچنین یک سرویس HTTP ساختگی ایجاد کرد که می توانستم برای تأیید اعتبار کلاینت در حال اجرا استفاده کنم:

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'),
  }
);

کامل index.js فایل را می توانید در اینجا پیدا کنید.

ما می‌توانیم این برنامه ساده Node.js را در Heroku نیز مستقر کنیم و مطمئن شویم که آن را تنظیم کرده‌ایم GRAPHQL_SUBSCRIPTION_HOST متغیر محیطی به URL برنامه Heroku که قبلا استفاده کردیم.

موارد زیر را نیز ایجاد کردم Procfile برای اینکه به Heroku بگویم چگونه برنامه من را راه اندازی کند:

web: node src/index.js

بعد من یک برنامه جدید Heroku ایجاد کردم:

$ 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

سپس، من را تنظیم کردم GRAPHQL_SUBSCRIPTION_HOST متغیر محیطی برای اشاره به سرور GraphQL در حال اجرا من:

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

در این مرحله، ما آماده هستیم تا کد خود را در Heroku مستقر کنیم:

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

هنگامی که سرویس گیرنده WebSocket شروع به کار کرد، می توانیم وضعیت آن را در داشبورد Heroku مشاهده کنیم:

تصویر 3

با مشاهده سیاهههای مربوط به داشبورد Heroku برای jvc-websocket-example به عنوان مثال، ما می توانیم به روز رسانی های متعدد را مشاهده کنیم balance دارایی از jvc-graphql-server-sub خدمات در نسخه ی نمایشی خود، من حتی توانستم مورد استفاده را ضبط کنم که در آن موجودی به صفر رسیده است، و شبیه سازی پرداخت انجام شده است:

تصویر 4

در ترمینال، می‌توانیم با دستور CLI، به همان لاگ‌ها دسترسی پیدا کنیم.

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]: }

ما نه تنها یک سرویس GraphQL با اجرای اشتراک داریم، بلکه اکنون یک سرویس گیرنده WebSocket داریم که این به روز رسانی ها را مصرف می کند.

نتیجه گیری

خوانندگان من ممکن است بیانیه ماموریت شخصی من را به یاد بیاورند، که من احساس می کنم می تواند برای هر متخصص فناوری اطلاعات اعمال شود:

«زمان خود را روی ارائه ویژگی‌ها/عملکردهایی متمرکز کنید که ارزش مالکیت معنوی شما را افزایش می‌دهد. از چارچوب ها، محصولات و خدمات برای هر چیز دیگری استفاده کنید.”

– جی. وستر

در این بررسی عمیق در اشتراک‌های GraphQL، ما با استفاده از سرویس دیگری که بر روی Heroku اجرا می‌شود – یک برنامه مبتنی بر Node.js که از WebSockets استفاده می‌کند، به‌روزرسانی‌های سرور آپولو را که روی Heroku اجرا می‌شود، با موفقیت مصرف کردیم. با استفاده از اشتراک‌های سبک وزن، از ارسال درخواست برای داده‌های بدون تغییر اجتناب کردیم، اما صرفاً مشترک شدیم تا به‌روزرسانی‌های موجودی اعتبار را در صورت وقوع دریافت کنیم.

در مقدمه، به دنبال یک اصل ارزش اضافی در موضوعی که قبلاً در مورد آن نوشته‌ام، اشاره کردم. اشتراک‌های GraphQL نمونه‌ای عالی از چیزی است که من در ذهن داشتم، زیرا به مصرف‌کنندگان اجازه می‌دهد فوراً به‌روزرسانی‌ها را دریافت کنند، بدون اینکه نیازی به پرس و جو در مورد داده‌های منبع داشته باشند. این باعث می‌شود مصرف‌کنندگان داده‌های Customer 360 بسیار هیجان‌زده شوند، زیرا می‌دانند که می‌توانند به‌روزرسانی‌های زنده را در همان زمان انجام دهند.

Heroku نمونه دیگری است که با ارائه پلتفرمی که به من امکان می‌دهد با استفاده از یک CLI و دستورات استاندارد Git به سرعت راه‌حل‌ها را نمونه‌سازی کنم، به بیانیه ماموریت من پایبند است. این نه تنها به من یک راه آسان برای نمایش موارد استفاده از اشتراک‌هایم می‌دهد، بلکه برای پیاده‌سازی یک مصرف‌کننده با استفاده از WebSockets نیز.

اگر به کد منبع این مقاله علاقه مند هستید، مخازن من در GitLab را بررسی کنید:

  • اشتراک graphql-server-customer

  • websocket-example

وقتی می گویم با این تلاش مهارت های GraphQL خود را با موفقیت ارتقا داده ام، احساس اطمینان می کنم. این سفر برای من جدید و چالش برانگیز بود … و همچنین بسیار سرگرم کننده!

من قصد دارم در مرحله بعدی به احراز هویت بپردازم، که امیدوارم فرصت دیگری برای ارتقاء سطح با GraphQL و Apollo Server فراهم کند. با ما همراه باشید!

یک روز واقعا عالی داشته باشید!

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا