Արդեն մի քանի տարի է, ես փորձել եմ բացահայտել շրջանակներ, ապրանքներ և ծառայություններ, որոնք թույլ են տալիս տեխնոլոգներին պահպանել իրենց ուշադրությունը իրենց մտավոր սեփականության արժեքի ընդլայնման վրա: Սա ինձ համար շարունակում է մնալ հրաշալի ճանապարհորդություն՝ լի եզակի ուսուցման հնարավորություններով:
Ինժեները իմ մեջ վերջերս մտածեց, թե արդյոք կա մի իրավիճակ, որտեղ ես կարող եմ երկրորդական օգուտ գտնել գոյություն ունեցող հայեցակարգի համար, որի մասին ես նախկինում խոսել եմ: Այլ կերպ ասած, ես կարո՞ղ եմ բացահայտել մեկ այլ օգուտ նույն ազդեցության մակարդակով, ինչ նախկինում ճանաչված սկզբնական մայր լուծումը:
Այս հոդվածի համար ես ուզում էի ավելի խորանալ GraphQL-ի մեջ՝ տեսնելու, թե ինչ կարող եմ գտնել:
Իմ « Երբ հանգստանալու ժամանակն է » հոդվածում ես խոսեցի այն մասին, թե ինչպես կան իրական աշխարհի սցենարներ, երբ GraphQL-ը գերադասելի է RESTful ծառայության փոխարեն: Մենք քայլեցինք, թե ինչպես կարելի է կառուցել և տեղակայել GraphQL API՝ օգտագործելով Apollo Server:
Այս հաջորդական գրառման մեջ ես նախատեսում եմ բարձրացնել իմ գիտելիքները GraphQL-ի մասին՝ անցնելով իրական ժամանակում տվյալների որոնման բաժանորդագրությունների միջով: Մենք նաև կկառուցենք WebSocket ծառայություն՝ բաժանորդագրությունները սպառելու համար:
Իմ նախորդ հոդվածը կենտրոնացած էր Հաճախորդ 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 }
Հաճախորդի մեկ (360) տեսակետը ստանալու համար RESTful մոտեցման օգտագործումը կպահանջի մի քանի հարցումների և պատասխանների համադրում: GraphQL-ը մեզ լուծում է տալիս, որը շատ ավելի լավ է աշխատում:
Կյանքի ցանկացած բնագավառում մակարդակը բարձրանալու համար պետք է հասնել նոր նպատակների: Իմ սեփական նպատակների համար այստեղ սա նշանակում է.
GraphQL հարցումների և մուտացիաների վրա բաժանորդագրություններ օգտագործելու գաղափարը նախընտրելի մեթոդ է, երբ բավարարվում են հետևյալ պայմանները.
Սա կարևոր է, քանի որ GraphQL-ի ներսում բաժանորդագրություններ իրականացնելը մանրուք չէ: Ոչ միայն հիմքում ընկած սերվերը պետք է թարմացվի, այլև սպառող հավելվածը կպահանջի որոշակի վերանախագծում:
Բարեբախտաբար, օգտագործման դեպքը, որը մենք հետապնդում ենք մեր Հաճախորդ 360 օրինակով, հիանալի հարմար է բաժանորդագրությունների համար: Բացի այդ, մենք կիրականացնենք WebSocket մոտեցում՝ այդ բաժանորդագրությունները օգտագործելու համար:
Ինչպես նախկինում, ես կշարունակեմ օգտագործել Apollo-ն առաջ գնալով:
Նախ, մենք պետք է տեղադրենք անհրաժեշտ գրադարանները՝ իմ Apollo 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-ով ավելացնելու համար: Երբ մնացորդը հասնում է (կամ գերազանցում է) $10,000 վարկային սահմանաչափը, ես վերականգնում եմ մնացորդը մինչև $2,500՝ նմանակելով մնացորդի վճարումը:
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 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
Հրամանը նաև ավտոմատ կերպով ավելացրել է Հերոկուի կողմից որպես հեռակառավարվող պահոց.
$ git remote heroku origin
Ինչպես ես նշել եմ իմ նախորդ հոդվածում, Apollo Server-ը անջատում է Apollo Explorer-ը արտադրական միջավայրերում: Որպեսզի Apollo Explorer-ը հասանելի լինի մեր կարիքների համար, ես պետք է սահմանեի NODE_ENV
միջավայրի փոփոխականը զարգացման համար: Ես դա սահմանեցի հետևյալ CLI հրամանով.
$ heroku config:set NODE_ENV=development Setting NODE_ENV and restarting ⬢ jvc-graphql-server-sub... done, v3 NODE_ENV: development
Ես պատրաստ էի տեղակայել իմ կոդը Հերոկուում.
$ git commit --allow-empty -m 'Deploy to Heroku' $ git push heroku
Heroku Dashboard-ի արագ տեսքը ցույց տվեց, որ իմ Apollo սերվերը աշխատում է առանց որևէ խնդիրների.
Կարգավորումների բաժնում ես գտա Heroku հավելվածի URL-ը այս ծառայության օրինակի համար.
https://jvc-graphql-server-sub-1ec2e6406a82.herokuapp.com/
Խնդրում ենք նկատի ունենալ. այս հղումն այլևս չի գործի մինչև այս հոդվածը հրապարակվի:
Առայժմ ես կարող եմ GraphQL-ն ավելացնել այս URL-ին՝ Apollo Server Studio-ին գործարկելու համար: Սա թույլ կտա ինձ տեսնել, որ բաժանորդագրությունները աշխատում են այնպես, ինչպես սպասվում էր.
Ուշադրություն դարձրեք Բաժանորդագրության պատասխաններին էկրանի աջ կողմում:
Մենք կարող ենք օգտագործել 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
միջավայրի փոփոխականը սահմանել ենք Heroku հավելվածի URL-ին, որը մենք նախկինում օգտագործել ենք:
Ես նաև ստեղծեցի հետևյալ Procfile
Հերոկուին պատմելու համար, թե ինչպես գործարկել իմ հավելվածը.
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
Այս պահին մենք պատրաստ ենք մեր կոդը տեղակայել Հերոկուում՝
$ git commit --allow-empty -m 'Deploy to Heroku' $ git push heroku
WebSocket հաճախորդը սկսելուց հետո մենք կարող ենք տեսնել դրա կարգավիճակը Heroku Dashboard-ում.
Դիտելով Heroku Dashboard-ի տեղեկամատյանները jvc-websocket-example
օրինակի համար՝ մենք կարող ենք տեսնել jvc-graphql-server-sub
ծառայության balance
հատկության բազմաթիվ թարմացումները: Իմ ցուցադրությունում ես նույնիսկ կարողացա ֆիքսել օգտագործման դեպքը, երբ մնացորդը զրոյի է հասցվել՝ նմանակելով, որ վճարում է կատարվել.
Տերմինալում մենք կարող ենք մուտք գործել այդ նույն տեղեկամատյանները CLI հրամանի heroku տեղեկամատյաններով:
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-ում աշխատող Apollo սերվերի թարմացումները՝ օգտագործելով մեկ այլ ծառայություն, որը նույնպես գործում է Heroku-ի վրա՝ Node.js-ի վրա հիմնված հավելված, որն օգտագործում է WebSockets: Օգտագործելով թեթև բաժանորդագրությունները՝ մենք խուսափեցինք անփոփոխ տվյալների համար հարցումներ ուղարկելուց, այլ պարզապես բաժանորդագրվեցինք՝ ստանալու վարկային մնացորդի թարմացումները, երբ դրանք տեղի էին ունենում:
Ներածությունում ես նշեցի, որ որոնել լրացուցիչ արժեքային սկզբունք այն թեմայի ներսում, որի մասին նախկինում գրել եմ: GraphQL բաժանորդագրությունները հիանալի օրինակ են այն ամենի, ինչ ես ունեի, քանի որ այն թույլ է տալիս սպառողներին անմիջապես թարմացումներ ստանալ՝ առանց աղբյուրի տվյալների դեմ հարցումներ անելու անհրաժեշտության: Սա շատ կհուզի Հաճախորդ 360-ի տվյալների սպառողներին՝ իմանալով, որ նրանք կարող են թարմացումներ կատարել, ինչպես դրանք տեղի են ունենում:
Heroku-ն ևս մեկ օրինակ է, որը շարունակում է հավատարիմ մնալ իմ առաքելության հայտարարությանը` առաջարկելով հարթակ, որն ինձ հնարավորություն է տալիս արագորեն նախատիպել լուծումները՝ օգտագործելով CLI և ստանդարտ Git հրամանները: Սա ոչ միայն ինձ հեշտ միջոց է տալիս ցուցադրելու իմ բաժանորդագրության օգտագործման դեպքը, այլև WebSockets օգտագործող սպառողին իրականացնելու համար:
Եթե ձեզ հետաքրքրում է այս հոդվածի սկզբնական կոդը, ստուգեք իմ պահեստները GitLab-ում.
Ես վստահ եմ զգում, երբ ասում եմ, որ այս ջանքերով ես հաջողությամբ բարձրացրել եմ իմ GraphQL հմտությունները: Այս ճամփորդությունն ինձ համար նոր և դժվար էր… և նաև շատ զվարճալի:
Հաջորդիվ ես նախատեսում եմ սուզվել նույնականացման մեջ, ինչը, հուսով եմ, ևս մեկ հնարավորություն է տալիս մակարդակի բարձրանալու GraphQL-ի և Apollo Server-ի հետ: Հետևե՛ք:
Ունեցեք իսկապես հիանալի օր: