Već nekoliko godina pokušavam identificirati okvire, proizvode i usluge koji omogućavaju tehnolozima da zadrže fokus na proširenju vrijednosti svog intelektualnog vlasništva. Ovo je i dalje divno putovanje za mene, ispunjeno jedinstvenim prilikama za učenje.
Inženjer u meni se nedavno zapitao postoji li situacija u kojoj bih mogao pronaći sekundarnu korist za postojeći koncept o kojem sam ranije govorio. Drugim riječima, mogu li identificirati još jednu korist sa istim nivoom utjecaja kao što je prethodno prepoznato originalno roditeljsko rješenje?
Za ovaj članak, htio sam dublje zaroniti u GraphQL da vidim šta mogu pronaći.
U svom članku „ Kada je vrijeme da se odmori REST “ govorio sam o tome kako postoje scenariji u stvarnom svijetu kada je GraphQL poželjniji od RESTful usluge. Prošetali smo kroz kako da izgradimo i primenimo GraphQL API koristeći Apollo Server.
U ovom naknadnom postu planiram da poboljšam svoje znanje o GraphQL-u tako što ću proći kroz pretplate za preuzimanje podataka u realnom vremenu. Također ćemo izgraditi WebSocket servis za korištenje pretplata.
Moj prethodni članak se fokusirao na slučaj upotrebe Customer 360, gdje pokrovitelji mog izmišljenog poslovanja održavaju sljedeće zbirke podataka:
Velika pobjeda u korištenju GraphQL-a je to što jedan zahtjev za GraphQL može dohvatiti sve potrebne podatke za token korisnika (jedinstveni identitet).
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 }
Korištenje RESTful pristupa za dohvaćanje jednog (360) pogleda korisnika zahtijevalo bi spajanje više zahtjeva i odgovora. GraphQL nam daje rješenje koje radi mnogo bolje.
Da bi se napredovao u bilo kom aspektu života, potrebno je postići nove ciljeve. Za moje ciljeve ovdje, ovo znači:
Ideja korištenja pretplata preko upita i mutacija unutar GraphQL-a je poželjna metoda kada su ispunjeni sljedeći uvjeti:
Ovo je važno jer implementacija pretplata unutar GraphQL-a nije trivijalna. Ne samo da će osnovni server morati da se ažurira, već će i aplikacija koja troši zahtev zahtevati redizajn.
Srećom, slučaj upotrebe koji pratimo s našim primjerom Customer 360 je odličan za pretplate. Također, implementiraćemo WebSocket pristup za iskorištavanje tih pretplata.
Kao i prije, nastavit ću koristiti Apollo i dalje.
Prvo, moramo instalirati potrebne biblioteke za podršku pretplata na moj Apollo GraphQL server:
npm install ws npm install graphql-ws @graphql-tools/schema npm install graphql-subscriptions
Sa instaliranim stavkama, fokusirao sam se na ažuriranje index.ts
iz svog originalnog spremišta kako bih proširio typedefs
konstantu sa sljedećim:
type Subscription { creditUpdated: Credit }
Također sam uspostavio konstantu za smještaj nove PubSub
instance i napravio uzorak pretplate koju ćemo kasnije koristiti:
const pubsub = new PubSub(); pubsub.publish('CREDIT_BALANCE_UPDATED', { creditUpdated: { } });
Očistio sam postojeće rezolvere i dodao novu Subscription
za ovaj novi slučaj upotrebe:
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']), } } };
Zatim sam refaktorirao konfiguraciju servera i predstavio dizajn pretplate:
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`); });
Da bih simulirao ažuriranja koja su vođena klijentima, kreirao sam sljedeću metodu za povećanje kreditnog stanja za 50 USD svakih pet sekundi dok je usluga pokrenuta. Kada stanje dostigne (ili premaši) kreditno ograničenje od 10.000 USD, vraćam stanje na 2.500 USD, simulirajući plaćanje salda.
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();
Cijeli index.ts
fajl možete pronaći ovdje .
Pošto je usluga spremna, vrijeme je da implementiramo uslugu kako bismo mogli komunicirati s njom. Budući da je Heroku prošli put odlično funkcionirao (a meni ga je lako koristiti), ostanimo pri tom pristupu.
Za početak, trebao sam pokrenuti sljedeće Heroku CLI komande:
$ 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
Komanda je također automatski dodala spremište koje Heroku koristi kao daljinski:
$ git remote heroku origin
Kao što sam napomenuo u svom prethodnom članku, Apollo Server onemogućuje Apollo Explorer u proizvodnim okruženjima. Da bi Apollo Explorer bio dostupan za naše potrebe, morao sam postaviti varijablu okruženja NODE_ENV
na razvoj. Postavio sam to sa sljedećom CLI naredbom:
$ heroku config:set NODE_ENV=development Setting NODE_ENV and restarting ⬢ jvc-graphql-server-sub... done, v3 NODE_ENV: development
Bio sam spreman da postavim svoj kod na Heroku:
$ git commit --allow-empty -m 'Deploy to Heroku' $ git push heroku
Brzi pregled Heroku kontrolne table pokazao je da moj Apollo server radi bez ikakvih problema:
U odjeljku Postavke pronašao sam URL aplikacije Heroku za ovu instancu usluge:
https://jvc-graphql-server-sub-1ec2e6406a82.herokuapp.com/
Imajte na umu – ovaj link više neće biti u upotrebi do trenutka objavljivanja ovog članka.
Za sada bih mogao dodati GraphQL ovom URL-u da pokrenem Apollo Server Studio. Ovo mi omogućava da vidim kako pretplate rade prema očekivanjima:
Obratite pažnju na odgovore pretplate na desnoj strani ekrana.
Možemo iskoristiti podršku za WebSocket i Heroku-ove mogućnosti da kreiramo implementaciju koja koristi pretplatu koju smo kreirali.
U mom slučaju, kreirao sam index.js fajl sa sledećim sadržajem. U osnovi, ovo je kreiralo WebSocket klijenta i također uspostavilo lažnu HTTP uslugu koju sam mogao koristiti za provjeru da li klijent radi:
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'), } );
Cijeli index.js
fajl možete pronaći ovdje .
Ovu jednostavnu Node.js aplikaciju možemo primijeniti i na Heroku, pazeći da postavite varijablu okruženja GRAPHQL_SUBSCRIPTION_HOST
na URL Heroku aplikacije koji smo ranije koristili.
Također sam kreirao sljedeći Procfile
da kažem Herokuu kako da pokrene moju aplikaciju:
web: node src/index.js
Zatim sam kreirao novu Heroku aplikaciju:
$ 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
Zatim sam postavio varijablu okruženja GRAPHQL_SUBSCRIPTION_HOST
da ukazuje na moj pokrenut GraphQL server:
$ heroku --app jvc-websocket-example \ config:set \ GRAPHQL_SUBSCRIPTION_HOST=ws://jvc-graphql-server-sub-1ec2e6406a82.herokuapp.com/graphql
U ovom trenutku, spremni smo za implementaciju našeg koda na Heroku:
$ git commit --allow-empty -m 'Deploy to Heroku' $ git push heroku
Kada se WebSocket klijent pokrene, možemo vidjeti njegov status na Heroku kontrolnoj tabli:
Pregledom evidencije unutar Heroku Dashboard-a za jvc-websocket-example
instancu, možemo vidjeti višestruka ažuriranja svojstva balance
usluge jvc-graphql-server-sub
. U mom demo-u, čak sam uspio uhvatiti slučaj upotrebe u kojem je stanje smanjeno na nulu, simulirajući da je izvršeno plaćanje:
U terminalu možemo pristupiti tim istim evidencijama pomoću CLI naredbe 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]: }
Ne samo da imamo GraphQL uslugu sa implementacijom pretplate koja je pokrenuta, već sada imamo i WebSocket klijent koji koristi ta ažuriranja.
Moji čitaoci se mogu sjetiti moje lične izjave o misiji, za koju smatram da se može primijeniti na bilo kojeg IT profesionalca:
„Usredsredite svoje vreme na isporuku karakteristika/funkcionalnosti koje proširuju vrednost vašeg intelektualnog vlasništva. Iskoristite okvire, proizvode i usluge za sve ostalo.” — J. Vester
U ovom dubokom zaronu u GraphQL pretplate, uspješno smo iskoristili ažuriranja sa Apollo servera koji radi na Heroku-u koristeći drugu uslugu koja je također pokrenuta na Heroku-u – aplikaciju zasnovanu na Node.js koja koristi WebSockets. Koristeći lagane pretplate, izbjegli smo slanje upita za nepromjenjive podatke, već smo se jednostavno pretplatili na primanje ažuriranja stanja kredita čim se dogode.
U uvodu sam spomenuo traženje principa dodatne vrijednosti unutar teme o kojoj sam ranije pisao. GraphQL pretplate su odličan primjer onoga što sam imao na umu jer omogućava potrošačima da primaju ažuriranja odmah, bez potrebe da postavljaju upite prema izvornim podacima. Ovo će potrošače podataka Customer 360 učiniti veoma uzbuđenim, znajući da mogu uživo ažurirati kako se dogode.
Heroku je još jedan primjer koji nastavlja da se pridržava moje izjave o misiji nudeći platformu koja mi omogućava da brzo prototipiram rješenja koristeći CLI i standardne Git komande. Ovo ne samo da mi daje jednostavan način da prikažem slučaj upotrebe moje pretplate, već i da implementiram korisnika koristeći WebSockets.
Ako ste zainteresovani za izvorni kod za ovaj članak, pogledajte moja spremišta na GitLabu:
Osjećam se samouvjereno kada kažem da sam ovim naporom uspješno poboljšao svoje GraphQL vještine. Ovo putovanje je bilo novo i izazovno za mene… i isto tako zabavno!
Sledeće planiram da zaronim u autentifikaciju, koja će, nadam se, pružiti još jednu priliku da se podignem na nivo sa GraphQL i Apollo serverom. Stay tuned!
Želim vam zaista divan dan!