1"use strict";(globalThis.webpackChunkwebsite=globalThis.webpackChunkwebsite||[]).push([[1829],{1221(e,t,n){n.r(t),n.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>a,metadata:()=>s,toc:()=>u});const s=JSON.parse('{"id":"subscriptions","title":"Subscriptions","description":"Graphql subscriptions allow you subscribe to a reactive source and as new data arrives a graphql query is applied over that data and the results are passed on.","source":"@site/versioned_docs/version-v25/subscriptions.md","sourceDirName":".","slug":"/subscriptions","permalink":"/documentation/subscriptions","draft":false,"unlisted":false,"editUrl":"https://github.com/graphql-java/graphql-java-page/edit/master/versioned_docs/version-v25/subscriptions.md","tags":[],"version":"v25","frontMatter":{"title":"Subscriptions","date":"2018-09-09T02:52:46.000Z","description":"Graphql subscriptions allow you subscribe to a reactive source and as new data arrives a graphql query is applied over that data and the results are passed on."},"sidebar":"tutorialSidebar","previous":{"title":"Schema","permalink":"/documentation/schema"},"next":{"title":"Upgrade notes","permalink":"/documentation/upgrade-notes"}}');var r=n(4848),i=n(8453);const a={title:"Subscriptions",date:new Date("2018-09-09T02:52:46.000Z"),description:"Graphql subscriptions allow you subscribe to a reactive source and as new data arrives a graphql query is applied over that data and the results are passed on."},o="Subscriptions",c={},u=[{value:"Subscription Queries",id:"subscription-queries",level:2},{value:"Subscription Data Fetchers",id:"subscription-data-fetchers",level:2}];function l(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",p:"p",pre:"pre",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(t.header,{children:(0,r.jsx)(t.h1,{id:"subscriptions",children:"Subscriptions"})}),"\n",(0,r.jsx)(t.h2,{id:"subscription-queries",children:"Subscription Queries"}),"\n",(0,r.jsx)(t.p,{children:"Graphql subscriptions allow you subscribe to a reactive source and as new data arrives\na graphql query is applied over that data and the results are passed on."}),"\n",(0,r.jsxs)(t.p,{children:["See ",(0,r.jsx)(t.a,{href:"http://graphql.org/blog/subscriptions-in-graphql-and-relay/",children:"http://graphql.org/blog/subscriptions-in-graphql-and-relay/"})," for more general details on\ngraphql subscriptions."]}),"\n",(0,r.jsx)(t.p,{children:"Imagine you have an stock market pricing service and you make a graphql subscription to it like this"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-graphql",children:'subscription StockCodeSubscription {\n stockQuotes(stockCode:"IBM") {\n dateTime\n stockCode\n stockPrice\n stockPriceChange\n }\n}\n'})}),"\n",(0,r.jsxs)(t.p,{children:["graphql subscriptions allow a stream of ",(0,r.jsx)(t.code,{children:"ExecutionResult"})," objects to be sent down each time the stock price\nchanges. The field selection set will applied to the underlying data and are represented just like any other\ngraphql query."]}),"\n",(0,r.jsxs)(t.p,{children:["What is special is that the initial result of a subscription query is a reactive-streams ",(0,r.jsx)(t.code,{children:"Publisher"})," object which you\nneed to use to get the future values."]}),"\n",(0,r.jsxs)(t.p,{children:["You need to use ",(0,r.jsx)(t.code,{children:"SubscriptionExecutionStrategy"})," as your execution strategy as it has the support for the reactive-streams APIs."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-java",children:"GraphQL graphQL = GraphQL\n .newGraphQL(schema)\n .subscriptionExecutionStrategy(new SubscriptionExecutionStrategy())\n .build();\n\nExecutionResult executionResult = graphQL.execute(query);\n\nPublisher<ExecutionResult> stockPriceStream = executionResult.getData();\n"})}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.code,{children:"Publisher<ExecutionResult>"})," here is the publisher of a stream of events. You need to subscribe to this with your processing\ncode which will look something like the following"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-java",children:'GraphQL graphQL = GraphQL\n .newGraphQL(schema)\n .subscriptionExecutionStrategy(new SubscriptionExecutionStrategy())\n .build();\n\nString query = "" +\n " subscription StockCodeSubscription {\\n" +\n " stockQuotes(stockCode:\\"IBM\\") {\\n" +\n " dateTime\\n" +\n " stockCode\\n" +\n " stockPrice\\n" +\n " stockPriceChange\\n" +\n " }\\n" +\n " }\\n";\n\nExecutionResult executionResult = graphQL.execute(query);\n\nPublisher<ExecutionResult> stockPriceStream = executionResult.getData();
1\n\nAtomicReference<Subscription> subscriptionRef = new AtomicReference<>();\nstockPriceStream.subscribe(new Subscriber<ExecutionResult>() {\n\n @Override\n public void onSubscribe(Subscription s) {\n subscriptionRef.set(s);\n s.request(1);\n }\n\n @Override\n public void onNext(ExecutionResult er) {\n //\n // process the next stock price\n //\n processStockPriceChange(er.getData());\n\n //\n // ask the publisher for one more item please\n //\n subscriptionRef.get().request(1);\n }\n\n @Override\n public void onError(Throwable t) {\n //\n // The upstream publishing data source has encountered an error\n // and the subscription is now terminated. Real production code needs\n // to decide on a error handling strategy.\n //\n }\n\n @Override\n public void onComplete() {\n //\n // the subscription has completed. There is not more data\n //\n }\n});\n'})}),"\n",(0,r.jsxs)(t.p,{children:["You are now writing reactive-streams code to consume a series of ",(0,r.jsx)(t.code,{children:"ExecutionResults"}),". You can see\nmore details on reactive-streams code here ",(0,r.jsx)(t.a,{href:"http://www.reactive-streams.org/",children:"http://www.reactive-streams.org/"})]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"RxJava"})," is a popular implementation of reactive-streams. Check out ",(0,r.jsx)(t.a,{href:"http://reactivex.io/intro.html",children:"http://reactivex.io/intro.html"})," to find out more\nabout creating Publishers of data and Subscriptions to that data."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"Project Reactor"})," is another popular implementation of reactive-streams. Check out ",(0,r.jsx)(t.a,{href:"https://projectreactor.io/",children:"https://projectreactor.io/"})," as well."]}),"\n",(0,r.jsx)(t.p,{children:"graphql-java only produces a stream of results. It does not concern itself with sending these over the network on things\nlike web sockets and so on. That is important but not a concern of the base graphql-java library."}),"\n",(0,r.jsx)(t.p,{children:"We have put together a basic example of using websockets (backed by Jetty) with a simulated stock price application that\nis built using RxJava."}),"\n",(0,r.jsxs)(t.p,{children:["See ",(0,r.jsx)(t.a,{href:"https://github.com/graphql-java/graphql-java-subscription-example",children:"https://github.com/graphql-java/graphql-java-subscription-example"})," for more detailed code on handling network concerns and\nthe like."]}),"\n",(0,r.jsx)(t.h2,{id:"subscription-data-fetchers",children:"Subscription Data Fetchers"}),"\n",(0,r.jsxs)(t.p,{children:["The ",(0,r.jsx)(t.code,{children:"DataFetcher"})," behind a subscription field is responsible for creating the ",(0,r.jsx)(t.code,{children:"Publisher"})," of data. The objects\nreturn by this Publisher will be mapped over the graphql query as each arrives and then sent back out as an execution result."]}),"\n",(0,r.jsx)(t.p,{children:"You data fetcher is going to look something like this."}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-java",children:'DataFetcher<Publisher<StockInfo>> publisherDataFetcher = new DataFetcher<Publisher<StockInfo>>() {\n @Override\n public Publisher<StockInfo> get(DataFetchingEnvironment environment) {\n String stockCodeArg = environment.getArgument("stockCode");\n return buildPublisherForStockCode(stockCodeArg);\n }\n};\n'})}),"\n",(0,r.jsx)(t.p,{children:"Now the exact details of how you get that stream of events is up to you and you're reactive code. graphql-java\ngives you a way to map the graphql query fields over that stream of objects just like a standard graphql query."})]})}function h(e={}){const{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(l,{...e})}):l(e)}},8453(e,t,n){n.d(t,{R:()=>a,x:()=>o});var s=n(6540);const r={},i=s.createContext(r);function a(e){const t=s.useContext(i);return s.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:a(e.components),s.createElement(i.Provider,{value:t},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.