├── .npmignore ├── .gitattributes ├── examples ├── README.md ├── pr │ └── 196 │ │ ├── client │ │ ├── src │ │ │ ├── App.re │ │ │ ├── Index.re │ │ │ ├── index.html │ │ │ ├── Client.re │ │ │ ├── Wallets.re │ │ │ └── Settings.re │ │ ├── .gitignore │ │ ├── build │ │ │ └── index.html │ │ ├── bsconfig.json │ │ ├── webpack.config.js │ │ ├── package.json │ │ ├── README.md │ │ └── graphql_schema.json │ │ └── server │ │ ├── package.json │ │ └── index.js ├── swapi │ ├── .gitignore │ ├── src │ │ ├── index.re │ │ ├── Page.re │ │ ├── ShowLivePersons.re │ │ ├── PersonById.re │ │ ├── PersonByIdDelete.re │ │ ├── SubscribeToPersons.re │ │ ├── GetPersonById.re │ │ ├── AddPerson.re │ │ ├── GetPerson.re │ │ ├── Persons.re │ │ ├── Client.re │ │ ├── DeletePerson.re │ │ ├── DeletePersonButton.re │ │ └── PersonSubscribeToMore.re │ ├── index.html │ ├── webpack.config.js │ ├── README.md │ ├── bsconfig.json │ └── package.json └── realtime-chat-application │ ├── src │ ├── Theme.re │ ├── index.re │ ├── Handler.re │ ├── Messages.re │ ├── App.re │ ├── Header.re │ ├── ChatBubble.re │ ├── index.html │ ├── NewMessageNotification.re │ ├── ReasonApolloClient.re │ ├── AddMessage.re │ └── MessagesContainer.re │ ├── public │ ├── favicon.ico │ ├── notification.mp3 │ ├── notification.ogg │ ├── manifest.json │ └── index.html │ ├── webpack.config.js │ ├── bsconfig.json │ ├── .gitignore │ ├── package.json │ ├── README.md │ └── graphql_schema.json ├── .travis.yml ├── src ├── ApolloProvider.re ├── ApolloUtilities.re ├── ReasonApolloUtils.re ├── ApolloConsumer.re ├── graphql-types │ ├── ReasonApolloSubscription.rei │ ├── ReasonApolloSubscription.re │ ├── ReasonApolloMutation.rei │ ├── ReasonApolloQuery.rei │ ├── ReasonApolloMutation.re │ └── ReasonApolloQuery.re ├── ReasonApollo.re ├── ApolloInMemoryCache.re ├── ReasonApolloTypes.re ├── ApolloLinks.re └── ApolloClient.re ├── .github ├── PULL_REQUEST_TEMPLATE.md └── ISSUE_TEMPLATE.md ├── .gitignore ├── bsconfig.json ├── LICENSE ├── package.json ├── CONTRIBUTING.md └── README.md /.npmignore: -------------------------------------------------------------------------------- 1 | examples -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.re linguist-language=Reason 2 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | This folder contains working examples of usage of the library. -------------------------------------------------------------------------------- /examples/pr/196/client/src/App.re: -------------------------------------------------------------------------------- 1 | [@react.component] 2 | let make = () =>
; 3 | -------------------------------------------------------------------------------- /examples/pr/196/client/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .merlin 3 | .bsb.lock 4 | npm-debug.log 5 | /lib/bs/ 6 | /node_modules/ 7 | -------------------------------------------------------------------------------- /examples/swapi/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .merlin 3 | .bsb.lock 4 | npm-debug.log 5 | /lib/bs/ 6 | /node_modules/ 7 | build -------------------------------------------------------------------------------- /examples/realtime-chat-application/src/Theme.re: -------------------------------------------------------------------------------- 1 | open Css; 2 | 3 | let primaryColor = purple; 4 | let secondaryColor = tomato; 5 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apollographql/reason-apollo/HEAD/examples/realtime-chat-application/public/favicon.ico -------------------------------------------------------------------------------- /examples/realtime-chat-application/public/notification.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apollographql/reason-apollo/HEAD/examples/realtime-chat-application/public/notification.mp3 -------------------------------------------------------------------------------- /examples/realtime-chat-application/public/notification.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apollographql/reason-apollo/HEAD/examples/realtime-chat-application/public/notification.ogg -------------------------------------------------------------------------------- /examples/pr/196/client/src/Index.re: -------------------------------------------------------------------------------- 1 | ReactDOMRe.renderToElementWithId( 2 | 3 | 4 | , 5 | "index1", 6 | ); 7 | -------------------------------------------------------------------------------- /examples/swapi/src/index.re: -------------------------------------------------------------------------------- 1 | ReactDOMRe.renderToElementWithId( 2 | 3 | 4 | 5 | , "index"); 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - "8" 5 | cache: 6 | yarn: true 7 | directories: 8 | - node_modules 9 | install: npm install 10 | script: 11 | - npm run build -------------------------------------------------------------------------------- /examples/realtime-chat-application/src/index.re: -------------------------------------------------------------------------------- 1 | ReactDOMRe.renderToElementWithId( 2 | 3 | 4 | 5 | , "root"); 6 | -------------------------------------------------------------------------------- /src/ApolloProvider.re: -------------------------------------------------------------------------------- 1 | open ApolloClient; 2 | 3 | [@bs.module "react-apollo"] [@react.component] 4 | external make: 5 | (~client: generatedApolloClient, ~children: React.element) => React.element = 6 | "ApolloProvider"; 7 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/src/Handler.re: -------------------------------------------------------------------------------- 1 | let onChange = evt => ( 2 | evt 3 | |> ReactEventRe.Form.target 4 | |> ReactDOMRe.domElementToObj 5 | )##value; 6 | -------------------------------------------------------------------------------- /examples/swapi/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Reason Example 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/ApolloUtilities.re: -------------------------------------------------------------------------------- 1 | type operationDefinitionNode = { 2 | kind: string, 3 | operation: string, 4 | }; 5 | 6 | [@bs.module "apollo-utilities"] 7 | external getMainDefinition: 8 | ReasonApolloTypes.documentNodeT => operationDefinitionNode = 9 | "getMainDefinition"; 10 | -------------------------------------------------------------------------------- /examples/pr/196/client/build/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ReasonReact Examples 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/pr/196/client/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ReasonReact Examples 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/swapi/src/Page.re: -------------------------------------------------------------------------------- 1 | [@react.component] 2 | let make = () => 3 |
4 |

{React.string("Star Wars")}

5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
; 13 | -------------------------------------------------------------------------------- /examples/pr/196/client/src/Client.re: -------------------------------------------------------------------------------- 1 | /* Create an InMemoryCache */ 2 | let inMemoryCache = ApolloInMemoryCache.createInMemoryCache(); 3 | 4 | /* Create an HTTP Link */ 5 | let httpLink = ApolloLinks.createHttpLink(~uri="http://localhost:4000", ()); 6 | 7 | let instance = 8 | ReasonApollo.createApolloClient(~link=httpLink, ~cache=inMemoryCache, ()); 9 | -------------------------------------------------------------------------------- /examples/swapi/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const isProd = process.env.NODE_ENV === "production"; 3 | 4 | module.exports = { 5 | entry: './src/index.bs.js', 6 | mode: isProd ? "production" : "development", 7 | output: { 8 | path: path.join(__dirname, "build"), 9 | filename: 'bundle.js', 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const isProd = process.env.NODE_ENV === "production"; 3 | 4 | module.exports = { 5 | entry: './src/index.bs.js', 6 | mode: isProd ? "production" : "development", 7 | output: { 8 | path: path.join(__dirname, "build"), 9 | filename: 'bundle.js', 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /examples/pr/196/server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "start": "nodemon index.js" 8 | }, 9 | "devDependencies": { 10 | "nodemon": "^1.19.1" 11 | }, 12 | "dependencies": { 13 | "apollo-server": "^2.6.1", 14 | "graphql": "^14.3.1" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ReasonApolloUtils.re: -------------------------------------------------------------------------------- 1 | let getNonEmptyObj = jsObj => 2 | switch (jsObj |> Js.Nullable.toOption) { 3 | | None => None 4 | | Some(data) => 5 | switch (Js.Json.decodeObject(data)) { 6 | | None => None 7 | | Some(data) => 8 | switch (Array.length(Js.Dict.keys(data))) { 9 | | 0 => None 10 | | _ => Some(Js.Json.object_(data)) 11 | } 12 | } 13 | }; -------------------------------------------------------------------------------- /examples/swapi/README.md: -------------------------------------------------------------------------------- 1 | # Reason-Apollo Swapi 2 | 3 | This project illustrates the usage of reason-apollo to query the [SWAPI](http://swapi.apis.guru/) and serves as an example on how to use the project. 4 | 5 | ## Getting started 6 | 7 | ``` 8 | npm install 9 | npm start 10 | # in another tab 11 | npm run webpack 12 | ``` 13 | 14 | Then modify whichever file in `src` and refresh the page to see the changes. 15 | -------------------------------------------------------------------------------- /src/ApolloConsumer.re: -------------------------------------------------------------------------------- 1 | open ApolloClient; 2 | 3 | module JsConsumer = { 4 | [@bs.module "react-apollo"] [@react.component] 5 | external make: 6 | (~children: generatedApolloClient => React.element) => React.element = 7 | "ApolloConsumer"; 8 | }; 9 | 10 | [@react.component] 11 | let make = (~children: generatedApolloClient => React.element) => 12 | {client => children(client)} ; 13 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/src/Messages.re: -------------------------------------------------------------------------------- 1 | let component = ReasonReact.statelessComponent("Messages"); 2 | 3 | let make = ( 4 | ~messages, 5 | ~onLoad, 6 | _children 7 | ) => { 8 | ...component, 9 | didMount: _self => { 10 | onLoad() 11 | }, 12 | render: _self =>
13 | { 14 | messages 15 | |> Js.Array.map(message => ) 16 | |> ReasonReact.array 17 | } 18 |
19 | }; 20 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | **Pull Request Labels** 4 | 5 | 8 | 9 | - [ ] feature 10 | - [ ] blocking 11 | - [ ] docs 12 | 13 | 17 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/src/App.re: -------------------------------------------------------------------------------- 1 | module Styles = { 2 | open Css; 3 | 4 | let container = style([ 5 | marginBottom(px(100)) 6 | ]); 7 | }; 8 | 9 | let component = ReasonReact.statelessComponent("App"); 10 | 11 | let make = _children => { 12 | ...component, 13 | render: _self => 14 |
15 |
16 | 17 | 18 | 19 |
, 20 | }; 21 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/src/Header.re: -------------------------------------------------------------------------------- 1 | module Styles = { 2 | open Css; 3 | 4 | let header = style([ 5 | backgroundColor(Theme.primaryColor), 6 | color(white), 7 | fontSize(rem(2.0)), 8 | padding(px(20)) 9 | ]); 10 | }; 11 | 12 | let component = ReasonReact.statelessComponent("Header"); 13 | 14 | let make = _children => { 15 | ...component, 16 | render: _self =>
("Chat Application" |> ReasonReact.string)
, 17 | }; 18 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/bsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reason-scripts", 3 | "sources": ["src", "lib"], 4 | "bs-dependencies": ["reason-react", "@glennsl/bs-jest", "bs-css", "reason-apollo"], 5 | "reason": { 6 | "react-jsx": 2 7 | }, 8 | "bsc-flags": ["-bs-super-errors"], 9 | "refmt": 3, 10 | "package-specs": { 11 | "module": "commonjs", 12 | "in-source": true 13 | }, 14 | "ppx-flags": [ 15 | "graphql_ppx/ppx" 16 | ], 17 | "suffix": ".bs.js" 18 | } 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | *.log 3 | npm-debug.log* 4 | yarn-debug.log* 5 | yarn-error.log* 6 | package-lock.json 7 | 8 | 9 | # Dependency directories 10 | node_modules/ 11 | 12 | # Optional npm cache directory 13 | .npm 14 | 15 | # Optional eslint cache 16 | .eslintcache 17 | 18 | # Yarn Integrity file 19 | .yarn-integrity 20 | 21 | .merlin 22 | 23 | lib 24 | *.bs.js 25 | 26 | **/*.swp 27 | **/.graphql_ppx_cache 28 | 29 | .bsb.lock 30 | schema.graphql 31 | .DS_Store 32 | 33 | # Editor 34 | **/.idea 35 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # bucklescript 13 | /lib 14 | /types 15 | .merlin 16 | *.bs.js 17 | 18 | # misc 19 | .DS_Store 20 | .env.local 21 | .env.development.local 22 | .env.test.local 23 | .env.production.local 24 | 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | **/*.swp 29 | -------------------------------------------------------------------------------- /examples/swapi/src/ShowLivePersons.re: -------------------------------------------------------------------------------- 1 | let ste = React.string; 2 | 3 | [@react.component] 4 | let make = (~persons, ~getLiveData) => { 5 | React.useEffect0(() => { 6 | getLiveData(); 7 | /* Nothing to clean */ 8 | None; 9 | }); 10 | persons 11 | |> Array.mapi((index, person) => 12 |
string_of_int}> 13 | {person##name |> ste} 14 |
15 |

{"ID: " ++ person##id |> ste}

16 |
17 | ) 18 | |> React.array; 19 | }; 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | **Issue Labels** 4 | 5 | 8 | 9 | - [ ] has-reproduction 10 | - [ ] feature 11 | - [ ] docs 12 | - [ ] blocking 13 | - [ ] good first issue 14 | 15 | 19 | -------------------------------------------------------------------------------- /examples/pr/196/client/bsconfig.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "name": "react-hooks-template", 4 | "reason": { 5 | "react-jsx": 3 6 | }, 7 | "sources": { 8 | "dir" : "src", 9 | "subdirs" : true 10 | }, 11 | "package-specs": [{ 12 | "module": "commonjs", 13 | "in-source": true 14 | }], 15 | "suffix": ".bs.js", 16 | "namespace": true, 17 | "bs-dependencies": [ 18 | "reason-react", 19 | "reason-apollo" 20 | ], 21 | "ppx-flags": [ 22 | "graphql_ppx/ppx" 23 | ], 24 | "refmt": 3 25 | } 26 | -------------------------------------------------------------------------------- /bsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reason-apollo", 3 | "sources": [ 4 | { 5 | "dir": "src", 6 | "public": "all", 7 | "subdirs": ["graphql-types"] 8 | }, 9 | { 10 | "dir": "examples", 11 | "type": "dev" 12 | } 13 | ], 14 | "bs-dependencies": ["reason-react"], 15 | "bsc-flags": ["-bs-super-errors"], 16 | "reason": { 17 | "react-jsx": 3 18 | }, 19 | "refmt": 3, 20 | "package-specs": [ 21 | { 22 | "module": "es6", 23 | "in-source": true 24 | } 25 | ], 26 | "suffix": ".bs.js" 27 | } 28 | -------------------------------------------------------------------------------- /examples/swapi/src/PersonById.re: -------------------------------------------------------------------------------- 1 | let ste = React.string; 2 | 3 | [@react.component] 4 | let make = () => { 5 | let (id, setId) = React.useState(() => ""); 6 |
7 |
8 |

{"Get Person By Id" |> ste}

9 | { 15 | let id = ReactEvent.Form.target(event)##value; 16 | setId(_ => id); 17 | }} 18 | required=true 19 | /> 20 | 21 | 22 |
; 23 | }; 24 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/src/ChatBubble.re: -------------------------------------------------------------------------------- 1 | module Styles = { 2 | open Css; 3 | let container = userMsg => style([ 4 | margin(px(5)), 5 | padding(px(5)), 6 | backgroundColor(Theme.secondaryColor), 7 | color(white), 8 | borderRadius(px(3)), 9 | width(px(300)) 10 | ]); 11 | }; 12 | 13 | let component = ReasonReact.statelessComponent("Message"); 14 | 15 | let make = (~message, _children) => { 16 | ...component, 17 | render: _ => 18 |
19 | (message##author##name ++ " : " ++ message##text |> ReasonReact.string) 20 |
, 21 | }; 22 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Chat App 8 | 9 | 15 | 16 | 17 | 20 |
21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Chat App 8 | 9 | 15 | 16 | 17 | 20 |
21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/swapi/src/PersonByIdDelete.re: -------------------------------------------------------------------------------- 1 | let ste = React.string; 2 | 3 | let onIdInputChange = (setId, e) => setId(ReactEvent.Form.target(e)##value); 4 | 5 | [@react.component] 6 | let make = () => { 7 | let (id, setId) = React.useState(() => ""); 8 |
9 |
10 |

{"Delete Selected Person By Id" |> ste}

11 |

{"Select an ID from above and paste it into box" |> ste}

12 | 20 |
21 | 22 |
; 23 | }; 24 | -------------------------------------------------------------------------------- /examples/pr/196/client/src/Wallets.re: -------------------------------------------------------------------------------- 1 | module GetWallets = [%graphql 2 | {| 3 | query getWallets { 4 | wallets { 5 | id 6 | name 7 | } 8 | } 9 | |} 10 | ]; 11 | 12 | module GetWalletsQuery = ReasonApollo.CreateQuery(GetWallets); 13 | 14 | [@react.component] 15 | let make = () => { 16 | 17 | ...{({result}) => 18 | switch (result) { 19 | | Loading =>
{ReasonReact.string("Loading")}
20 | | Error(error) =>
{ReasonReact.string(error##message)}
21 | | Data(response) => 22 | Js.log2("Wallets", response); 23 |
{ReasonReact.string("Success")}
; 24 | } 25 | } 26 |
; 27 | }; 28 | -------------------------------------------------------------------------------- /examples/pr/196/client/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const outputDir = path.join(__dirname, 'build/'); 4 | 5 | const isProd = process.env.NODE_ENV === 'production'; 6 | 7 | module.exports = { 8 | entry: './src/Index.bs.js', 9 | mode: isProd ? 'production' : 'development', 10 | output: { 11 | path: outputDir, 12 | filename: 'Index.js' 13 | }, 14 | plugins: [ 15 | new HtmlWebpackPlugin({ 16 | template: 'src/index.html', 17 | inject: false 18 | }) 19 | ], 20 | devServer: { 21 | compress: true, 22 | contentBase: outputDir, 23 | port: process.env.PORT || 8000, 24 | historyApiFallback: true 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /examples/swapi/bsconfig.json: -------------------------------------------------------------------------------- 1 | /* This is the BuckleScript configuration file. Note that this is a comment; 2 | BuckleScript comes with a JSON parser that supports comments and trailing 3 | comma. If this screws with your editor highlighting, please tell us by filing 4 | an issue! */ 5 | { 6 | "name": "react-template", 7 | "reason": { "react-jsx": 3 }, 8 | "sources": ["src"], 9 | "package-specs": [ 10 | { 11 | "module": "commonjs", 12 | "in-source": true 13 | } 14 | ], 15 | "suffix": ".bs.js", 16 | "namespace": true, 17 | "bs-dependencies": ["reason-react", "reason-apollo"], 18 | "bsc-flags": [ 19 | "-bs-super-errors" 20 | ], 21 | "refmt": 3, 22 | "ppx-flags": ["@baransu/graphql_ppx_re/ppx6"] 23 | } 24 | -------------------------------------------------------------------------------- /examples/pr/196/client/src/Settings.re: -------------------------------------------------------------------------------- 1 | module GetSettings = [%graphql 2 | {| 3 | query getSettings { 4 | settings { 5 | id 6 | version 7 | wallets { 8 | id 9 | name 10 | } 11 | } 12 | } 13 | |} 14 | ]; 15 | 16 | module GetSettingsQuery = ReasonApollo.CreateQuery(GetSettings); 17 | 18 | [@react.component] 19 | let make = () => { 20 | 21 | ...{({result}) => 22 | switch (result) { 23 | | Loading =>
{ReasonReact.string("Loading")}
24 | | Error(error) =>
{ReasonReact.string(error##message)}
25 | | Data(response) => 26 | Js.log(response); 27 |
{ReasonReact.string("Success")}
; 28 | } 29 | } 30 |
; 31 | }; 32 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reason-workshop-chat-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "bs-css": "^7.2.0", 7 | "react": "^16.5.2", 8 | "react-dom": "^16.5.2", 9 | "reason-apollo": "../../", 10 | "reason-scripts": "0.9.0" 11 | }, 12 | "scripts": { 13 | "start": "bsb -make-world -w", 14 | "webpack": "webpack-dev-server", 15 | "get-schema": "yarn send-introspection-query https://boiling-bastion-96890.herokuapp.com/graphql" 16 | }, 17 | "devDependencies": { 18 | "@glennsl/bs-jest": "^0.4.4", 19 | "bs-platform": "^4.0.6", 20 | "graphql_ppx": "^0.2.7", 21 | "reason-react": "^0.5.3", 22 | "webpack": "^4.20.2", 23 | "webpack-cli": "^3.1.2", 24 | "webpack-dev-server": "^3.1.9" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/swapi/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reason-apollo-test", 3 | "version": "0.1.0", 4 | "scripts": { 5 | "build": "bsb -make-world", 6 | "start": "bsb -make-world -w", 7 | "clean": "bsb -clean-world", 8 | "webpack": "webpack-dev-server", 9 | "format": "refmt", 10 | "get-schema": "yarn send-introspection-query https://api.graph.cool/simple/v1/cjdgba1jw4ggk0185ig4bhpsn" 11 | }, 12 | "keywords": [ 13 | "BuckleScript" 14 | ], 15 | "author": "", 16 | "license": "MIT", 17 | "dependencies": { 18 | "apollo-utilities": "^1.0.16", 19 | "react": "^16.8.6", 20 | "react-dom": "^16.8.6", 21 | "reason-apollo": "../../", 22 | "reason-react": "^0.7.0" 23 | }, 24 | "devDependencies": { 25 | "@baransu/graphql_ppx_re": "^0.7.1", 26 | "bs-platform": "^7.2.2", 27 | "webpack": "^4.6.0", 28 | "webpack-cli": "^3.1.2", 29 | "webpack-dev-server": "^3.1.3" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /examples/pr/196/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-react-app", 3 | "version": "0.1.0", 4 | "scripts": { 5 | "build": "bsb -make-world", 6 | "start": "bsb -make-world -w", 7 | "clean": "bsb -clean-world", 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "webpack": "webpack -w", 10 | "webpack:production": "NODE_ENV=production webpack", 11 | "server": "webpack-dev-server" 12 | }, 13 | "keywords": [ 14 | "BuckleScript" 15 | ], 16 | "author": "", 17 | "license": "MIT", 18 | "dependencies": { 19 | "react": "^16.8.1", 20 | "react-dom": "^16.8.1", 21 | "reason-apollo": "^0.16.1", 22 | "reason-react": ">=0.7.0" 23 | }, 24 | "devDependencies": { 25 | "bs-platform": "^7.0.1", 26 | "graphql_ppx": "^0.2.8", 27 | "html-webpack-plugin": "^3.2.0", 28 | "webpack": "^4.0.1", 29 | "webpack-cli": "^3.1.1", 30 | "webpack-dev-server": "^3.1.8" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/src/NewMessageNotification.re: -------------------------------------------------------------------------------- 1 | module NewNotification = [%graphql {| 2 | subscription messageAdded { 3 | messageAdded { 4 | id 5 | text 6 | author { 7 | id 8 | name 9 | } 10 | } 11 | } 12 | |}]; 13 | 14 | module NewNotificationSub = ReasonApollo.CreateSubscription(NewNotification); 15 | 16 | 17 | let component = ReasonReact.statelessComponent("NewMessageNotification"); 18 | 19 | let make = _children => { 20 | ...component, 21 | render: _self => 22 | 23 | ...{ 24 | ({result}) => { 25 | switch result { 26 | | Loading =>
27 | | Error(_error) =>
28 | | Data(_response) => 29 | 33 | } 34 | } 35 | } 36 | 37 | }; 38 | -------------------------------------------------------------------------------- /examples/swapi/src/SubscribeToPersons.re: -------------------------------------------------------------------------------- 1 | module Persons = [%graphql 2 | {| 3 | 4 | subscription { 5 | person: Person { 6 | node { 7 | name 8 | } 9 | } 10 | } 11 | |} 12 | ]; 13 | 14 | module PersonsSubscription = ReasonApollo.CreateSubscription(Persons); 15 | 16 | [@react.component] 17 | let make = () => { 18 |
19 |

{"Person Subscription" |> React.string}

20 | 21 | ...{({result}) => 22 | switch (result) { 23 | | Error(_e) => 24 | Js.log(_e); 25 | "Something went wrong" |> React.string; 26 | | Loading => "Loading" |> React.string 27 | | Data(response) => 28 | switch (response##person) { 29 | | Some(person) => 30 | switch (person##node) { 31 | | Some(node) => node##name |> React.string 32 | | None => "No node found" |> React.string 33 | } 34 | | None => "Persons not found" |> React.string 35 | } 36 | } 37 | } 38 | 39 |
; 40 | }; 41 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/src/ReasonApolloClient.re: -------------------------------------------------------------------------------- 1 | /* Create an InMemoryCache */ 2 | let inMemoryCache = ApolloInMemoryCache.createInMemoryCache(); 3 | 4 | /* Create an HTTP Link */ 5 | let httpLink = 6 | ApolloLinks.createHttpLink( 7 | ~uri="https://boiling-bastion-96890.herokuapp.com/graphql", 8 | (), 9 | ); 10 | 11 | /* WebSocket client */ 12 | let webSocketLink = 13 | ApolloLinks.webSocketLink( 14 | ~uri="wss://boiling-bastion-96890.herokuapp.com/graphql", 15 | ~reconnect=true, 16 | (), 17 | ); 18 | 19 | /* based on test, execute left or right */ 20 | let webSocketHttpLink = 21 | ApolloLinks.split( 22 | operation => { 23 | let operationDefinition = 24 | ApolloUtilities.getMainDefinition(operation##query); 25 | operationDefinition##kind == "OperationDefinition" 26 | && 27 | operationDefinition##operation == "subscription"; 28 | }, 29 | webSocketLink, 30 | httpLink, 31 | ); 32 | 33 | let instance = 34 | ReasonApollo.createApolloClient( 35 | ~link=webSocketHttpLink, 36 | ~cache=inMemoryCache, 37 | (), 38 | ); 39 | -------------------------------------------------------------------------------- /examples/swapi/src/GetPersonById.re: -------------------------------------------------------------------------------- 1 | let ste = React.string; 2 | 3 | /* alias Person as person because compiler doesn't like uppercase key names */ 4 | module GetPerson = [%graphql 5 | {| 6 | query getPerson ($id:ID!){ 7 | person: 8 | Person(id:$id) { 9 | id 10 | age 11 | name 12 | } 13 | } 14 | |} 15 | ]; 16 | 17 | module GetPersonQuery = ReasonApollo.CreateQuery(GetPerson); 18 | 19 | [@react.component] 20 | let make = (~id) => { 21 | let getPersonQuery = GetPerson.make(~id, ()); 22 | 23 | ...{({result}) => 24 |
25 | {switch (result) { 26 | | Error(e) => 27 | Js.log(e); 28 | "Something Went Wrong" |> ste; 29 | | Loading => "Loading" |> ste 30 | | Data(response) => 31 | switch (response##person) { 32 | | None => "No Person Data" |> ste 33 | | Some(person) =>
{person##name |> ste}
34 | } 35 | }} 36 |
37 | } 38 |
; 39 | }; 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Meteor Development Group, Inc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /examples/swapi/src/AddPerson.re: -------------------------------------------------------------------------------- 1 | let ste = React.string; 2 | 3 | module AddPerson = [%graphql 4 | {| 5 | 6 | mutation addPerson($age: Int!, $name: String!) { 7 | createPerson(age: $age, name: $name) { 8 | name 9 | } 10 | } 11 | |} 12 | ]; 13 | 14 | module AddPersonMutation = ReasonApollo.CreateMutation(AddPerson); 15 | 16 | [@react.component] 17 | let make = () => { 18 | let addPersonMutation = AddPerson.make(~name="Bob", ~age=24, ()); 19 | 20 | ...{(mutation, {result}) => 21 |
22 | 33 | 34 | {switch (result) { 35 | | NotCalled => "" |> ste 36 | | Data(_) => "Person has been added" |> ste 37 | | Error(_) => "ERROR" |> ste 38 | | Loading => "Loading" |> ste 39 | }} 40 | 41 |
42 | } 43 |
; 44 | }; 45 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/README.md: -------------------------------------------------------------------------------- 1 | ## Reason DOJO 2 | 3 | ### Real time chat application with Reason and GraphQL 4 | 5 | This example shows Reason Apollo usage with Queries, Mutations and Subscriptions 6 | 7 | ### Config 8 | 9 | - Your GraphQL endpoint: https://boiling-bastion-96890.herokuapp.com/graphql 10 | - The documentation of the GraphQL endpoint (Note! We didn't wrote any documentation, just a normal GraphQL API): 11 | https://graphqlbin.com/v2/WLPqS6 (We recommend using Chrome) 12 | - Paper, pen, redbull,... 13 | 14 | 15 | ### SETUP 16 | 17 | #### GraphQL Playground 18 | Open the GraphQL playground in your browser https://graphqlbin.com/v2/WLPqS6 (Safari doesn't work) 19 | Add a user, grab it's id, put the id into AddMessage.re to make mutations. 20 | (Don't assume endpoint has existing valid user id hardcoded in src) 21 | ` 22 | mutation { 23 | addUser(name:"MyUser") { 24 | id 25 | name 26 | } 27 | } 28 | ` 29 | 30 | #### Run the app 31 | `yarn` 32 | `yarn start` 33 | `yarn webpack` 34 | 35 | (note: the send text field seems to be unused and hard coded to send "HI") 36 | 37 | #### Setup GraphQL PPX 38 | Run the introspection query, so the ppx can typecheck based on the graphql_schema : 39 | https://github.com/apollographql/reason-apollo#send-introspection-query 40 | 41 | 42 | -------------------------------------------------------------------------------- /examples/swapi/src/GetPerson.re: -------------------------------------------------------------------------------- 1 | let ste = React.string; 2 | 3 | /* alias Person as person because compiler doesn't like uppercase key names */ 4 | module GetPerson = [%graphql 5 | {| 6 | query getPerson ($id:ID!){ 7 | person: 8 | Person(id:$id) { 9 | id 10 | age 11 | name 12 | } 13 | } 14 | |} 15 | ]; 16 | 17 | module GetPersonQuery = ReasonApollo.CreateQuery(GetPerson); 18 | 19 | [@react.component] 20 | let make = () => { 21 | /* pick a valid id from list returned from GetPersons query here 22 | "https://api.graph.cool/simple/v1/cjdgba1jw4ggk0185ig4bhpsn" and pass it to ~id variable 23 | */ 24 | let getPersonQuery = GetPerson.make(~id="cjdgbi6d136a90157kpqef72m", ()); 25 | 26 | ...{({result}) => 27 |
28 |

{"Get Person: " |> ste}

29 | {switch (result) { 30 | | Error(e) => 31 | Js.log(e); 32 | "Something Went Wrong" |> ste; 33 | | Loading => "Loading" |> ste 34 | | Data(response) => 35 | switch (response##person) { 36 | | None => "No Person Data" |> ste 37 | | Some(person) =>
{person##name |> ste}
38 | } 39 | }} 40 |
41 | } 42 |
; 43 | }; 44 | -------------------------------------------------------------------------------- /src/graphql-types/ReasonApolloSubscription.rei: -------------------------------------------------------------------------------- 1 | open! ReasonApolloTypes; 2 | 3 | module Make: 4 | (Config: ReasonApolloTypes.Config) => 5 | { 6 | [@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; 7 | 8 | let graphQLSubscriptionAST: queryString; 9 | 10 | type response = subscriptionResponse(Config.t); 11 | 12 | type renderPropObj = { 13 | result: response, 14 | data: option(Config.t), 15 | error: option(apolloError), 16 | loading: bool, 17 | }; 18 | 19 | type renderPropObjJS = { 20 | loading: bool, 21 | data: Js.Nullable.t(Js.Json.t), 22 | error: Js.Nullable.t(apolloError), 23 | }; 24 | 25 | let apolloDataToVariant: renderPropObjJS => response; 26 | 27 | let convertJsInputToReason: renderPropObjJS => renderPropObj; 28 | 29 | module JsSubscription: { 30 | [@bs.module "react-apollo"] [@react.component] 31 | external make: 32 | ( 33 | ~subscription: ReasonApolloTypes.queryString, 34 | ~variables: option(Js.Json.t), 35 | ~children: renderPropObjJS => ReasonReact.reactElement 36 | ) => 37 | ReasonReact.reactElement = 38 | "Subscription"; 39 | }; 40 | 41 | [@react.component] 42 | let make: 43 | (~variables: Js.Json.t=?, ~children: renderPropObj => React.element) => 44 | React.element; 45 | }; 46 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/src/AddMessage.re: -------------------------------------------------------------------------------- 1 | module Styles = { 2 | open Css; 3 | let container = style([ 4 | 5 | ]); 6 | 7 | let input = style([ 8 | width(px(300)), 9 | height(px(22)), 10 | marginLeft(px(32)), 11 | ]); 12 | 13 | let submitBtn = style([ 14 | height(px(28)), 15 | ]); 16 | }; 17 | 18 | module AddMessage = [%graphql {| 19 | mutation addMessage { 20 | addMessage(userId: "e4315d20-fa78-11e8-877a-8f1cf822dad6", text: "HI") { 21 | id 22 | } 23 | } 24 | |}]; 25 | 26 | module AddMessageMutation = ReasonApollo.CreateMutation(AddMessage); 27 | 28 | type state = { 29 | text: string 30 | }; 31 | 32 | type action = 33 | | Change(string); 34 | 35 | let component = ReasonReact.reducerComponent("AddMessage"); 36 | 37 | let make = _children => { 38 | ...component, 39 | initialState: () => { text: "" }, 40 | reducer: (action, _state) => switch action { 41 | | Change(str) => ReasonReact.Update({text: str}) 42 | }, 43 | render: ({state: {text}, send}) => 44 | 45 | ...{ 46 | (mutation, _result) => { 47 |
48 | send(Change(Handler.onChange(e)))} 52 | /> 53 | 59 |
60 | } 61 | } 62 |
, 63 | }; 64 | -------------------------------------------------------------------------------- /examples/pr/196/server/index.js: -------------------------------------------------------------------------------- 1 | const { ApolloServer, gql } = require('apollo-server'); 2 | 3 | // This is a (sample) collection of books we'll be able to query 4 | // the GraphQL server for. A more complete example might fetch 5 | // from an existing data source like a REST API or database. 6 | 7 | const wallets = [{ 8 | id: "1", 9 | name: "What" 10 | }, { 11 | id: "2", 12 | name: "Ever" 13 | }] 14 | 15 | const settings = { 16 | id: "1", 17 | version: "v1", 18 | wallets: wallets 19 | } 20 | 21 | // Type definitions define the "shape" of your data and specify 22 | // which ways the data can be fetched from the GraphQL server. 23 | const typeDefs = gql` 24 | type Wallet { 25 | id: ID! 26 | name: String! 27 | } 28 | 29 | type Settings { 30 | id: ID! 31 | version: String! 32 | wallets: [Wallet!]! 33 | } 34 | 35 | type Query { 36 | wallets: [Wallet!]! 37 | settings: Settings! 38 | } 39 | `; 40 | 41 | // Resolvers define the technique for fetching the types in the 42 | // schema. We'll retrieve books from the "books" array above. 43 | const resolvers = { 44 | Query: { 45 | wallets: () => wallets, 46 | settings: () => settings 47 | }, 48 | }; 49 | 50 | // In the most basic sense, the ApolloServer can be started 51 | // by passing type definitions (typeDefs) and the resolvers 52 | // responsible for fetching the data for those types. 53 | const server = new ApolloServer({ typeDefs, resolvers }); 54 | 55 | // This `listen` method launches a web-server. Existing apps 56 | // can utilize middleware options, which we'll discuss later. 57 | server.listen().then(({ url }) => { 58 | console.log(`🚀 Server ready at ${url}`); 59 | }); 60 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reason-apollo", 3 | "version": "0.20.0", 4 | "license": "MIT", 5 | "sideEffects": "false", 6 | "description": "Using Apollo client 2 with Reason", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/apollographql/reason-apollo" 10 | }, 11 | "peerDependencies": {}, 12 | "keywords": [ 13 | "Reason", 14 | "Apollo", 15 | "React", 16 | "GraphQL" 17 | ], 18 | "author": "Grégoire Van der Auwermeulen ", 19 | "devDependencies": { 20 | "@baransu/graphql_ppx_re": "^0.7.1", 21 | "bs-platform": "^7.2.2", 22 | "husky": "^1.2.0", 23 | "lint-staged": "^8.1.0", 24 | "reason-react": "^0.7.0" 25 | }, 26 | "dependencies": { 27 | "apollo-cache-inmemory": "^1.6.0", 28 | "apollo-client": "^2.6.3", 29 | "apollo-link": "^1.2.12", 30 | "apollo-link-context": "^1.0.18", 31 | "apollo-link-error": "^1.1.11", 32 | "apollo-link-http": "^1.5.15", 33 | "apollo-link-ws": "^1.0.18", 34 | "apollo-upload-client": "9.1.0", 35 | "apollo-utilities": "^1.3.2", 36 | "graphql": "^14.0.2", 37 | "graphql-tag": "^2.10.0", 38 | "react-apollo": "^2.5.8", 39 | "subscriptions-transport-ws": "^0.9.16" 40 | }, 41 | "lint-staged": { 42 | "*.re": [ 43 | "bsrefmt --in-place", 44 | "git add" 45 | ] 46 | }, 47 | "husky": { 48 | "hooks": { 49 | "pre-commit": "lint-staged" 50 | } 51 | }, 52 | "scripts": { 53 | "build": "bsb -make-world", 54 | "start": "bsb -make-world -w", 55 | "clean": "bsb -clean-world", 56 | "lint-staged": "lint-staged", 57 | "test": "echo \"Error: no test specified\" && exit 1" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /examples/swapi/src/Persons.re: -------------------------------------------------------------------------------- 1 | let ste = React.string; 2 | 3 | module GetAllPersons = [%graphql 4 | {| 5 | query getAllPersons { 6 | allPersons { 7 | id 8 | age 9 | name 10 | } 11 | } 12 | |} 13 | ]; 14 | 15 | module GetAllPersonsQuery = ReasonApollo.CreateQuery(GetAllPersons); 16 | 17 | [@react.component] 18 | let make = () => 19 | 20 | ...{({result, fetchMore}) => 21 |
22 |

{"Persons: " |> ste}

23 | {switch (result) { 24 | | Error(e) => 25 | Js.log(e); 26 | "Something Went Wrong" |> ste; 27 | | Loading => "Loading" |> ste 28 | | Data(response) => 29 |
30 | {response##allPersons 31 | |> Array.mapi((index, person) => 32 |
string_of_int}> 33 | {person##name |> ste} 34 |
35 |

{"ID: " ++ person##id |> ste}

36 |
37 | ) 38 | |> React.array} 39 | 52 |
53 | }} 54 |
55 | } 56 |
; 57 | -------------------------------------------------------------------------------- /src/ReasonApollo.re: -------------------------------------------------------------------------------- 1 | open ApolloClient; 2 | 3 | /* 4 | * Expose a createApolloClient function that has to be passed to the ApolloProvider 5 | */ 6 | let createApolloClient = 7 | ( 8 | ~link, 9 | ~cache, 10 | ~ssrMode=?, 11 | ~ssrForceFetchDelay=?, 12 | ~connectToDevTools=?, 13 | ~queryDeduplication=?, 14 | (), 15 | ) => 16 | createApolloClientJS({ 17 | link, 18 | cache, 19 | ssrMode, 20 | ssrForceFetchDelay, 21 | connectToDevTools, 22 | queryDeduplication, 23 | }); 24 | // let createApolloClient = 25 | // ( 26 | // ~link, 27 | // ~cache, 28 | // ~ssrMode=?, 29 | // ~ssrForceFetchDelay=?, 30 | // ~connectToDevTools=?, 31 | // ~queryDeduplication=?, 32 | // (), 33 | // ) => { 34 | // createApolloClientJS( 35 | // apolloClientObjectParam( 36 | // ~link, 37 | // ~cache, 38 | // ~ssrMode?, 39 | // ~ssrForceFetchDelay?, 40 | // ~connectToDevTools?, 41 | // ~queryDeduplication?, 42 | // ), 43 | // ); 44 | // }; 45 | 46 | /* 47 | * Expose a module to perform "query" operations for the given client 48 | */ 49 | module CreateQuery = (Config: ReasonApolloTypes.Config) => 50 | ReasonApolloQuery.Make(Config); 51 | 52 | /* 53 | * Expose a module to perform "mutation" operations for the given client 54 | */ 55 | module CreateMutation = (Config: ReasonApolloTypes.Config) => 56 | ReasonApolloMutation.Make(Config); 57 | /* 58 | * Expose a module to perform "subscription" operations for the given client 59 | */ 60 | module CreateSubscription = (Config: ReasonApolloTypes.Config) => 61 | ReasonApolloSubscription.Make(Config); 62 | 63 | module Provider = ApolloProvider; 64 | 65 | module Consumer = ApolloConsumer; 66 | -------------------------------------------------------------------------------- /examples/swapi/src/Client.re: -------------------------------------------------------------------------------- 1 | /* open ApolloLinks; */ 2 | open ApolloInMemoryCache; 3 | 4 | /* Create an InMemoryCache */ 5 | let inMemoryCache = createInMemoryCache(); 6 | 7 | /* 8 | OR with dataIdFromObject: 9 | 10 | type dataObject = { 11 | . 12 | "__typename": string, 13 | "id": string 14 | }; 15 | 16 | createInMemoryCache(~dataIdFromObject=(obj: dataObject) => obj##id, ()); 17 | */ 18 | 19 | /* Create a Link that puts an Authorization header in context */ 20 | let headerContextLink = 21 | ApolloLinks.createContextLink(() => 22 | { 23 | "headers": { 24 | "authorization": "Bearer $123", 25 | }, 26 | } 27 | ); 28 | 29 | /* Create an HTTP Link */ 30 | let httpLink = 31 | ApolloLinks.createHttpLink( 32 | ~uri="https://api.graph.cool/simple/v1/cjdgba1jw4ggk0185ig4bhpsn", 33 | (), 34 | ); 35 | let webSocketLinkT: ReasonApolloTypes.webSocketLinkT = { 36 | uri: "wss://subscriptions.graph.cool/v1/cjdgba1jw4ggk0185ig4bhpsn", 37 | options: { 38 | reconnect: true, 39 | connectionParams: None, 40 | }, 41 | }; 42 | /* WebSocket client */ 43 | let webSocketLink = ApolloLinks.webSocketLink(webSocketLinkT); 44 | 45 | /* based on test, execute left or right */ 46 | let webSocketHttpLink = 47 | ApolloLinks.split( 48 | operation => { 49 | let operationDefinition = 50 | ApolloUtilities.getMainDefinition(operation.query); 51 | Js.log(operationDefinition); 52 | operationDefinition.kind == "OperationDefinition" 53 | && operationDefinition.operation == "subscription"; 54 | }, 55 | webSocketLink, 56 | httpLink, 57 | ); 58 | 59 | let instance = 60 | ReasonApollo.createApolloClient( 61 | ~link=ApolloLinks.from([|headerContextLink, webSocketHttpLink|]), 62 | ~cache=inMemoryCache, 63 | (), 64 | ); 65 | -------------------------------------------------------------------------------- /src/ApolloInMemoryCache.re: -------------------------------------------------------------------------------- 1 | open ReasonApolloTypes; 2 | 3 | /** 4 | * Used on the client to rehydrate the cache using the initial data passed from the server 5 | * - e.g. window.__APOLLO_STATE__ 6 | */ 7 | type restoreData; 8 | 9 | /** 10 | * Define the data to pass to the restore method that'll be used used to rehydrate client. 11 | * If you don't want to pass any data, simply return `Js_null_undefined.undefined`. 12 | */ 13 | type inMemoryCacheRestoreData = Js.Nullable.t(restoreData); 14 | 15 | /** 16 | * CreateInMemoryCache 17 | * https://github.com/apollographql/apollo-client/tree/master/packages/apollo-cache-inmemory 18 | */ 19 | /* Bind the InMemoryCache class */ 20 | [@bs.module "apollo-cache-inmemory"] 21 | [@bs.new] 22 | external apolloInMemoryCache : 'a => apolloCache = "InMemoryCache"; 23 | 24 | /* Bind the restore method */ 25 | [@bs.send.pipe : 't] 26 | external restore : inMemoryCacheRestoreData => apolloCache = "restore"; 27 | 28 | /* Fragment matcher */ 29 | type fragmentMatcher; 30 | 31 | [@bs.module "apollo-cache-inmemory"] [@bs.new] 32 | external introspectionFragmentMatcher : Js.t({..}) => fragmentMatcher = 33 | "IntrospectionFragmentMatcher"; 34 | 35 | let createIntrospectionFragmentMatcher = (~data) => 36 | introspectionFragmentMatcher({"introspectionQueryResultData": data}); 37 | 38 | /* Instantiate a new cache object */ 39 | [@bs.obj] external 40 | makeApolloInMemoryCacheParams : 41 | ( 42 | ~dataIdFromObject: (Js.t({..}) => string)=?, 43 | ~fragmentMatcher: fragmentMatcher=? 44 | ) => _ = ""; 45 | 46 | let createInMemoryCache = (~dataIdFromObject=?, ~fragmentMatcher=?, ()) => { 47 | /* Apollo Client, looks for key in Object. Doesn't check if value is null */ 48 | apolloInMemoryCache( 49 | makeApolloInMemoryCacheParams(~dataIdFromObject?, ~fragmentMatcher?) 50 | ); 51 | }; 52 | -------------------------------------------------------------------------------- /examples/swapi/src/DeletePerson.re: -------------------------------------------------------------------------------- 1 | let ste = React.string; 2 | 3 | module DeletePerson = [%graphql 4 | {| 5 | mutation deletePerson($id: ID!) { 6 | deletePerson(id: $id) { 7 | id 8 | } 9 | } 10 | |} 11 | ]; 12 | 13 | module DeletePersonMutation = ReasonApollo.CreateMutation(DeletePerson); 14 | 15 | [@react.component] 16 | let make = () => { 17 | /* pick a valid id from list returned from GetPersons query here 18 | "https://api.graph.cool/simple/v1/cjdgba1jw4ggk0185ig4bhpsn" and pass it to ~id variable 19 | */ 20 | let deletePersonMutation = 21 | DeletePerson.make(~id="cjhhv0i51k5lf0160xszwdaps", ()); 22 | 23 | ...{(mutation, {result}) => 24 |
25 |

{"Delete a Person By Id" |> ste}

26 |

27 | {"Pick and Id from above and put it in DeletePerson.re" |> ste} 28 |

29 | 41 | 42 | {switch (result) { 43 | | NotCalled => 44 | Js.log("Not called"); 45 | "" |> ste; 46 | | Data(d) => 47 | Js.log2("data", d); 48 | "Person has been deleted" |> ste; 49 | | Error(e) => 50 | Js.log2("error", e); 51 | "ERROR" |> ste; 52 | | Loading => 53 | Js.log("Loading"); 54 | "Loading" |> ste; 55 | }} 56 | 57 |
58 | } 59 |
; 60 | }; 61 | -------------------------------------------------------------------------------- /examples/swapi/src/DeletePersonButton.re: -------------------------------------------------------------------------------- 1 | let ste = ReasonReact.string; 2 | 3 | module DeletePerson = [%graphql 4 | {| 5 | mutation deletePerson($id: ID!) { 6 | deletePerson(id: $id) { 7 | id 8 | } 9 | } 10 | |} 11 | ]; 12 | 13 | module DeletePersonMutation = ReasonApollo.CreateMutation(DeletePerson); 14 | 15 | [@react.component] 16 | let make = (~id) => { 17 | let deletePersonMutation = DeletePerson.make(~id, ()); 18 | 19 | ...( 20 | (mutation, {result}) => 21 |
22 | 34 | 35 | ( 36 | switch (result) { 37 | | NotCalled => 38 | Js.log("Not called"); 39 | "" |> ste; 40 | | Data(d) => 41 | Js.log2("data", d); 42 | let person = d##deletePerson; 43 | Js.log2("deleted person", person); 44 | "Person with this ID has been deleted" |> ste; 45 | | Error(e) => 46 | Js.log2("error", e); 47 | "ERROR" |> ste; 48 | | Loading => 49 | Js.log("Loading"); 50 | "Loading" |> ste; 51 | } 52 | ) 53 | 54 |
55 | ) 56 |
; 57 | }; 58 | -------------------------------------------------------------------------------- /examples/pr/196/client/README.md: -------------------------------------------------------------------------------- 1 | # my-react-app 2 | 3 | ## Run Project 4 | 5 | ```sh 6 | npm install 7 | npm start 8 | # in another tab 9 | npm run webpack 10 | ``` 11 | 12 | After you see the webpack compilation succeed (the `npm run webpack` step), open up `build/index.html` (**no server needed!**). Then modify whichever `.re` file in `src` and refresh the page to see the changes. 13 | 14 | **For more elaborate ReasonReact examples**, please see https://github.com/reasonml-community/reason-react-example 15 | 16 | ## Run Project with Server 17 | 18 | To run with the webpack development server run `npm run server` and view in the browser at http://localhost:8000. Running in this environment provides hot reloading and support for routing; just edit and save the file and the browser will automatically refresh. 19 | 20 | Note that any hot reload on a route will fall back to the root (`/`), so `ReasonReact.Router.dangerouslyGetInitialUrl` will likely be needed alongside the `ReasonReact.Router.watchUrl` logic to handle routing correctly on hot reload refreshes or simply opening the app at a URL that is not the root. 21 | 22 | To use a port other than 8000 set the `PORT` environment variable (`PORT=8080 npm run server`). 23 | 24 | ## Build for Production 25 | 26 | ```sh 27 | npm run clean 28 | npm run build 29 | npm run webpack:production 30 | ``` 31 | 32 | This will replace the development artifact `build/Index.js` for an optimized version as well as copy `src/index.html` into `build/`. You can then deploy the contents of the `build` directory (`index.html` and `Index.js`). 33 | 34 | If you make use of routing (via `ReasonReact.Router` or similar logic) ensure that server-side routing handles your routes or that 404's are directed back to `index.html` (which is how the dev server is set up). 35 | 36 | **To enable dead code elimination**, change `bsconfig.json`'s `package-specs` `module` from `"commonjs"` to `"es6"`. Then re-run the above 2 commands. This will allow Webpack to remove unused code. 37 | -------------------------------------------------------------------------------- /examples/swapi/src/PersonSubscribeToMore.re: -------------------------------------------------------------------------------- 1 | [@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; 2 | 3 | let ste = React.string; 4 | 5 | module GetAllPersons = [%graphql 6 | {| 7 | query getAllPersons { 8 | allPersons { 9 | id 10 | age 11 | name 12 | } 13 | } 14 | |} 15 | ]; 16 | 17 | module GetAllPersonsQuery = ReasonApollo.CreateQuery(GetAllPersons); 18 | 19 | module NewPerson = [%graphql 20 | {| 21 | 22 | subscription { 23 | person: Person { 24 | node { 25 | name 26 | } 27 | } 28 | } 29 | |} 30 | ]; 31 | 32 | let newPerson = NewPerson.make(); 33 | let newPersonAST = gql(. newPerson##query); 34 | 35 | [@react.component] 36 | let make = () => { 37 | 38 | ...{({result, subscribeToMore}) => 39 |
40 |

{"Persons: " |> ste}

41 | {switch (result) { 42 | | Error(_e) => "Something Went Wrong" |> ste 43 | | Loading => "Loading" |> ste 44 | | Data(response) => 45 | { 48 | let _unsub = 49 | subscribeToMore( 50 | ~document=newPersonAST, 51 | ~updateQuery=[%bs.raw 52 | {| 53 | function(prev, next) { 54 | if(!next.subscriptionData.data || !next.subscriptionData.data.person) 55 | return prev; 56 | return Object.assign({}, prev, { 57 | messages: prev.allPersons.concat(next.subscriptionData.data.person) 58 | }); 59 | } 60 | |} 61 | ], 62 | (), 63 | ); 64 | (); 65 | }} 66 | /> 67 | }} 68 |
69 | } 70 |
; 71 | }; 72 | -------------------------------------------------------------------------------- /src/graphql-types/ReasonApolloSubscription.re: -------------------------------------------------------------------------------- 1 | open! ReasonApolloTypes; 2 | 3 | module Make = (Config: ReasonApolloTypes.Config) => { 4 | [@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; 5 | 6 | let graphQLSubscriptionAST = gql(. Config.query); 7 | 8 | type response = subscriptionResponse(Config.t); 9 | 10 | type renderPropObj = { 11 | result: response, 12 | data: option(Config.t), 13 | error: option(apolloError), 14 | loading: bool, 15 | }; 16 | 17 | type renderPropObjJS = { 18 | loading: bool, 19 | data: Js.Nullable.t(Js.Json.t), 20 | error: Js.Nullable.t(apolloError), 21 | }; 22 | 23 | let apolloDataToVariant = apolloData => 24 | switch ( 25 | apolloData.loading, 26 | apolloData.data |> ReasonApolloUtils.getNonEmptyObj, 27 | apolloData.error |> Js.Nullable.toOption, 28 | ) { 29 | | (true, _, _) => Loading 30 | | (false, Some(response), _) => Data(Config.parse(response)) 31 | | (false, _, Some(error)) => Error(error) 32 | | (false, None, None) => 33 | Error({ 34 | message: "No data", 35 | graphQLErrors: Js.Nullable.null, 36 | networkError: Js.Nullable.null, 37 | }) 38 | }; 39 | 40 | let convertJsInputToReason = apolloData => { 41 | result: apolloData |> apolloDataToVariant, 42 | data: 43 | switch (apolloData.data |> ReasonApolloUtils.getNonEmptyObj) { 44 | | None => None 45 | | Some(data) => 46 | switch (Config.parse(data)) { 47 | | parsedData => Some(parsedData) 48 | | exception _ => None 49 | } 50 | }, 51 | error: 52 | switch (apolloData.error |> Js.Nullable.toOption) { 53 | | Some(error) => Some(error) 54 | | None => None 55 | }, 56 | loading: apolloData.loading, 57 | }; 58 | 59 | module JsSubscription = { 60 | [@bs.module "react-apollo"] [@react.component] 61 | external make: 62 | ( 63 | ~subscription: ReasonApolloTypes.queryString, 64 | ~variables: option(Js.Json.t), 65 | ~children: renderPropObjJS => ReasonReact.reactElement 66 | ) => 67 | ReasonReact.reactElement = 68 | "Subscription"; 69 | }; 70 | 71 | [@react.component] 72 | let make = (~variables=?, ~children) => 73 | 74 | {apolloData => apolloData |> convertJsInputToReason |> children} 75 | ; 76 | }; 77 | -------------------------------------------------------------------------------- /examples/realtime-chat-application/src/MessagesContainer.re: -------------------------------------------------------------------------------- 1 | [@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; 2 | 3 | module Styles = { 4 | open Css; 5 | let container = style([ 6 | margin(px(20)), 7 | padding(px(5)), 8 | boxShadow(~x=px(2), ~y=px(2), grey) 9 | ]); 10 | }; 11 | 12 | module GetAllMessages = [%graphql {| 13 | { 14 | messages { 15 | id 16 | text 17 | author { 18 | id 19 | name 20 | } 21 | } 22 | } 23 | |}]; 24 | 25 | module GetAllMessagesQuery = ReasonApollo.CreateQuery(GetAllMessages); 26 | 27 | 28 | module MessageAdded = [%graphql {| 29 | subscription messageAdded { 30 | messageAdded { 31 | id 32 | text 33 | author { 34 | id 35 | name 36 | } 37 | } 38 | } 39 | |}]; 40 | 41 | let messageAdded = MessageAdded.make(); 42 | let messageAddedASTQuery = gql(. messageAdded##query); 43 | 44 | let component = ReasonReact.statelessComponent("Messages"); 45 | 46 | let make = _children => { 47 | ...component, 48 | render: _self =>
49 | 50 | ...{ 51 | ({result, subscribeToMore}) => switch result { 52 | | Loading =>
{"Loading" |> ReasonReact.string}
53 | | Error(_e) =>
{"Error" |> ReasonReact.string}
54 | | Data(response) => 55 | { 58 | let _unsub = subscribeToMore( 59 | ~document=messageAddedASTQuery, 60 | ~updateQuery={(prev, next) => { 61 | let addNewMessageJS = [%bs.raw {| 62 | function(prev, next) { 63 | if(!next.subscriptionData.data || !next.subscriptionData.data.messageAdded) 64 | return prev; 65 | return Object.assign({}, prev, { 66 | messages: prev.messages.concat(next.subscriptionData.data.messageAdded) 67 | }); 68 | } 69 | |}]; 70 | addNewMessageJS(prev, next); 71 | }}, 72 | () 73 | ) 74 | } 75 | } 76 | messages=(response##messages) 77 | /> 78 | } 79 | } 80 |
81 |
82 | }; -------------------------------------------------------------------------------- /src/ReasonApolloTypes.re: -------------------------------------------------------------------------------- 1 | /** 2 | * An abstract type to describe a query string object. 3 | */ 4 | type queryString; 5 | 6 | /** 7 | * The signature of the `graphql-tag/gql` function that transforms a GraphQL 8 | * query string to the standard GraphQL AST. 9 | * https://github.com/apollographql/graphql-tag 10 | */ 11 | type gql = (. string) => queryString; 12 | 13 | /** 14 | * An abstract type to describe an Apollo Link object. 15 | */ 16 | type apolloLink; 17 | 18 | /** 19 | * An abstract type to describe an Apollo Cache object. 20 | */ 21 | type apolloCache; 22 | 23 | type networkError = {statusCode: int}; 24 | 25 | type apolloErrorExtensions = {code: Js.Nullable.t(string)}; 26 | 27 | type graphqlError = { 28 | message: string, 29 | name: Js.Nullable.t(string), 30 | extensions: Js.Nullable.t(apolloErrorExtensions), 31 | locations: Js.Nullable.t(array(string)), 32 | path: Js.Nullable.t(array(string)), 33 | nodes: Js.Nullable.t(array(string)), 34 | }; 35 | 36 | type executionResult = { 37 | errors: Js.Nullable.t(Js.Array.t(graphqlError)), 38 | data: Js.Nullable.t(Js.Json.t), 39 | }; 40 | 41 | /* TODO define all types */ 42 | type operation = {query: queryString}; 43 | 44 | /* TODO define subscription */ 45 | type subscription; 46 | 47 | type errorResponse = { 48 | graphQLErrors: Js.Nullable.t(Js.Array.t(graphqlError)), 49 | networkError: Js.Nullable.t(networkError), 50 | response: Js.Nullable.t(executionResult), 51 | operation, 52 | forward: operation => subscription, 53 | }; 54 | 55 | module type Config = { 56 | let query: string; 57 | type t; 58 | let parse: Js.Json.t => t; 59 | }; 60 | 61 | type apolloError = { 62 | message: string, 63 | graphQLErrors: Js.Nullable.t(array(graphqlError)), 64 | networkError: Js.Nullable.t(string), 65 | }; 66 | 67 | type apolloOptions = { 68 | query: queryString, 69 | variables: Js.Json.t, 70 | }; 71 | 72 | type queryResponse('a) = 73 | | Loading 74 | | Error(apolloError) 75 | | Data('a); 76 | 77 | type mutationResponse('a) = 78 | | Loading 79 | | Error(apolloError) 80 | | Data('a) 81 | | NotCalled; 82 | 83 | type subscriptionResponse('a) = 84 | | Loading 85 | | Error(apolloError) 86 | | Data('a); 87 | 88 | type executionResponse('a) = 89 | | Errors(array(graphqlError)) 90 | | EmptyResponse 91 | | Data('a); 92 | /* 93 | apollo link ws 94 | */ 95 | 96 | type webSocketLinkOptionsT = { 97 | reconnect: bool, 98 | connectionParams: option(Js.Json.t), 99 | }; 100 | 101 | type webSocketLinkT = { 102 | uri: string, 103 | options: webSocketLinkOptionsT, 104 | }; 105 | 106 | type documentNodeT; 107 | 108 | type splitTest = {query: documentNodeT}; 109 | -------------------------------------------------------------------------------- /src/graphql-types/ReasonApolloMutation.rei: -------------------------------------------------------------------------------- 1 | open! ReasonApolloTypes; 2 | 3 | type renderPropObjJS = { 4 | loading: bool, 5 | called: bool, 6 | data: Js.Nullable.t(Js.Json.t), 7 | error: Js.Nullable.t(apolloError), 8 | networkStatus: Js.Nullable.t(int), 9 | variables: Js.Null_undefined.t(Js.Json.t), 10 | }; 11 | 12 | module Make: 13 | (Config: Config) => 14 | { 15 | external cast: 16 | string => 17 | { 18 | . 19 | "data": Js.Json.t, 20 | "loading": bool, 21 | } = 22 | "%identity"; 23 | 24 | [@bs.module "graphql-tag"] external gql: gql = "default"; 25 | 26 | let graphqlMutationAST: queryString; 27 | type response = mutationResponse(Config.t); 28 | type renderPropObj = { 29 | result: response, 30 | data: option(Config.t), 31 | loading: bool, 32 | error: option(apolloError), 33 | networkStatus: option(int), 34 | }; 35 | type apolloMutation = 36 | ( 37 | ~variables: Js.Json.t=?, 38 | ~refetchQueries: array(string)=?, 39 | ~optimisticResponse: Config.t=?, 40 | unit 41 | ) => 42 | Js.Promise.t(executionResponse(Config.t)); 43 | 44 | type jsMutationParams = { 45 | variables: option(Js.Json.t), 46 | refetchQueries: option(array(string)), 47 | optimisticResponse: option(Config.t), 48 | }; 49 | 50 | let convertExecutionResultToReason: 51 | executionResult => executionResponse(Config.t); 52 | 53 | let apolloMutationFactory: 54 | ( 55 | ~jsMutation: jsMutationParams => Js.Promise.t(executionResult), 56 | ~variables: Js.Json.t=?, 57 | ~refetchQueries: array(string)=?, 58 | ~optimisticResponse: Config.t=?, 59 | unit 60 | ) => 61 | Js.Promise.t(executionResponse(Config.t)); 62 | 63 | let apolloDataToReason: renderPropObjJS => response; 64 | 65 | let convertJsInputToReason: renderPropObjJS => renderPropObj; 66 | 67 | module JsMutation: { 68 | [@bs.module "react-apollo"] [@react.component] 69 | external make: 70 | ( 71 | ~mutation: queryString, 72 | ~variables: Js.Json.t=?, 73 | ~onCompleted: unit => unit=?, 74 | ~onError: apolloError => unit=?, 75 | ~children: ( 76 | jsMutationParams => Js.Promise.t(executionResult), 77 | renderPropObjJS 78 | ) => 79 | React.element 80 | ) => 81 | React.element = 82 | "Mutation"; 83 | }; 84 | 85 | [@react.component] 86 | let make: 87 | ( 88 | ~variables: Js.Json.t=?, 89 | ~onError: apolloError => unit=?, 90 | ~onCompleted: unit => unit=?, 91 | ~children: (apolloMutation, renderPropObj) => React.element 92 | ) => 93 | React.element; 94 | }; 95 | -------------------------------------------------------------------------------- /src/ApolloLinks.re: -------------------------------------------------------------------------------- 1 | open ReasonApolloTypes; 2 | 3 | /* Bind the method `from`, used to compose links together */ 4 | [@bs.module "apollo-link"] 5 | external from: array(apolloLink) => apolloLink = "from"; 6 | 7 | /* Bind the method split. Based on a test send left or right */ 8 | [@bs.module "apollo-link"] 9 | external split: (splitTest => bool, apolloLink, apolloLink) => apolloLink = 10 | "split"; 11 | 12 | /* Bind the HttpLink class */ 13 | [@bs.module "apollo-link-http"] [@bs.new] 14 | external createHttpLink: ApolloClient.linkOptions => apolloLink = "HttpLink"; 15 | 16 | /* Bind the setContext method */ 17 | [@bs.module "apollo-link-context"] 18 | external apolloLinkSetContext: (unit => Js.t({..})) => apolloLink = 19 | "setContext"; 20 | 21 | /* Bind the onError method */ 22 | [@bs.module "apollo-link-error"] 23 | external apolloLinkOnError: (errorResponse => unit) => apolloLink = "onError"; 24 | 25 | /* bind apollo-link-ws */ 26 | [@bs.module "apollo-link-ws"] [@bs.new] 27 | external webSocketLink: webSocketLinkT => apolloLink = "WebSocketLink"; 28 | 29 | /* Bind createUploadLink function from apollo upload link */ 30 | [@bs.module "apollo-upload-client"] 31 | external createUploadLink: ApolloClient.uploadLinkOptions => apolloLink = 32 | "createUploadLink"; 33 | 34 | // let webSocketLink = (~uri, ~reconnect=?, ~connectionParams=?, ()) => { 35 | // uri, 36 | // options: { 37 | // reconnect, 38 | // connectionParams, 39 | // }, 40 | // }; 41 | 42 | /** 43 | * CreateHttpLink 44 | * https://github.com/apollographql/apollo-link/tree/master/packages/apollo-link-http 45 | */ 46 | let createHttpLink = 47 | ( 48 | ~uri, 49 | ~includeExtensions=?, 50 | ~fetch=?, 51 | ~headers=?, 52 | ~credentials=?, 53 | ~fetchOptions=?, 54 | (), 55 | ) => { 56 | createHttpLink({ 57 | uri, 58 | includeExtensions: Js.Nullable.fromOption(includeExtensions), 59 | fetch: Js.Nullable.fromOption(fetch), 60 | headers: Js.Nullable.fromOption(headers), 61 | credentials: Js.Nullable.fromOption(credentials), 62 | fetchOptions: Js.Nullable.fromOption(fetchOptions), 63 | }); 64 | }; 65 | 66 | /** 67 | * CreateUploadLink 68 | * https://github.com/jaydenseric/apollo-upload-client#function-createuploadlink 69 | */ 70 | let createUploadLink = 71 | ( 72 | ~uri=?, 73 | ~fetch=?, 74 | ~fetchOptions=?, 75 | ~credentials=?, 76 | ~headers=?, 77 | ~includeExtensions=?, 78 | (), 79 | ) => 80 | createUploadLink( 81 | Js.Nullable.{ 82 | uri: fromOption(uri), 83 | fetch: fromOption(fetch), 84 | fetchOptions: fromOption(fetchOptions), 85 | credentials: fromOption(credentials), 86 | headers: fromOption(headers), 87 | includeExtensions: fromOption(includeExtensions), 88 | }, 89 | ); 90 | 91 | /** 92 | * CreateContextLink 93 | * https://github.com/apollographql/apollo-link/tree/master/packages/apollo-link-context 94 | */ 95 | let createContextLink = contextHandler => { 96 | /* Instanciate a new context link object */ 97 | apolloLinkSetContext( 98 | contextHandler, 99 | ); 100 | }; 101 | 102 | /** 103 | * CreateErrorLink 104 | * https://github.com/apollographql/apollo-link/tree/master/packages/apollo-link-error 105 | */ 106 | let createErrorLink = errorHandler => { 107 | /* Instanciate a new error link object */ 108 | apolloLinkOnError(errorHandler); 109 | }; 110 | -------------------------------------------------------------------------------- /src/ApolloClient.re: -------------------------------------------------------------------------------- 1 | open ReasonApolloTypes; 2 | 3 | type queryObj = { 4 | query: ReasonApolloTypes.queryString, 5 | variables: Js.Json.t, 6 | }; 7 | 8 | type mutationObj = { 9 | mutation: ReasonApolloTypes.queryString, 10 | variables: Js.Json.t, 11 | }; 12 | 13 | type generatedApolloClient = { 14 | query: 15 | [@bs.meth] (queryObj => Js.Promise.t(ReasonApolloQuery.renderPropObjJS)), 16 | mutate: 17 | [@bs.meth] ( 18 | mutationObj => Js.Promise.t(ReasonApolloMutation.renderPropObjJS) 19 | ), 20 | resetStore: [@bs.meth] (unit => Js.Promise.t(unit)), 21 | }; 22 | 23 | type fetch; 24 | 25 | type linkOptions = { 26 | uri: string, 27 | includeExtensions: Js.Nullable.t(bool), 28 | fetch: Js.Nullable.t(fetch), 29 | headers: Js.Nullable.t(Js.Json.t), 30 | credentials: Js.Nullable.t(string), 31 | fetchOptions: Js.Nullable.t(Js.Json.t), 32 | }; 33 | 34 | type uploadLinkOptions = { 35 | uri: Js.Nullable.t(string), 36 | fetch: Js.Nullable.t(fetch), 37 | fetchOptions: Js.Nullable.t(Js.t({.})), 38 | credentials: Js.Nullable.t(string), 39 | headers: Js.Nullable.t(Js.Json.t), 40 | includeExtensions: Js.Nullable.t(bool), 41 | }; 42 | 43 | type apolloClientObjectParam = { 44 | link: apolloLink, 45 | cache: apolloCache, 46 | ssrMode: option(bool), 47 | ssrForceFetchDelay: option(int), 48 | connectToDevTools: option(bool), 49 | queryDeduplication: option(bool), 50 | }; 51 | [@bs.module "apollo-client"] [@bs.new] 52 | external createApolloClientJS: apolloClientObjectParam => generatedApolloClient = 53 | "ApolloClient"; 54 | 55 | [@bs.module "graphql-tag"] external gql: ReasonApolloTypes.gql = "default"; 56 | 57 | // [@bs.obj] 58 | // external apolloClientObjectParam: 59 | // ( 60 | // ~link: apolloLink, 61 | // ~cache: apolloCache, 62 | // ~ssrMode: bool=?, 63 | // ~ssrForceFetchDelay: int=?, 64 | // ~connectToDevTools: bool=?, 65 | // ~queryDeduplication: bool=? 66 | // ) => 67 | // _ = 68 | // ""; 69 | // type apolloClientObjectParam = { 70 | // link: apolloLink, 71 | // cache: apolloCache, 72 | // ssrMode: option(bool), 73 | // ssrForceFetchDelay: option(int), 74 | // connectToDevTools: option(bool), 75 | // queryDeduplication: option(bool), 76 | // }; 77 | module ReadQuery = (Config: ReasonApolloTypes.Config) => { 78 | type readQueryOptions = { 79 | query: ReasonApolloTypes.queryString, 80 | variables: Js.Nullable.t(Js.Json.t), 81 | }; 82 | type response = option(Config.t); 83 | [@bs.send] 84 | external readQuery: 85 | (generatedApolloClient, readQueryOptions) => Js.Nullable.t(Js.Json.t) = 86 | "readQuery"; 87 | 88 | let graphqlQueryAST = gql(. Config.query); 89 | let apolloDataToRecord: Js.Nullable.t(Js.Json.t) => response = 90 | apolloData => 91 | Js.Nullable.toOption(apolloData)->(Belt.Option.map(Config.parse)); 92 | 93 | let make = (~client, ~variables: option(Js.Json.t)=?, ()) => 94 | readQuery( 95 | client, 96 | {query: graphqlQueryAST, variables: Js.Nullable.fromOption(variables)}, 97 | ) 98 | ->apolloDataToRecord; 99 | }; 100 | 101 | module WriteQuery = (Config: ReasonApolloTypes.Config) => { 102 | type writeQueryOptions = { 103 | query: ReasonApolloTypes.queryString, 104 | variables: Js.Nullable.t(Js.Json.t), 105 | data: Config.t, 106 | }; 107 | [@bs.send] 108 | external writeQuery: (generatedApolloClient, writeQueryOptions) => unit = 109 | "writeQuery"; 110 | 111 | let graphqlQueryAST = gql(. Config.query); 112 | 113 | let make = (~client, ~variables: option(Js.Json.t)=?, ~data: Config.t, ()) => 114 | writeQuery( 115 | client, 116 | { 117 | query: graphqlQueryAST, 118 | variables: Js.Nullable.fromOption(variables), 119 | data, 120 | }, 121 | ); 122 | }; 123 | -------------------------------------------------------------------------------- /src/graphql-types/ReasonApolloQuery.rei: -------------------------------------------------------------------------------- 1 | open! ReasonApolloTypes; 2 | 3 | type updateQueryOptions = { 4 | fetchMoreResult: option(Js.Json.t), 5 | variables: option(Js.Json.t), 6 | }; 7 | 8 | type onErrorT; 9 | type updateQueryT = (Js.Json.t, updateQueryOptions) => Js.Json.t; 10 | type updateSubscriptionOptions = { 11 | subscriptionData: option(Js.Json.t), 12 | variables: option(Js.Json.t), 13 | }; 14 | type updateQuerySubscriptionT = 15 | (Js.Json.t, updateSubscriptionOptions) => Js.Json.t; 16 | 17 | type subscribeToMoreOptions = { 18 | document: queryString, 19 | variables: option(Js.Json.t), 20 | updateQuery: option(updateQuerySubscriptionT), 21 | onError: option(onErrorT), 22 | }; 23 | 24 | /* We don't accept a new query for now */ 25 | 26 | type fetchMoreOptions = { 27 | variables: option(Js.Json.t), 28 | updateQuery: updateQueryT, 29 | }; 30 | 31 | type renderPropObjJS = { 32 | loading: bool, 33 | data: Js.Nullable.t(Js.Json.t), 34 | error: Js.Nullable.t(apolloError), 35 | refetch: Js.Nullable.t(Js.Json.t) => Js.Promise.t(renderPropObjJS), 36 | networkStatus: Js.Nullable.t(int), 37 | variables: Js.Nullable.t(Js.Json.t), 38 | fetchMore: fetchMoreOptions => Js.Promise.t(unit), 39 | subscribeToMore: subscribeToMoreOptions => unit, 40 | }; 41 | 42 | module Make: 43 | (Config: Config) => 44 | { 45 | [@bs.module "graphql-tag"] external gql: gql = "default"; 46 | 47 | type response = queryResponse(Config.t); 48 | 49 | type renderPropObj = { 50 | result: response, 51 | data: option(Config.t), 52 | error: option(apolloError), 53 | loading: bool, 54 | refetch: option(Js.Json.t) => Js.Promise.t(response), 55 | fetchMore: 56 | (~variables: option(Js.Json.t), ~updateQuery: updateQueryT, unit) => 57 | Js.Promise.t(unit), 58 | networkStatus: option(int), 59 | subscribeToMore: 60 | ( 61 | ~document: queryString, 62 | ~variables: Js.Json.t=?, 63 | ~updateQuery: updateQuerySubscriptionT=?, 64 | ~onError: onErrorT=?, 65 | unit 66 | ) => 67 | unit, 68 | }; 69 | 70 | let graphqlQueryAST: queryString; 71 | let apolloDataToVariant: renderPropObjJS => response; 72 | 73 | let convertJsInputToReason: renderPropObjJS => renderPropObj; 74 | 75 | module JsQuery: { 76 | [@bs.module "react-apollo"] [@react.component] 77 | external make: 78 | ( 79 | ~query: queryString, 80 | ~variables: Js.Json.t=?, 81 | ~pollInterval: int=?, 82 | ~notifyOnNetworkStatusChange: bool=?, 83 | ~fetchPolicy: string=?, 84 | ~errorPolicy: string=?, 85 | ~ssr: bool=?, 86 | ~displayName: string=?, 87 | ~skip: bool=?, 88 | ~onCompleted: Js.Nullable.t(Js.Json.t) => unit=?, 89 | ~onError: apolloError => unit=?, 90 | ~partialRefetch: bool=?, 91 | ~delay: bool=?, 92 | ~context: Js.Json.t=?, 93 | ~children: renderPropObjJS => React.element 94 | ) => 95 | React.element = 96 | "Query"; 97 | }; 98 | 99 | [@react.component] 100 | let make: 101 | ( 102 | ~variables: Js.Json.t=?, 103 | ~pollInterval: int=?, 104 | ~notifyOnNetworkStatusChange: bool=?, 105 | ~fetchPolicy: string=?, 106 | ~errorPolicy: string=?, 107 | ~ssr: bool=?, 108 | ~displayName: string=?, 109 | ~skip: bool=?, 110 | ~onCompleted: Js.Nullable.t(Js.Json.t) => unit=?, 111 | ~onError: apolloError => unit=?, 112 | ~partialRefetch: bool=?, 113 | ~delay: bool=?, 114 | ~context: Js.Json.t=?, 115 | ~children: renderPropObj => React.element 116 | ) => 117 | React.element; 118 | }; 119 | -------------------------------------------------------------------------------- /src/graphql-types/ReasonApolloMutation.re: -------------------------------------------------------------------------------- 1 | open! ReasonApolloTypes; 2 | 3 | type renderPropObjJS = { 4 | loading: bool, 5 | called: bool, 6 | data: Js.Nullable.t(Js.Json.t), 7 | error: Js.Nullable.t(apolloError), 8 | networkStatus: Js.Nullable.t(int), 9 | variables: Js.Null_undefined.t(Js.Json.t), 10 | }; 11 | 12 | module Make = (Config: Config) => { 13 | external cast: 14 | string => 15 | { 16 | . 17 | "data": Js.Json.t, 18 | "loading": bool, 19 | } = 20 | "%identity"; 21 | 22 | [@bs.module "graphql-tag"] external gql: gql = "default"; 23 | 24 | let graphqlMutationAST = gql(. Config.query); 25 | type response = mutationResponse(Config.t); 26 | type renderPropObj = { 27 | result: response, 28 | data: option(Config.t), 29 | loading: bool, 30 | error: option(apolloError), 31 | networkStatus: option(int), 32 | }; 33 | type apolloMutation = 34 | ( 35 | ~variables: Js.Json.t=?, 36 | ~refetchQueries: array(string)=?, 37 | ~optimisticResponse: Config.t=?, 38 | unit 39 | ) => 40 | Js.Promise.t(executionResponse(Config.t)); 41 | 42 | type jsMutationParams = { 43 | variables: option(Js.Json.t), 44 | refetchQueries: option(array(string)), 45 | optimisticResponse: option(Config.t), 46 | }; 47 | 48 | let convertExecutionResultToReason = (executionResult: executionResult) => 49 | switch ( 50 | executionResult.data |> ReasonApolloUtils.getNonEmptyObj, 51 | executionResult.errors |> Js.Nullable.toOption, 52 | ) { 53 | | (Some(data), _) => Data(Config.parse(data)) 54 | | (_, Some(errors)) => Errors(errors) 55 | | (None, None) => EmptyResponse 56 | }; 57 | 58 | let apolloMutationFactory = 59 | ( 60 | ~jsMutation, 61 | ~variables=?, 62 | ~refetchQueries=?, 63 | ~optimisticResponse=?, 64 | (), 65 | ) => 66 | jsMutation({variables, refetchQueries, optimisticResponse}) 67 | // jsMutation( 68 | // jsMutationParams( 69 | // ~variables?, 70 | // ~refetchQueries?, 71 | // ~optimisticResponse?, 72 | // (), 73 | // ), 74 | // ) 75 | |> Js.Promise.( 76 | then_(response => resolve(convertExecutionResultToReason(response))) 77 | ); 78 | 79 | let apolloDataToReason: renderPropObjJS => response = 80 | apolloData => 81 | switch ( 82 | apolloData.loading, 83 | apolloData.data |> ReasonApolloUtils.getNonEmptyObj, 84 | apolloData.error |> Js.Nullable.toOption, 85 | ) { 86 | | (true, _, _) => Loading 87 | | (false, Some(data), _) => Data(Config.parse(data)) 88 | | (false, _, Some(error)) => Error(error) 89 | | (false, None, None) => NotCalled 90 | }; 91 | 92 | let convertJsInputToReason = (apolloData: renderPropObjJS) => { 93 | result: apolloDataToReason(apolloData), 94 | data: 95 | switch (apolloData.data |> ReasonApolloUtils.getNonEmptyObj) { 96 | | None => None 97 | | Some(data) => 98 | switch (Config.parse(data)) { 99 | | parsedData => Some(parsedData) 100 | | exception _ => None 101 | } 102 | }, 103 | error: apolloData.error |> Js.Nullable.toOption, 104 | loading: apolloData.loading, 105 | networkStatus: apolloData.networkStatus->Js.Nullable.toOption, 106 | }; 107 | 108 | module JsMutation = { 109 | [@bs.module "react-apollo"] [@react.component] 110 | external make: 111 | ( 112 | ~mutation: queryString, 113 | ~variables: Js.Json.t=?, 114 | ~onCompleted: unit => unit=?, 115 | ~onError: apolloError => unit=?, 116 | ~children: ( 117 | jsMutationParams => Js.Promise.t(executionResult), 118 | renderPropObjJS 119 | ) => 120 | React.element 121 | ) => 122 | React.element = 123 | "Mutation"; 124 | }; 125 | 126 | [@react.component] 127 | let make = (~variables=?, ~onError=?, ~onCompleted=?, ~children) => 128 | 129 | {(mutation, apolloData) => 130 | children( 131 | apolloMutationFactory(~jsMutation=mutation), 132 | apolloData |> convertJsInputToReason, 133 | )} 134 | ; 135 | }; 136 | -------------------------------------------------------------------------------- /src/graphql-types/ReasonApolloQuery.re: -------------------------------------------------------------------------------- 1 | open! ReasonApolloTypes; 2 | 3 | type updateQueryOptions = { 4 | fetchMoreResult: option(Js.Json.t), 5 | variables: option(Js.Json.t), 6 | }; 7 | 8 | type onErrorT; 9 | type updateQueryT = (Js.Json.t, updateQueryOptions) => Js.Json.t; 10 | type updateSubscriptionOptions = { 11 | subscriptionData: option(Js.Json.t), 12 | variables: option(Js.Json.t), 13 | }; 14 | type updateQuerySubscriptionT = 15 | (Js.Json.t, updateSubscriptionOptions) => Js.Json.t; 16 | 17 | type subscribeToMoreOptions = { 18 | document: queryString, 19 | variables: option(Js.Json.t), 20 | updateQuery: option(updateQuerySubscriptionT), 21 | onError: option(onErrorT), 22 | }; 23 | 24 | type fetchMoreOptions = { 25 | variables: option(Js.Json.t), 26 | updateQuery: updateQueryT, 27 | }; 28 | 29 | type renderPropObjJS = { 30 | loading: bool, 31 | data: Js.Nullable.t(Js.Json.t), 32 | error: Js.Nullable.t(apolloError), 33 | refetch: Js.Nullable.t(Js.Json.t) => Js.Promise.t(renderPropObjJS), 34 | networkStatus: Js.Nullable.t(int), 35 | variables: Js.Nullable.t(Js.Json.t), 36 | fetchMore: fetchMoreOptions => Js.Promise.t(unit), 37 | subscribeToMore: subscribeToMoreOptions => unit, 38 | }; 39 | 40 | module Make = (Config: Config) => { 41 | [@bs.module "graphql-tag"] external gql: gql = "default"; 42 | 43 | type response = queryResponse(Config.t); 44 | 45 | type renderPropObj = { 46 | result: response, 47 | data: option(Config.t), 48 | error: option(apolloError), 49 | loading: bool, 50 | refetch: option(Js.Json.t) => Js.Promise.t(response), 51 | fetchMore: 52 | (~variables: option(Js.Json.t), ~updateQuery: updateQueryT, unit) => 53 | Js.Promise.t(unit), 54 | networkStatus: option(int), 55 | subscribeToMore: 56 | ( 57 | ~document: queryString, 58 | ~variables: Js.Json.t=?, 59 | ~updateQuery: updateQuerySubscriptionT=?, 60 | ~onError: onErrorT=?, 61 | unit 62 | ) => 63 | unit, 64 | }; 65 | 66 | let graphqlQueryAST = gql(. Config.query); 67 | let apolloDataToVariant = (apolloData: renderPropObjJS): response => 68 | switch ( 69 | apolloData.loading, 70 | apolloData.data |> ReasonApolloUtils.getNonEmptyObj, 71 | apolloData.error |> Js.Nullable.toOption, 72 | ) { 73 | | (true, _, _) => Loading 74 | | (false, Some(response), _) => Data(Config.parse(response)) 75 | | (false, _, Some(error)) => Error(error) 76 | | (false, None, None) => 77 | Error({ 78 | message: "No data", 79 | graphQLErrors: Js.Nullable.null, 80 | networkError: Js.Nullable.null, 81 | }) 82 | }; 83 | 84 | let convertJsInputToReason = (apolloData: renderPropObjJS) => { 85 | result: apolloData |> apolloDataToVariant, 86 | data: 87 | switch (apolloData.data |> ReasonApolloUtils.getNonEmptyObj) { 88 | | None => None 89 | | Some(data) => 90 | switch (Config.parse(data)) { 91 | | parsedData => Some(parsedData) 92 | | exception _ => None 93 | } 94 | }, 95 | error: 96 | switch (apolloData.error |> Js.Nullable.toOption) { 97 | | Some(error) => Some(error) 98 | | None => None 99 | }, 100 | loading: apolloData.loading, 101 | refetch: variables => 102 | apolloData.refetch(variables |> Js.Nullable.fromOption) 103 | |> Js.Promise.then_(data => 104 | data |> apolloDataToVariant |> Js.Promise.resolve 105 | ), 106 | fetchMore: (~variables, ~updateQuery, ()) => 107 | apolloData.fetchMore({variables, updateQuery}), 108 | networkStatus: apolloData.networkStatus->Js.Nullable.toOption, 109 | subscribeToMore: 110 | (~document, ~variables=?, ~updateQuery=?, ~onError=?, ()) => { 111 | apolloData.subscribeToMore({document, variables, updateQuery, onError}); 112 | }, 113 | }; 114 | 115 | module JsQuery = { 116 | [@bs.module "react-apollo"] [@react.component] 117 | external make: 118 | ( 119 | ~query: queryString, 120 | ~variables: Js.Json.t=?, 121 | ~pollInterval: int=?, 122 | ~notifyOnNetworkStatusChange: bool=?, 123 | ~fetchPolicy: string=?, 124 | ~errorPolicy: string=?, 125 | ~ssr: bool=?, 126 | ~displayName: string=?, 127 | ~skip: bool=?, 128 | ~onCompleted: Js.Nullable.t(Js.Json.t) => unit=?, 129 | ~onError: apolloError => unit=?, 130 | ~partialRefetch: bool=?, 131 | ~delay: bool=?, 132 | ~context: Js.Json.t=?, 133 | ~children: renderPropObjJS => React.element 134 | ) => 135 | React.element = 136 | "Query"; 137 | }; 138 | 139 | [@react.component] 140 | let make = 141 | ( 142 | ~variables=?, 143 | ~pollInterval=?, 144 | ~notifyOnNetworkStatusChange=?, 145 | ~fetchPolicy=?, 146 | ~errorPolicy=?, 147 | ~ssr=?, 148 | ~displayName=?, 149 | ~skip=?, 150 | ~onCompleted=?, 151 | ~onError=?, 152 | ~partialRefetch=?, 153 | ~delay=?, 154 | ~context=?, 155 | ~children, 156 | ) => 157 | 172 | {apolloData => apolloData |> convertJsInputToReason |> children} 173 | ; 174 | }; 175 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Apollo Contributor Guide 2 | 3 | Excited about Apollo and want to make it better? We’re excited too! 4 | 5 | Apollo is a community of developers just like you, striving to create the best tools and libraries around GraphQL. We welcome anyone who wants to contribute or provide constructive feedback, no matter the age or level of experience. If you want to help but don't know where to start, let us know, and we'll find something for you. 6 | 7 | Oh, and if you haven't already, sign up for the [Apollo Slack](http://www.apollodata.com/#slack). 8 | 9 | Here are some ways to contribute to the project, from easiest to most difficult: 10 | 11 | * [Reporting bugs](#reporting-bugs) 12 | * [Improving the documentation](#improving-the-documentation) 13 | * [Responding to issues](#responding-to-issues) 14 | * [Small bug fixes](#small-bug-fixes) 15 | * [Suggesting features](#suggesting-features) 16 | * [Big pull requests](#big-prs) 17 | 18 | ## Issues 19 | 20 | ### Reporting bugs 21 | 22 | If you encounter a bug, please file an issue on GitHub via the repository of the sub-project you think contains the bug. If an issue you have is already reported, please add additional information or add a 👍 reaction to indicate your agreement. 23 | 24 | While we will try to be as helpful as we can on any issue reported, please include the following to maximize the chances of a quick fix: 25 | 26 | 1. **Intended outcome:** What you were trying to accomplish when the bug occurred, and as much code as possible related to the source of the problem. 27 | 2. **Actual outcome:** A description of what actually happened, including a screenshot or copy-paste of any related error messages, logs, or other output that might be related. Places to look for information include your browser console, server console, and network logs. Please avoid non-specific phrases like “didn’t work” or “broke”. 28 | 3. **How to reproduce the issue:** Instructions for how the issue can be reproduced by a maintainer or contributor. Be as specific as possible, and only mention what is necessary to reproduce the bug. If possible, try to isolate the exact circumstances in which the bug occurs and avoid speculation over what the cause might be. 29 | 30 | Creating a good reproduction really helps contributors investigate and resolve your issue quickly. In many cases, the act of creating a minimal reproduction illuminates that the source of the bug was somewhere outside the library in question, saving time and effort for everyone. 31 | 32 | Include in the issue a link to your reproduction—a couple good options are a small Github repo or a [CodeSandbox](https://codesandbox.io/). Here's a starter CodeSandbox you can use: https://codesandbox.io/s/yrwE7pvJ7 33 | 34 | If you have a more complicated issue where it is helpful to run it locally, you may consider using [react-apollo-error-template](https://github.com/apollographql/react-apollo-error-template) for reproducing the issue. 35 | 36 | ### Improving the documentation 37 | 38 | Improving the documentation, examples, and other open source content can be the easiest way to contribute to the library. If you see a piece of content that can be better, open a PR with an improvement, no matter how small! If you would like to suggest a big change or major rewrite, we’d love to hear your ideas but please open an issue for discussion before writing the PR. 39 | 40 | ### Responding to issues 41 | 42 | In addition to reporting issues, a great way to contribute to Apollo is to respond to other peoples' issues and try to identify the problem or help them work around it. If you’re interested in taking a more active role in this process, please go ahead and respond to issues. And don't forget to say "Hi" on Apollo Slack! 43 | 44 | ### Small bug fixes 45 | 46 | For a small bug fix change (less than 20 lines of code changed), feel free to open a pull request. We’ll try to merge it as fast as possible and ideally publish a new release on the same day. The only requirement is, make sure you also add a test that verifies the bug you are trying to fix. 47 | 48 | ### Suggesting features 49 | 50 | Most of the features in Apollo came from suggestions by you, the community! We welcome any ideas about how to make Apollo better for your use case. Unless there is overwhelming demand for a feature, it might not get implemented immediately, but please include as much information as possible that will help people have a discussion about your proposal: 51 | 52 | 1. **Use case:** What are you trying to accomplish, in specific terms? Often, there might already be a good way to do what you need and a new feature is unnecessary, but it’s hard to know without information about the specific use case. 53 | 2. **Could this be a plugin?** In many cases, a feature might be too niche to be included in the core of a library, and is better implemented as a companion package. If there isn’t a way to extend the library to do what you want, could we add additional plugin APIs? It’s important to make the case for why a feature should be part of the core functionality of the library. 54 | 3. **Is there a workaround?** Is this a more convenient way to do something that is already possible, or is there some blocker that makes a workaround unfeasible? 55 | 56 | Feature requests will be labeled as such, and we encourage using GitHub issues as a place to discuss new features and possible implementation designs. Please refrain from submitting a pull request to implement a proposed feature until there is consensus that it should be included. This way, you can avoid putting in work that can’t be merged in. 57 | 58 | Once there is a consensus on the need for a new feature, proceed as listed below under “Big PRs”. 59 | 60 | ## Big PRs 61 | 62 | This includes: 63 | 64 | - Big bug fixes 65 | - New features 66 | 67 | For significant changes to a repository, it’s important to settle on a design before starting on the implementation. This way, we can make sure that major improvements get the care and attention they deserve. Since big changes can be risky and might not always get merged, it’s good to reduce the amount of possible wasted effort by agreeing on an implementation design/plan first. 68 | 69 | 1. **Open an issue.** Open an issue about your bug or feature, as described above. 70 | 2. **Reach consensus.** Some contributors and community members should reach an agreement that this feature or bug is important, and that someone should work on implementing or fixing it. 71 | 3. **Agree on intended behavior.** On the issue, reach an agreement about the desired behavior. In the case of a bug fix, it should be clear what it means for the bug to be fixed, and in the case of a feature, it should be clear what it will be like for developers to use the new feature. 72 | 4. **Agree on implementation plan.** Write a plan for how this feature or bug fix should be implemented. What modules need to be added or rewritten? Should this be one pull request or multiple incremental improvements? Who is going to do each part? 73 | 5. **Submit PR.** In the case where multiple dependent patches need to be made to implement the change, only submit one at a time. Otherwise, the others might get stale while the first is reviewed and merged. Make sure to avoid “while we’re here” type changes - if something isn’t relevant to the improvement at hand, it should be in a separate PR; this especially includes code style changes of unrelated code. 74 | 6. **Review.** At least one core contributor should sign off on the change before it’s merged. Look at the “code review” section below to learn about factors are important in the code review. If you want to expedite the code being merged, try to review your own code first! 75 | 7. **Merge and release!** 76 | 77 | ### Code review guidelines 78 | 79 | It’s important that every piece of code in Apollo packages is reviewed by at least one core contributor familiar with that codebase. Here are some things we look for: 80 | 81 | 1. **Required CI checks pass.** This is a prerequisite for the review, and it is the PR author's responsibility. As long as the tests don’t pass, the PR won't get reviewed. 82 | 2. **Simplicity.** Is this the simplest way to achieve the intended goal? If there are too many files, redundant functions, or complex lines of code, suggest a simpler way to do the same thing. In particular, avoid implementing an overly general solution when a simple, small, and pragmatic fix will do. 83 | 3. **Testing.** Do the tests ensure this code won’t break when other stuff changes around it? When it does break, will the tests added help us identify which part of the library has the problem? Did we cover an appropriate set of edge cases? Look at the test coverage report if there is one. Are all significant code paths in the new code exercised at least once? 84 | 4. **No unnecessary or unrelated changes.** PRs shouldn’t come with random formatting changes, especially in unrelated parts of the code. If there is some refactoring that needs to be done, it should be in a separate PR from a bug fix or feature, if possible. 85 | 5. **Code has appropriate comments.** Code should be commented, or written in a clear “self-documenting” way. 86 | 6. **Idiomatic use of the language.** In TypeScript, make sure the typings are specific and correct. In ES2015, make sure to use imports rather than require and const instead of var, etc. Ideally a linter enforces a lot of this, but use your common sense and follow the style of the surrounding code. 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Archival 2 | This repo was archived by the Apollo Security team on 2023-05-26 3 | 4 | 5 | # Reason-apollo 6 | 7 | [![npm version](https://badge.fury.io/js/reason-apollo.svg)](https://badge.fury.io/js/reason-apollo) 8 | [![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/apollo) 9 | 10 | > react-apollo with ReasonML 11 | 12 | ## Install and setup 13 | 14 | #### Install 15 | 16 | ``` 17 | yarn add reason-apollo 18 | 19 | # Add graphql_ppx 20 | yarn add @baransu/graphql_ppx_re --dev 21 | ``` 22 | 23 | #### bsconfig 24 | 25 | Add `reason-apollo` to your `bs-dependencies` and 26 | `@baransu/graphql_ppx_re/ppx` to your `ppx-flags` 27 | 28 | **bsconfig.json** 29 | 30 | ``` 31 | "bs-dependencies": [ 32 | "reason-react", 33 | "reason-apollo" 34 | ], 35 | "ppx-flags": [ 36 | "@baransu/graphql_ppx_re/ppx" 37 | ] 38 | ``` 39 | 40 | #### Send introspection query 41 | 42 | This will generate a `graphql_schema.json` which will be used to safely type your GraphQL queries/mutations. 43 | 44 | ``` 45 | npx get-graphql-schema ENDPOINT_URL -j > graphql_schema.json 46 | ``` 47 | 48 | ## Why reason-apollo? 49 | 50 | Watch its usage in this video: 51 | 52 | [![Watch reason-apollo usage here](https://i.ytimg.com/vi/yMqE37LqRLA/hqdefault.jpg?sqp=-oaymwEZCNACELwBSFXyq4qpAwsIARUAAIhCGAFwAQ==&rs=AOn4CLD9rxIyXtckkxmGAxRn_Uv2mDcXcQ)](https://www.youtube.com/watch?v=yMqE37LqRLA) 53 | 54 | # Usage 55 | 56 | ## Create the Apollo Client 57 | 58 | **Client.re** 59 | 60 | ```reason 61 | /* Create an InMemoryCache */ 62 | let inMemoryCache = ApolloInMemoryCache.createInMemoryCache(); 63 | 64 | /* Create an HTTP Link */ 65 | let httpLink = 66 | ApolloLinks.createHttpLink(~uri="http://localhost:3010/graphql", ()); 67 | 68 | let instance = 69 | ReasonApollo.createApolloClient(~link=httpLink, ~cache=inMemoryCache, ()); 70 | ``` 71 | 72 | ## ApolloProvider 73 | 74 | **Index.re** 75 | 76 | ```reason 77 | /* 78 | Enhance your application with the `ReasonApollo.Provider` 79 | passing it your client instance 80 | */ 81 | ReactDOMRe.renderToElementWithId( 82 | 83 | 84 | , 85 | "index", 86 | ); 87 | ``` 88 | 89 | ## Query 90 | 91 | **MyQuery.re** 92 | 93 | ```reason 94 | /* Create a GraphQL Query by using the graphql_ppx */ 95 | module GetUserName = [%graphql 96 | {| 97 | query getUserName($id: ID!){ 98 | user(id: $ID) { 99 | id 100 | device { 101 | id 102 | brand { 103 | id 104 | name 105 | } 106 | } 107 | } 108 | } 109 | |} 110 | ]; 111 | 112 | module GetUserNameQuery = ReasonApollo.CreateQuery(GetUserName); 113 | 114 | [@react.component] 115 | let make = () => { 116 | let userNameQuery = GetUserName.make(~id="42", ()); 117 | 118 | ...{({result}) => 119 | switch (result) { 120 | | Loading =>
{ReasonReact.string("Loading")}
121 | | Error(error) =>
{ReasonReact.string(error##message)}
122 | | Data(response) => 123 |
124 | {/* Handles a deeply nested optional response */ 125 | response##user 126 | ->Belt.Option.flatMap(user => user##device) 127 | ->Belt.Option.flatMap(device => device##brand) 128 | ->Belt.Option.mapWithDefault("", brand => brand##name)} 129 |
130 | } 131 | } 132 |
; 133 | }; 134 | 135 | ``` 136 | 137 | ## Mutation 138 | 139 | **MyMutation.re** 140 | 141 | ```reason 142 | module AddUser = [%graphql 143 | {| 144 | mutation addUser($name: String!) { 145 | addUser(name: $name) { 146 | id 147 | name 148 | } 149 | } 150 | |} 151 | ]; 152 | 153 | module AddUserMutation = ReasonApollo.CreateMutation(AddUser); 154 | 155 | [[@react.component] 156 | let make = () => { 157 | 158 | ...{(mutation /* Mutation to call */, _ /* Result of your mutation */) => { 159 | let addNewUserQuery = AddUser.make(~name="Bob", ()); 160 |
161 | 172 |
; 173 | }} 174 |
; 175 | }; 176 | ``` 177 | 178 | ## Subscription 179 | 180 | **MySubscription.re** 181 | 182 | ```reason 183 | module UserAdded = [%graphql {| 184 | subscription userAdded { 185 | userAdded { 186 | id 187 | name 188 | } 189 | } 190 | |}]; 191 | 192 | module UserAddedSubscription = ReasonApollo.CreateSubscription(UserAdded); 193 | 194 | [@react.component] 195 | let make = () => { 196 | 197 | ...{({result}) => { 198 | switch (result) { 199 | | Loading =>
{ReasonReact.string("Loading")}
200 | | Error(error) =>
{ReasonReact.string(error##message)}
201 | | Data(_response) => 202 | 206 | } 207 | }} 208 |
; 209 | }; 210 | ``` 211 | 212 | ## ApolloConsumer 213 | 214 | If you simply want to have access to the ApolloClient, you can use the `ApolloConsumer` 215 | 216 | ```reason 217 | 218 | ...{apolloClient => {/* We have access to the client! */}} 219 | ; 220 | ``` 221 | 222 | ## Tips and Tricks 223 | 224 | ### access deeply nested optional objects 225 | 226 | If for this query 227 | 228 | ```graphql 229 | query { 230 | user { 231 | device { 232 | brand { 233 | name 234 | } 235 | } 236 | } 237 | } 238 | ``` 239 | 240 | you end up with that kind of code: 241 | 242 | ```reason 243 | let deviceName = 244 | switch (response##user) { 245 | | None => "" 246 | | Some(user) => 247 | switch (user##device) { 248 | | None => "" 249 | | Some(device) => 250 | switch (device##brand) { 251 | | None => "" 252 | | Some(brand) => brand##name 253 | } 254 | } 255 | }; 256 | 257 | ``` 258 | 259 | 1. Use `Belt` 260 | 261 | ```reason 262 | open Belt.Option; 263 | 264 | let deviceName = 265 | response##user 266 | ->flatMap(user => user##device) 267 | ->flatMap(device => device##brand) 268 | ->mapWithDefault("", brand => brand##name); 269 | ``` 270 | 271 | 2. Use `@bsRecord` 272 | 273 | The `@bsRecord` modifier is an [extension](https://github.com/reasonml-community/graphql_ppx#record-conversion) of the graphql syntax for BuckleScipt/ReasonML. It allows you to convert a reason object to a reason record and reap the benefits of pattern matching, but you need to defined the record by yourself. 274 | 275 | ```reason 276 | type brand = { 277 | name: string 278 | }; 279 | 280 | type device = { 281 | brand: option(brand) 282 | }; 283 | 284 | type user = { 285 | device: option(device) 286 | }; 287 | 288 | type response = user; 289 | 290 | query { 291 | user @bsRecord { 292 | device @bsRecord { 293 | brand @bsRecord { 294 | name 295 | } 296 | } 297 | } 298 | } 299 | ``` 300 | 301 | This time we can pattern match more precisely. 302 | 303 | ```reason 304 | let deviceName = 305 | switch (response##user) { 306 | | Some({device: Some({brand: {name}})}) => name 307 | | _ => "" 308 | }; 309 | 310 | ``` 311 | 312 | 3. Use `get_in_ppx` 313 | 314 | `npm install get_in_ppx` 315 | and in `bsconfig.json` 316 | `"ppx-flags": ["get_in_ppx/ppx"]` 317 | you can write 318 | 319 | ```reason 320 | let deviceName = response##user#??device#??brand#?name; 321 | ``` 322 | 323 | There's a [blogpost](https://jaredforsyth.com/posts/optional-attribute-access-in-reason/) from Jared Forsyth (author of this ppx) for more explanation. 324 | 325 | ### Use an alias for irregular field names 326 | 327 | You might find yourself consuming an API with field names like `Field`. Currently, reason object field names are required to be camel case. Therefore if you have a request like this: 328 | 329 | ```reason 330 | { 331 | Object { 332 | id 333 | title 334 | } 335 | } 336 | ``` 337 | 338 | You will attempt to access the response object but it will throw an error: 339 | 340 | ```reason 341 | response##Object; /* Does not work :( */ 342 | ``` 343 | 344 | Instead, use an `alias` to modify the response: 345 | 346 | ```reason 347 | { 348 | object: Object { 349 | id 350 | title 351 | } 352 | } 353 | ``` 354 | 355 | Then you can access the object like this: 356 | 357 | ```reason 358 | response##object 359 | ``` 360 | 361 | ### Generic Error and Loading components 362 | 363 | You can create a generic error and Loading component and compose them like this example: 364 | 365 | ```reason 366 | module QueryView = { 367 | [@react.component] 368 | let make = 369 | ( 370 | ~result: ReasonApolloTypes.queryResponse('a), 371 | ~accessData: 'a => option('b), 372 | ~render: ('b, 'c) => React.element, 373 | ~onLoadMore: ('b, 'unit) => unit=(_, ()) => (), 374 | ) => { 375 | switch (result) { 376 | | Error(error) => 377 | | Loading => ReasonReact.null 378 | | Data(response) => 379 | switch (accessData(response)) { 380 | | Some(data) => render(data, onLoadMore(data)) 381 | | _ => 382 | } 383 | }; 384 | }; 385 | }; 386 | 387 | ``` 388 | 389 | ## FAQ 390 | 391 | ### I've added the schema file, but my build fails saying it couldn't be found? 392 | 393 | In some cases, it seems like there are some differences between the provided `send-introspection-query` 394 | and output from tools you might be using to download the schema (such as `apollo-codegen` or `graphql-cli`). 395 | If your build is failing, please make sure to try with the provided script. In your project root, run: 396 | 397 | ``` 398 | npx get-graphql-schema ENDPOINT_URL -j > graphql_schema.json 399 | ``` 400 | -------------------------------------------------------------------------------- /examples/pr/196/client/graphql_schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "__schema": { 4 | "queryType": { 5 | "name": "Query" 6 | }, 7 | "mutationType": null, 8 | "subscriptionType": null, 9 | "types": [ 10 | { 11 | "kind": "OBJECT", 12 | "name": "Query", 13 | "description": "", 14 | "fields": [ 15 | { 16 | "name": "wallets", 17 | "description": "", 18 | "args": [], 19 | "type": { 20 | "kind": "NON_NULL", 21 | "name": null, 22 | "ofType": { 23 | "kind": "LIST", 24 | "name": null, 25 | "ofType": { 26 | "kind": "NON_NULL", 27 | "name": null, 28 | "ofType": { 29 | "kind": "OBJECT", 30 | "name": "Wallet", 31 | "ofType": null 32 | } 33 | } 34 | } 35 | }, 36 | "isDeprecated": false, 37 | "deprecationReason": null 38 | }, 39 | { 40 | "name": "settings", 41 | "description": "", 42 | "args": [], 43 | "type": { 44 | "kind": "NON_NULL", 45 | "name": null, 46 | "ofType": { 47 | "kind": "OBJECT", 48 | "name": "Settings", 49 | "ofType": null 50 | } 51 | }, 52 | "isDeprecated": false, 53 | "deprecationReason": null 54 | } 55 | ], 56 | "inputFields": null, 57 | "interfaces": [], 58 | "enumValues": null, 59 | "possibleTypes": null 60 | }, 61 | { 62 | "kind": "OBJECT", 63 | "name": "Wallet", 64 | "description": "", 65 | "fields": [ 66 | { 67 | "name": "id", 68 | "description": "", 69 | "args": [], 70 | "type": { 71 | "kind": "NON_NULL", 72 | "name": null, 73 | "ofType": { 74 | "kind": "SCALAR", 75 | "name": "ID", 76 | "ofType": null 77 | } 78 | }, 79 | "isDeprecated": false, 80 | "deprecationReason": null 81 | }, 82 | { 83 | "name": "name", 84 | "description": "", 85 | "args": [], 86 | "type": { 87 | "kind": "NON_NULL", 88 | "name": null, 89 | "ofType": { 90 | "kind": "SCALAR", 91 | "name": "String", 92 | "ofType": null 93 | } 94 | }, 95 | "isDeprecated": false, 96 | "deprecationReason": null 97 | } 98 | ], 99 | "inputFields": null, 100 | "interfaces": [], 101 | "enumValues": null, 102 | "possibleTypes": null 103 | }, 104 | { 105 | "kind": "SCALAR", 106 | "name": "ID", 107 | "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.", 108 | "fields": null, 109 | "inputFields": null, 110 | "interfaces": null, 111 | "enumValues": null, 112 | "possibleTypes": null 113 | }, 114 | { 115 | "kind": "SCALAR", 116 | "name": "String", 117 | "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", 118 | "fields": null, 119 | "inputFields": null, 120 | "interfaces": null, 121 | "enumValues": null, 122 | "possibleTypes": null 123 | }, 124 | { 125 | "kind": "OBJECT", 126 | "name": "Settings", 127 | "description": "", 128 | "fields": [ 129 | { 130 | "name": "id", 131 | "description": "", 132 | "args": [], 133 | "type": { 134 | "kind": "NON_NULL", 135 | "name": null, 136 | "ofType": { 137 | "kind": "SCALAR", 138 | "name": "ID", 139 | "ofType": null 140 | } 141 | }, 142 | "isDeprecated": false, 143 | "deprecationReason": null 144 | }, 145 | { 146 | "name": "version", 147 | "description": "", 148 | "args": [], 149 | "type": { 150 | "kind": "NON_NULL", 151 | "name": null, 152 | "ofType": { 153 | "kind": "SCALAR", 154 | "name": "String", 155 | "ofType": null 156 | } 157 | }, 158 | "isDeprecated": false, 159 | "deprecationReason": null 160 | }, 161 | { 162 | "name": "wallets", 163 | "description": "", 164 | "args": [], 165 | "type": { 166 | "kind": "NON_NULL", 167 | "name": null, 168 | "ofType": { 169 | "kind": "LIST", 170 | "name": null, 171 | "ofType": { 172 | "kind": "NON_NULL", 173 | "name": null, 174 | "ofType": { 175 | "kind": "OBJECT", 176 | "name": "Wallet", 177 | "ofType": null 178 | } 179 | } 180 | } 181 | }, 182 | "isDeprecated": false, 183 | "deprecationReason": null 184 | } 185 | ], 186 | "inputFields": null, 187 | "interfaces": [], 188 | "enumValues": null, 189 | "possibleTypes": null 190 | }, 191 | { 192 | "kind": "OBJECT", 193 | "name": "__Schema", 194 | "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", 195 | "fields": [ 196 | { 197 | "name": "types", 198 | "description": "A list of all types supported by this server.", 199 | "args": [], 200 | "type": { 201 | "kind": "NON_NULL", 202 | "name": null, 203 | "ofType": { 204 | "kind": "LIST", 205 | "name": null, 206 | "ofType": { 207 | "kind": "NON_NULL", 208 | "name": null, 209 | "ofType": { 210 | "kind": "OBJECT", 211 | "name": "__Type", 212 | "ofType": null 213 | } 214 | } 215 | } 216 | }, 217 | "isDeprecated": false, 218 | "deprecationReason": null 219 | }, 220 | { 221 | "name": "queryType", 222 | "description": "The type that query operations will be rooted at.", 223 | "args": [], 224 | "type": { 225 | "kind": "NON_NULL", 226 | "name": null, 227 | "ofType": { 228 | "kind": "OBJECT", 229 | "name": "__Type", 230 | "ofType": null 231 | } 232 | }, 233 | "isDeprecated": false, 234 | "deprecationReason": null 235 | }, 236 | { 237 | "name": "mutationType", 238 | "description": "If this server supports mutation, the type that mutation operations will be rooted at.", 239 | "args": [], 240 | "type": { 241 | "kind": "OBJECT", 242 | "name": "__Type", 243 | "ofType": null 244 | }, 245 | "isDeprecated": false, 246 | "deprecationReason": null 247 | }, 248 | { 249 | "name": "subscriptionType", 250 | "description": "If this server support subscription, the type that subscription operations will be rooted at.", 251 | "args": [], 252 | "type": { 253 | "kind": "OBJECT", 254 | "name": "__Type", 255 | "ofType": null 256 | }, 257 | "isDeprecated": false, 258 | "deprecationReason": null 259 | }, 260 | { 261 | "name": "directives", 262 | "description": "A list of all directives supported by this server.", 263 | "args": [], 264 | "type": { 265 | "kind": "NON_NULL", 266 | "name": null, 267 | "ofType": { 268 | "kind": "LIST", 269 | "name": null, 270 | "ofType": { 271 | "kind": "NON_NULL", 272 | "name": null, 273 | "ofType": { 274 | "kind": "OBJECT", 275 | "name": "__Directive", 276 | "ofType": null 277 | } 278 | } 279 | } 280 | }, 281 | "isDeprecated": false, 282 | "deprecationReason": null 283 | } 284 | ], 285 | "inputFields": null, 286 | "interfaces": [], 287 | "enumValues": null, 288 | "possibleTypes": null 289 | }, 290 | { 291 | "kind": "OBJECT", 292 | "name": "__Type", 293 | "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", 294 | "fields": [ 295 | { 296 | "name": "kind", 297 | "description": null, 298 | "args": [], 299 | "type": { 300 | "kind": "NON_NULL", 301 | "name": null, 302 | "ofType": { 303 | "kind": "ENUM", 304 | "name": "__TypeKind", 305 | "ofType": null 306 | } 307 | }, 308 | "isDeprecated": false, 309 | "deprecationReason": null 310 | }, 311 | { 312 | "name": "name", 313 | "description": null, 314 | "args": [], 315 | "type": { 316 | "kind": "SCALAR", 317 | "name": "String", 318 | "ofType": null 319 | }, 320 | "isDeprecated": false, 321 | "deprecationReason": null 322 | }, 323 | { 324 | "name": "description", 325 | "description": null, 326 | "args": [], 327 | "type": { 328 | "kind": "SCALAR", 329 | "name": "String", 330 | "ofType": null 331 | }, 332 | "isDeprecated": false, 333 | "deprecationReason": null 334 | }, 335 | { 336 | "name": "fields", 337 | "description": null, 338 | "args": [ 339 | { 340 | "name": "includeDeprecated", 341 | "description": null, 342 | "type": { 343 | "kind": "SCALAR", 344 | "name": "Boolean", 345 | "ofType": null 346 | }, 347 | "defaultValue": "false" 348 | } 349 | ], 350 | "type": { 351 | "kind": "LIST", 352 | "name": null, 353 | "ofType": { 354 | "kind": "NON_NULL", 355 | "name": null, 356 | "ofType": { 357 | "kind": "OBJECT", 358 | "name": "__Field", 359 | "ofType": null 360 | } 361 | } 362 | }, 363 | "isDeprecated": false, 364 | "deprecationReason": null 365 | }, 366 | { 367 | "name": "interfaces", 368 | "description": null, 369 | "args": [], 370 | "type": { 371 | "kind": "LIST", 372 | "name": null, 373 | "ofType": { 374 | "kind": "NON_NULL", 375 | "name": null, 376 | "ofType": { 377 | "kind": "OBJECT", 378 | "name": "__Type", 379 | "ofType": null 380 | } 381 | } 382 | }, 383 | "isDeprecated": false, 384 | "deprecationReason": null 385 | }, 386 | { 387 | "name": "possibleTypes", 388 | "description": null, 389 | "args": [], 390 | "type": { 391 | "kind": "LIST", 392 | "name": null, 393 | "ofType": { 394 | "kind": "NON_NULL", 395 | "name": null, 396 | "ofType": { 397 | "kind": "OBJECT", 398 | "name": "__Type", 399 | "ofType": null 400 | } 401 | } 402 | }, 403 | "isDeprecated": false, 404 | "deprecationReason": null 405 | }, 406 | { 407 | "name": "enumValues", 408 | "description": null, 409 | "args": [ 410 | { 411 | "name": "includeDeprecated", 412 | "description": null, 413 | "type": { 414 | "kind": "SCALAR", 415 | "name": "Boolean", 416 | "ofType": null 417 | }, 418 | "defaultValue": "false" 419 | } 420 | ], 421 | "type": { 422 | "kind": "LIST", 423 | "name": null, 424 | "ofType": { 425 | "kind": "NON_NULL", 426 | "name": null, 427 | "ofType": { 428 | "kind": "OBJECT", 429 | "name": "__EnumValue", 430 | "ofType": null 431 | } 432 | } 433 | }, 434 | "isDeprecated": false, 435 | "deprecationReason": null 436 | }, 437 | { 438 | "name": "inputFields", 439 | "description": null, 440 | "args": [], 441 | "type": { 442 | "kind": "LIST", 443 | "name": null, 444 | "ofType": { 445 | "kind": "NON_NULL", 446 | "name": null, 447 | "ofType": { 448 | "kind": "OBJECT", 449 | "name": "__InputValue", 450 | "ofType": null 451 | } 452 | } 453 | }, 454 | "isDeprecated": false, 455 | "deprecationReason": null 456 | }, 457 | { 458 | "name": "ofType", 459 | "description": null, 460 | "args": [], 461 | "type": { 462 | "kind": "OBJECT", 463 | "name": "__Type", 464 | "ofType": null 465 | }, 466 | "isDeprecated": false, 467 | "deprecationReason": null 468 | } 469 | ], 470 | "inputFields": null, 471 | "interfaces": [], 472 | "enumValues": null, 473 | "possibleTypes": null 474 | }, 475 | { 476 | "kind": "ENUM", 477 | "name": "__TypeKind", 478 | "description": "An enum describing what kind of type a given `__Type` is.", 479 | "fields": null, 480 | "inputFields": null, 481 | "interfaces": null, 482 | "enumValues": [ 483 | { 484 | "name": "SCALAR", 485 | "description": "Indicates this type is a scalar.", 486 | "isDeprecated": false, 487 | "deprecationReason": null 488 | }, 489 | { 490 | "name": "OBJECT", 491 | "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", 492 | "isDeprecated": false, 493 | "deprecationReason": null 494 | }, 495 | { 496 | "name": "INTERFACE", 497 | "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", 498 | "isDeprecated": false, 499 | "deprecationReason": null 500 | }, 501 | { 502 | "name": "UNION", 503 | "description": "Indicates this type is a union. `possibleTypes` is a valid field.", 504 | "isDeprecated": false, 505 | "deprecationReason": null 506 | }, 507 | { 508 | "name": "ENUM", 509 | "description": "Indicates this type is an enum. `enumValues` is a valid field.", 510 | "isDeprecated": false, 511 | "deprecationReason": null 512 | }, 513 | { 514 | "name": "INPUT_OBJECT", 515 | "description": "Indicates this type is an input object. `inputFields` is a valid field.", 516 | "isDeprecated": false, 517 | "deprecationReason": null 518 | }, 519 | { 520 | "name": "LIST", 521 | "description": "Indicates this type is a list. `ofType` is a valid field.", 522 | "isDeprecated": false, 523 | "deprecationReason": null 524 | }, 525 | { 526 | "name": "NON_NULL", 527 | "description": "Indicates this type is a non-null. `ofType` is a valid field.", 528 | "isDeprecated": false, 529 | "deprecationReason": null 530 | } 531 | ], 532 | "possibleTypes": null 533 | }, 534 | { 535 | "kind": "SCALAR", 536 | "name": "Boolean", 537 | "description": "The `Boolean` scalar type represents `true` or `false`.", 538 | "fields": null, 539 | "inputFields": null, 540 | "interfaces": null, 541 | "enumValues": null, 542 | "possibleTypes": null 543 | }, 544 | { 545 | "kind": "OBJECT", 546 | "name": "__Field", 547 | "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", 548 | "fields": [ 549 | { 550 | "name": "name", 551 | "description": null, 552 | "args": [], 553 | "type": { 554 | "kind": "NON_NULL", 555 | "name": null, 556 | "ofType": { 557 | "kind": "SCALAR", 558 | "name": "String", 559 | "ofType": null 560 | } 561 | }, 562 | "isDeprecated": false, 563 | "deprecationReason": null 564 | }, 565 | { 566 | "name": "description", 567 | "description": null, 568 | "args": [], 569 | "type": { 570 | "kind": "SCALAR", 571 | "name": "String", 572 | "ofType": null 573 | }, 574 | "isDeprecated": false, 575 | "deprecationReason": null 576 | }, 577 | { 578 | "name": "args", 579 | "description": null, 580 | "args": [], 581 | "type": { 582 | "kind": "NON_NULL", 583 | "name": null, 584 | "ofType": { 585 | "kind": "LIST", 586 | "name": null, 587 | "ofType": { 588 | "kind": "NON_NULL", 589 | "name": null, 590 | "ofType": { 591 | "kind": "OBJECT", 592 | "name": "__InputValue", 593 | "ofType": null 594 | } 595 | } 596 | } 597 | }, 598 | "isDeprecated": false, 599 | "deprecationReason": null 600 | }, 601 | { 602 | "name": "type", 603 | "description": null, 604 | "args": [], 605 | "type": { 606 | "kind": "NON_NULL", 607 | "name": null, 608 | "ofType": { 609 | "kind": "OBJECT", 610 | "name": "__Type", 611 | "ofType": null 612 | } 613 | }, 614 | "isDeprecated": false, 615 | "deprecationReason": null 616 | }, 617 | { 618 | "name": "isDeprecated", 619 | "description": null, 620 | "args": [], 621 | "type": { 622 | "kind": "NON_NULL", 623 | "name": null, 624 | "ofType": { 625 | "kind": "SCALAR", 626 | "name": "Boolean", 627 | "ofType": null 628 | } 629 | }, 630 | "isDeprecated": false, 631 | "deprecationReason": null 632 | }, 633 | { 634 | "name": "deprecationReason", 635 | "description": null, 636 | "args": [], 637 | "type": { 638 | "kind": "SCALAR", 639 | "name": "String", 640 | "ofType": null 641 | }, 642 | "isDeprecated": false, 643 | "deprecationReason": null 644 | } 645 | ], 646 | "inputFields": null, 647 | "interfaces": [], 648 | "enumValues": null, 649 | "possibleTypes": null 650 | }, 651 | { 652 | "kind": "OBJECT", 653 | "name": "__InputValue", 654 | "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", 655 | "fields": [ 656 | { 657 | "name": "name", 658 | "description": null, 659 | "args": [], 660 | "type": { 661 | "kind": "NON_NULL", 662 | "name": null, 663 | "ofType": { 664 | "kind": "SCALAR", 665 | "name": "String", 666 | "ofType": null 667 | } 668 | }, 669 | "isDeprecated": false, 670 | "deprecationReason": null 671 | }, 672 | { 673 | "name": "description", 674 | "description": null, 675 | "args": [], 676 | "type": { 677 | "kind": "SCALAR", 678 | "name": "String", 679 | "ofType": null 680 | }, 681 | "isDeprecated": false, 682 | "deprecationReason": null 683 | }, 684 | { 685 | "name": "type", 686 | "description": null, 687 | "args": [], 688 | "type": { 689 | "kind": "NON_NULL", 690 | "name": null, 691 | "ofType": { 692 | "kind": "OBJECT", 693 | "name": "__Type", 694 | "ofType": null 695 | } 696 | }, 697 | "isDeprecated": false, 698 | "deprecationReason": null 699 | }, 700 | { 701 | "name": "defaultValue", 702 | "description": "A GraphQL-formatted string representing the default value for this input value.", 703 | "args": [], 704 | "type": { 705 | "kind": "SCALAR", 706 | "name": "String", 707 | "ofType": null 708 | }, 709 | "isDeprecated": false, 710 | "deprecationReason": null 711 | } 712 | ], 713 | "inputFields": null, 714 | "interfaces": [], 715 | "enumValues": null, 716 | "possibleTypes": null 717 | }, 718 | { 719 | "kind": "OBJECT", 720 | "name": "__EnumValue", 721 | "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", 722 | "fields": [ 723 | { 724 | "name": "name", 725 | "description": null, 726 | "args": [], 727 | "type": { 728 | "kind": "NON_NULL", 729 | "name": null, 730 | "ofType": { 731 | "kind": "SCALAR", 732 | "name": "String", 733 | "ofType": null 734 | } 735 | }, 736 | "isDeprecated": false, 737 | "deprecationReason": null 738 | }, 739 | { 740 | "name": "description", 741 | "description": null, 742 | "args": [], 743 | "type": { 744 | "kind": "SCALAR", 745 | "name": "String", 746 | "ofType": null 747 | }, 748 | "isDeprecated": false, 749 | "deprecationReason": null 750 | }, 751 | { 752 | "name": "isDeprecated", 753 | "description": null, 754 | "args": [], 755 | "type": { 756 | "kind": "NON_NULL", 757 | "name": null, 758 | "ofType": { 759 | "kind": "SCALAR", 760 | "name": "Boolean", 761 | "ofType": null 762 | } 763 | }, 764 | "isDeprecated": false, 765 | "deprecationReason": null 766 | }, 767 | { 768 | "name": "deprecationReason", 769 | "description": null, 770 | "args": [], 771 | "type": { 772 | "kind": "SCALAR", 773 | "name": "String", 774 | "ofType": null 775 | }, 776 | "isDeprecated": false, 777 | "deprecationReason": null 778 | } 779 | ], 780 | "inputFields": null, 781 | "interfaces": [], 782 | "enumValues": null, 783 | "possibleTypes": null 784 | }, 785 | { 786 | "kind": "OBJECT", 787 | "name": "__Directive", 788 | "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", 789 | "fields": [ 790 | { 791 | "name": "name", 792 | "description": null, 793 | "args": [], 794 | "type": { 795 | "kind": "NON_NULL", 796 | "name": null, 797 | "ofType": { 798 | "kind": "SCALAR", 799 | "name": "String", 800 | "ofType": null 801 | } 802 | }, 803 | "isDeprecated": false, 804 | "deprecationReason": null 805 | }, 806 | { 807 | "name": "description", 808 | "description": null, 809 | "args": [], 810 | "type": { 811 | "kind": "SCALAR", 812 | "name": "String", 813 | "ofType": null 814 | }, 815 | "isDeprecated": false, 816 | "deprecationReason": null 817 | }, 818 | { 819 | "name": "locations", 820 | "description": null, 821 | "args": [], 822 | "type": { 823 | "kind": "NON_NULL", 824 | "name": null, 825 | "ofType": { 826 | "kind": "LIST", 827 | "name": null, 828 | "ofType": { 829 | "kind": "NON_NULL", 830 | "name": null, 831 | "ofType": { 832 | "kind": "ENUM", 833 | "name": "__DirectiveLocation", 834 | "ofType": null 835 | } 836 | } 837 | } 838 | }, 839 | "isDeprecated": false, 840 | "deprecationReason": null 841 | }, 842 | { 843 | "name": "args", 844 | "description": null, 845 | "args": [], 846 | "type": { 847 | "kind": "NON_NULL", 848 | "name": null, 849 | "ofType": { 850 | "kind": "LIST", 851 | "name": null, 852 | "ofType": { 853 | "kind": "NON_NULL", 854 | "name": null, 855 | "ofType": { 856 | "kind": "OBJECT", 857 | "name": "__InputValue", 858 | "ofType": null 859 | } 860 | } 861 | } 862 | }, 863 | "isDeprecated": false, 864 | "deprecationReason": null 865 | } 866 | ], 867 | "inputFields": null, 868 | "interfaces": [], 869 | "enumValues": null, 870 | "possibleTypes": null 871 | }, 872 | { 873 | "kind": "ENUM", 874 | "name": "__DirectiveLocation", 875 | "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", 876 | "fields": null, 877 | "inputFields": null, 878 | "interfaces": null, 879 | "enumValues": [ 880 | { 881 | "name": "QUERY", 882 | "description": "Location adjacent to a query operation.", 883 | "isDeprecated": false, 884 | "deprecationReason": null 885 | }, 886 | { 887 | "name": "MUTATION", 888 | "description": "Location adjacent to a mutation operation.", 889 | "isDeprecated": false, 890 | "deprecationReason": null 891 | }, 892 | { 893 | "name": "SUBSCRIPTION", 894 | "description": "Location adjacent to a subscription operation.", 895 | "isDeprecated": false, 896 | "deprecationReason": null 897 | }, 898 | { 899 | "name": "FIELD", 900 | "description": "Location adjacent to a field.", 901 | "isDeprecated": false, 902 | "deprecationReason": null 903 | }, 904 | { 905 | "name": "FRAGMENT_DEFINITION", 906 | "description": "Location adjacent to a fragment definition.", 907 | "isDeprecated": false, 908 | "deprecationReason": null 909 | }, 910 | { 911 | "name": "FRAGMENT_SPREAD", 912 | "description": "Location adjacent to a fragment spread.", 913 | "isDeprecated": false, 914 | "deprecationReason": null 915 | }, 916 | { 917 | "name": "INLINE_FRAGMENT", 918 | "description": "Location adjacent to an inline fragment.", 919 | "isDeprecated": false, 920 | "deprecationReason": null 921 | }, 922 | { 923 | "name": "VARIABLE_DEFINITION", 924 | "description": "Location adjacent to a variable definition.", 925 | "isDeprecated": false, 926 | "deprecationReason": null 927 | }, 928 | { 929 | "name": "SCHEMA", 930 | "description": "Location adjacent to a schema definition.", 931 | "isDeprecated": false, 932 | "deprecationReason": null 933 | }, 934 | { 935 | "name": "SCALAR", 936 | "description": "Location adjacent to a scalar definition.", 937 | "isDeprecated": false, 938 | "deprecationReason": null 939 | }, 940 | { 941 | "name": "OBJECT", 942 | "description": "Location adjacent to an object type definition.", 943 | "isDeprecated": false, 944 | "deprecationReason": null 945 | }, 946 | { 947 | "name": "FIELD_DEFINITION", 948 | "description": "Location adjacent to a field definition.", 949 | "isDeprecated": false, 950 | "deprecationReason": null 951 | }, 952 | { 953 | "name": "ARGUMENT_DEFINITION", 954 | "description": "Location adjacent to an argument definition.", 955 | "isDeprecated": false, 956 | "deprecationReason": null 957 | }, 958 | { 959 | "name": "INTERFACE", 960 | "description": "Location adjacent to an interface definition.", 961 | "isDeprecated": false, 962 | "deprecationReason": null 963 | }, 964 | { 965 | "name": "UNION", 966 | "description": "Location adjacent to a union definition.", 967 | "isDeprecated": false, 968 | "deprecationReason": null 969 | }, 970 | { 971 | "name": "ENUM", 972 | "description": "Location adjacent to an enum definition.", 973 | "isDeprecated": false, 974 | "deprecationReason": null 975 | }, 976 | { 977 | "name": "ENUM_VALUE", 978 | "description": "Location adjacent to an enum value definition.", 979 | "isDeprecated": false, 980 | "deprecationReason": null 981 | }, 982 | { 983 | "name": "INPUT_OBJECT", 984 | "description": "Location adjacent to an input object type definition.", 985 | "isDeprecated": false, 986 | "deprecationReason": null 987 | }, 988 | { 989 | "name": "INPUT_FIELD_DEFINITION", 990 | "description": "Location adjacent to an input object field definition.", 991 | "isDeprecated": false, 992 | "deprecationReason": null 993 | } 994 | ], 995 | "possibleTypes": null 996 | }, 997 | { 998 | "kind": "ENUM", 999 | "name": "CacheControlScope", 1000 | "description": "", 1001 | "fields": null, 1002 | "inputFields": null, 1003 | "interfaces": null, 1004 | "enumValues": [ 1005 | { 1006 | "name": "PUBLIC", 1007 | "description": "", 1008 | "isDeprecated": false, 1009 | "deprecationReason": null 1010 | }, 1011 | { 1012 | "name": "PRIVATE", 1013 | "description": "", 1014 | "isDeprecated": false, 1015 | "deprecationReason": null 1016 | } 1017 | ], 1018 | "possibleTypes": null 1019 | }, 1020 | { 1021 | "kind": "SCALAR", 1022 | "name": "Upload", 1023 | "description": "The `Upload` scalar type represents a file upload.", 1024 | "fields": null, 1025 | "inputFields": null, 1026 | "interfaces": null, 1027 | "enumValues": null, 1028 | "possibleTypes": null 1029 | }, 1030 | { 1031 | "kind": "SCALAR", 1032 | "name": "Int", 1033 | "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1. ", 1034 | "fields": null, 1035 | "inputFields": null, 1036 | "interfaces": null, 1037 | "enumValues": null, 1038 | "possibleTypes": null 1039 | } 1040 | ], 1041 | "directives": [ 1042 | { 1043 | "name": "cacheControl", 1044 | "description": "", 1045 | "locations": [ 1046 | "FIELD_DEFINITION", 1047 | "OBJECT", 1048 | "INTERFACE" 1049 | ], 1050 | "args": [ 1051 | { 1052 | "name": "maxAge", 1053 | "description": "", 1054 | "type": { 1055 | "kind": "SCALAR", 1056 | "name": "Int", 1057 | "ofType": null 1058 | }, 1059 | "defaultValue": null 1060 | }, 1061 | { 1062 | "name": "scope", 1063 | "description": "", 1064 | "type": { 1065 | "kind": "ENUM", 1066 | "name": "CacheControlScope", 1067 | "ofType": null 1068 | }, 1069 | "defaultValue": null 1070 | } 1071 | ] 1072 | }, 1073 | { 1074 | "name": "skip", 1075 | "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", 1076 | "locations": [ 1077 | "FIELD", 1078 | "FRAGMENT_SPREAD", 1079 | "INLINE_FRAGMENT" 1080 | ], 1081 | "args": [ 1082 | { 1083 | "name": "if", 1084 | "description": "Skipped when true.", 1085 | "type": { 1086 | "kind": "NON_NULL", 1087 | "name": null, 1088 | "ofType": { 1089 | "kind": "SCALAR", 1090 | "name": "Boolean", 1091 | "ofType": null 1092 | } 1093 | }, 1094 | "defaultValue": null 1095 | } 1096 | ] 1097 | }, 1098 | { 1099 | "name": "include", 1100 | "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", 1101 | "locations": [ 1102 | "FIELD", 1103 | "FRAGMENT_SPREAD", 1104 | "INLINE_FRAGMENT" 1105 | ], 1106 | "args": [ 1107 | { 1108 | "name": "if", 1109 | "description": "Included when true.", 1110 | "type": { 1111 | "kind": "NON_NULL", 1112 | "name": null, 1113 | "ofType": { 1114 | "kind": "SCALAR", 1115 | "name": "Boolean", 1116 | "ofType": null 1117 | } 1118 | }, 1119 | "defaultValue": null 1120 | } 1121 | ] 1122 | }, 1123 | { 1124 | "name": "deprecated", 1125 | "description": "Marks an element of a GraphQL schema as no longer supported.", 1126 | "locations": [ 1127 | "FIELD_DEFINITION", 1128 | "ENUM_VALUE" 1129 | ], 1130 | "args": [ 1131 | { 1132 | "name": "reason", 1133 | "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax (as specified by [CommonMark](https://commonmark.org/).", 1134 | "type": { 1135 | "kind": "SCALAR", 1136 | "name": "String", 1137 | "ofType": null 1138 | }, 1139 | "defaultValue": "\"No longer supported\"" 1140 | } 1141 | ] 1142 | } 1143 | ] 1144 | } 1145 | } 1146 | } -------------------------------------------------------------------------------- /examples/realtime-chat-application/graphql_schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "__schema": { 4 | "queryType": { 5 | "name": "Query" 6 | }, 7 | "mutationType": { 8 | "name": "Mutation" 9 | }, 10 | "subscriptionType": { 11 | "name": "Subscription" 12 | }, 13 | "types": [ 14 | { 15 | "kind": "OBJECT", 16 | "name": "Query", 17 | "description": "", 18 | "fields": [ 19 | { 20 | "name": "messages", 21 | "description": "", 22 | "args": [], 23 | "type": { 24 | "kind": "NON_NULL", 25 | "name": null, 26 | "ofType": { 27 | "kind": "LIST", 28 | "name": null, 29 | "ofType": { 30 | "kind": "NON_NULL", 31 | "name": null, 32 | "ofType": { 33 | "kind": "OBJECT", 34 | "name": "Message", 35 | "ofType": null 36 | } 37 | } 38 | } 39 | }, 40 | "isDeprecated": false, 41 | "deprecationReason": null 42 | } 43 | ], 44 | "inputFields": null, 45 | "interfaces": [], 46 | "enumValues": null, 47 | "possibleTypes": null 48 | }, 49 | { 50 | "kind": "OBJECT", 51 | "name": "Message", 52 | "description": "", 53 | "fields": [ 54 | { 55 | "name": "id", 56 | "description": "", 57 | "args": [], 58 | "type": { 59 | "kind": "NON_NULL", 60 | "name": null, 61 | "ofType": { 62 | "kind": "SCALAR", 63 | "name": "ID", 64 | "ofType": null 65 | } 66 | }, 67 | "isDeprecated": false, 68 | "deprecationReason": null 69 | }, 70 | { 71 | "name": "text", 72 | "description": "", 73 | "args": [], 74 | "type": { 75 | "kind": "NON_NULL", 76 | "name": null, 77 | "ofType": { 78 | "kind": "SCALAR", 79 | "name": "String", 80 | "ofType": null 81 | } 82 | }, 83 | "isDeprecated": false, 84 | "deprecationReason": null 85 | }, 86 | { 87 | "name": "author", 88 | "description": "", 89 | "args": [], 90 | "type": { 91 | "kind": "NON_NULL", 92 | "name": null, 93 | "ofType": { 94 | "kind": "OBJECT", 95 | "name": "User", 96 | "ofType": null 97 | } 98 | }, 99 | "isDeprecated": false, 100 | "deprecationReason": null 101 | } 102 | ], 103 | "inputFields": null, 104 | "interfaces": [], 105 | "enumValues": null, 106 | "possibleTypes": null 107 | }, 108 | { 109 | "kind": "SCALAR", 110 | "name": "ID", 111 | "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.", 112 | "fields": null, 113 | "inputFields": null, 114 | "interfaces": null, 115 | "enumValues": null, 116 | "possibleTypes": null 117 | }, 118 | { 119 | "kind": "SCALAR", 120 | "name": "String", 121 | "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", 122 | "fields": null, 123 | "inputFields": null, 124 | "interfaces": null, 125 | "enumValues": null, 126 | "possibleTypes": null 127 | }, 128 | { 129 | "kind": "OBJECT", 130 | "name": "User", 131 | "description": "", 132 | "fields": [ 133 | { 134 | "name": "id", 135 | "description": "", 136 | "args": [], 137 | "type": { 138 | "kind": "NON_NULL", 139 | "name": null, 140 | "ofType": { 141 | "kind": "SCALAR", 142 | "name": "ID", 143 | "ofType": null 144 | } 145 | }, 146 | "isDeprecated": false, 147 | "deprecationReason": null 148 | }, 149 | { 150 | "name": "name", 151 | "description": "", 152 | "args": [], 153 | "type": { 154 | "kind": "NON_NULL", 155 | "name": null, 156 | "ofType": { 157 | "kind": "SCALAR", 158 | "name": "String", 159 | "ofType": null 160 | } 161 | }, 162 | "isDeprecated": false, 163 | "deprecationReason": null 164 | } 165 | ], 166 | "inputFields": null, 167 | "interfaces": [], 168 | "enumValues": null, 169 | "possibleTypes": null 170 | }, 171 | { 172 | "kind": "OBJECT", 173 | "name": "Mutation", 174 | "description": "", 175 | "fields": [ 176 | { 177 | "name": "addMessage", 178 | "description": "", 179 | "args": [ 180 | { 181 | "name": "userId", 182 | "description": "", 183 | "type": { 184 | "kind": "NON_NULL", 185 | "name": null, 186 | "ofType": { 187 | "kind": "SCALAR", 188 | "name": "ID", 189 | "ofType": null 190 | } 191 | }, 192 | "defaultValue": null 193 | }, 194 | { 195 | "name": "text", 196 | "description": "", 197 | "type": { 198 | "kind": "NON_NULL", 199 | "name": null, 200 | "ofType": { 201 | "kind": "SCALAR", 202 | "name": "String", 203 | "ofType": null 204 | } 205 | }, 206 | "defaultValue": null 207 | } 208 | ], 209 | "type": { 210 | "kind": "NON_NULL", 211 | "name": null, 212 | "ofType": { 213 | "kind": "OBJECT", 214 | "name": "Message", 215 | "ofType": null 216 | } 217 | }, 218 | "isDeprecated": false, 219 | "deprecationReason": null 220 | }, 221 | { 222 | "name": "addUser", 223 | "description": "", 224 | "args": [ 225 | { 226 | "name": "name", 227 | "description": "", 228 | "type": { 229 | "kind": "NON_NULL", 230 | "name": null, 231 | "ofType": { 232 | "kind": "SCALAR", 233 | "name": "String", 234 | "ofType": null 235 | } 236 | }, 237 | "defaultValue": null 238 | } 239 | ], 240 | "type": { 241 | "kind": "NON_NULL", 242 | "name": null, 243 | "ofType": { 244 | "kind": "OBJECT", 245 | "name": "User", 246 | "ofType": null 247 | } 248 | }, 249 | "isDeprecated": false, 250 | "deprecationReason": null 251 | } 252 | ], 253 | "inputFields": null, 254 | "interfaces": [], 255 | "enumValues": null, 256 | "possibleTypes": null 257 | }, 258 | { 259 | "kind": "OBJECT", 260 | "name": "Subscription", 261 | "description": "", 262 | "fields": [ 263 | { 264 | "name": "messageAdded", 265 | "description": "", 266 | "args": [], 267 | "type": { 268 | "kind": "OBJECT", 269 | "name": "Message", 270 | "ofType": null 271 | }, 272 | "isDeprecated": false, 273 | "deprecationReason": null 274 | } 275 | ], 276 | "inputFields": null, 277 | "interfaces": [], 278 | "enumValues": null, 279 | "possibleTypes": null 280 | }, 281 | { 282 | "kind": "OBJECT", 283 | "name": "__Schema", 284 | "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", 285 | "fields": [ 286 | { 287 | "name": "types", 288 | "description": "A list of all types supported by this server.", 289 | "args": [], 290 | "type": { 291 | "kind": "NON_NULL", 292 | "name": null, 293 | "ofType": { 294 | "kind": "LIST", 295 | "name": null, 296 | "ofType": { 297 | "kind": "NON_NULL", 298 | "name": null, 299 | "ofType": { 300 | "kind": "OBJECT", 301 | "name": "__Type", 302 | "ofType": null 303 | } 304 | } 305 | } 306 | }, 307 | "isDeprecated": false, 308 | "deprecationReason": null 309 | }, 310 | { 311 | "name": "queryType", 312 | "description": "The type that query operations will be rooted at.", 313 | "args": [], 314 | "type": { 315 | "kind": "NON_NULL", 316 | "name": null, 317 | "ofType": { 318 | "kind": "OBJECT", 319 | "name": "__Type", 320 | "ofType": null 321 | } 322 | }, 323 | "isDeprecated": false, 324 | "deprecationReason": null 325 | }, 326 | { 327 | "name": "mutationType", 328 | "description": "If this server supports mutation, the type that mutation operations will be rooted at.", 329 | "args": [], 330 | "type": { 331 | "kind": "OBJECT", 332 | "name": "__Type", 333 | "ofType": null 334 | }, 335 | "isDeprecated": false, 336 | "deprecationReason": null 337 | }, 338 | { 339 | "name": "subscriptionType", 340 | "description": "If this server support subscription, the type that subscription operations will be rooted at.", 341 | "args": [], 342 | "type": { 343 | "kind": "OBJECT", 344 | "name": "__Type", 345 | "ofType": null 346 | }, 347 | "isDeprecated": false, 348 | "deprecationReason": null 349 | }, 350 | { 351 | "name": "directives", 352 | "description": "A list of all directives supported by this server.", 353 | "args": [], 354 | "type": { 355 | "kind": "NON_NULL", 356 | "name": null, 357 | "ofType": { 358 | "kind": "LIST", 359 | "name": null, 360 | "ofType": { 361 | "kind": "NON_NULL", 362 | "name": null, 363 | "ofType": { 364 | "kind": "OBJECT", 365 | "name": "__Directive", 366 | "ofType": null 367 | } 368 | } 369 | } 370 | }, 371 | "isDeprecated": false, 372 | "deprecationReason": null 373 | } 374 | ], 375 | "inputFields": null, 376 | "interfaces": [], 377 | "enumValues": null, 378 | "possibleTypes": null 379 | }, 380 | { 381 | "kind": "OBJECT", 382 | "name": "__Type", 383 | "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name and description, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", 384 | "fields": [ 385 | { 386 | "name": "kind", 387 | "description": null, 388 | "args": [], 389 | "type": { 390 | "kind": "NON_NULL", 391 | "name": null, 392 | "ofType": { 393 | "kind": "ENUM", 394 | "name": "__TypeKind", 395 | "ofType": null 396 | } 397 | }, 398 | "isDeprecated": false, 399 | "deprecationReason": null 400 | }, 401 | { 402 | "name": "name", 403 | "description": null, 404 | "args": [], 405 | "type": { 406 | "kind": "SCALAR", 407 | "name": "String", 408 | "ofType": null 409 | }, 410 | "isDeprecated": false, 411 | "deprecationReason": null 412 | }, 413 | { 414 | "name": "description", 415 | "description": null, 416 | "args": [], 417 | "type": { 418 | "kind": "SCALAR", 419 | "name": "String", 420 | "ofType": null 421 | }, 422 | "isDeprecated": false, 423 | "deprecationReason": null 424 | }, 425 | { 426 | "name": "fields", 427 | "description": null, 428 | "args": [ 429 | { 430 | "name": "includeDeprecated", 431 | "description": null, 432 | "type": { 433 | "kind": "SCALAR", 434 | "name": "Boolean", 435 | "ofType": null 436 | }, 437 | "defaultValue": "false" 438 | } 439 | ], 440 | "type": { 441 | "kind": "LIST", 442 | "name": null, 443 | "ofType": { 444 | "kind": "NON_NULL", 445 | "name": null, 446 | "ofType": { 447 | "kind": "OBJECT", 448 | "name": "__Field", 449 | "ofType": null 450 | } 451 | } 452 | }, 453 | "isDeprecated": false, 454 | "deprecationReason": null 455 | }, 456 | { 457 | "name": "interfaces", 458 | "description": null, 459 | "args": [], 460 | "type": { 461 | "kind": "LIST", 462 | "name": null, 463 | "ofType": { 464 | "kind": "NON_NULL", 465 | "name": null, 466 | "ofType": { 467 | "kind": "OBJECT", 468 | "name": "__Type", 469 | "ofType": null 470 | } 471 | } 472 | }, 473 | "isDeprecated": false, 474 | "deprecationReason": null 475 | }, 476 | { 477 | "name": "possibleTypes", 478 | "description": null, 479 | "args": [], 480 | "type": { 481 | "kind": "LIST", 482 | "name": null, 483 | "ofType": { 484 | "kind": "NON_NULL", 485 | "name": null, 486 | "ofType": { 487 | "kind": "OBJECT", 488 | "name": "__Type", 489 | "ofType": null 490 | } 491 | } 492 | }, 493 | "isDeprecated": false, 494 | "deprecationReason": null 495 | }, 496 | { 497 | "name": "enumValues", 498 | "description": null, 499 | "args": [ 500 | { 501 | "name": "includeDeprecated", 502 | "description": null, 503 | "type": { 504 | "kind": "SCALAR", 505 | "name": "Boolean", 506 | "ofType": null 507 | }, 508 | "defaultValue": "false" 509 | } 510 | ], 511 | "type": { 512 | "kind": "LIST", 513 | "name": null, 514 | "ofType": { 515 | "kind": "NON_NULL", 516 | "name": null, 517 | "ofType": { 518 | "kind": "OBJECT", 519 | "name": "__EnumValue", 520 | "ofType": null 521 | } 522 | } 523 | }, 524 | "isDeprecated": false, 525 | "deprecationReason": null 526 | }, 527 | { 528 | "name": "inputFields", 529 | "description": null, 530 | "args": [], 531 | "type": { 532 | "kind": "LIST", 533 | "name": null, 534 | "ofType": { 535 | "kind": "NON_NULL", 536 | "name": null, 537 | "ofType": { 538 | "kind": "OBJECT", 539 | "name": "__InputValue", 540 | "ofType": null 541 | } 542 | } 543 | }, 544 | "isDeprecated": false, 545 | "deprecationReason": null 546 | }, 547 | { 548 | "name": "ofType", 549 | "description": null, 550 | "args": [], 551 | "type": { 552 | "kind": "OBJECT", 553 | "name": "__Type", 554 | "ofType": null 555 | }, 556 | "isDeprecated": false, 557 | "deprecationReason": null 558 | } 559 | ], 560 | "inputFields": null, 561 | "interfaces": [], 562 | "enumValues": null, 563 | "possibleTypes": null 564 | }, 565 | { 566 | "kind": "ENUM", 567 | "name": "__TypeKind", 568 | "description": "An enum describing what kind of type a given `__Type` is.", 569 | "fields": null, 570 | "inputFields": null, 571 | "interfaces": null, 572 | "enumValues": [ 573 | { 574 | "name": "SCALAR", 575 | "description": "Indicates this type is a scalar.", 576 | "isDeprecated": false, 577 | "deprecationReason": null 578 | }, 579 | { 580 | "name": "OBJECT", 581 | "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", 582 | "isDeprecated": false, 583 | "deprecationReason": null 584 | }, 585 | { 586 | "name": "INTERFACE", 587 | "description": "Indicates this type is an interface. `fields` and `possibleTypes` are valid fields.", 588 | "isDeprecated": false, 589 | "deprecationReason": null 590 | }, 591 | { 592 | "name": "UNION", 593 | "description": "Indicates this type is a union. `possibleTypes` is a valid field.", 594 | "isDeprecated": false, 595 | "deprecationReason": null 596 | }, 597 | { 598 | "name": "ENUM", 599 | "description": "Indicates this type is an enum. `enumValues` is a valid field.", 600 | "isDeprecated": false, 601 | "deprecationReason": null 602 | }, 603 | { 604 | "name": "INPUT_OBJECT", 605 | "description": "Indicates this type is an input object. `inputFields` is a valid field.", 606 | "isDeprecated": false, 607 | "deprecationReason": null 608 | }, 609 | { 610 | "name": "LIST", 611 | "description": "Indicates this type is a list. `ofType` is a valid field.", 612 | "isDeprecated": false, 613 | "deprecationReason": null 614 | }, 615 | { 616 | "name": "NON_NULL", 617 | "description": "Indicates this type is a non-null. `ofType` is a valid field.", 618 | "isDeprecated": false, 619 | "deprecationReason": null 620 | } 621 | ], 622 | "possibleTypes": null 623 | }, 624 | { 625 | "kind": "SCALAR", 626 | "name": "Boolean", 627 | "description": "The `Boolean` scalar type represents `true` or `false`.", 628 | "fields": null, 629 | "inputFields": null, 630 | "interfaces": null, 631 | "enumValues": null, 632 | "possibleTypes": null 633 | }, 634 | { 635 | "kind": "OBJECT", 636 | "name": "__Field", 637 | "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", 638 | "fields": [ 639 | { 640 | "name": "name", 641 | "description": null, 642 | "args": [], 643 | "type": { 644 | "kind": "NON_NULL", 645 | "name": null, 646 | "ofType": { 647 | "kind": "SCALAR", 648 | "name": "String", 649 | "ofType": null 650 | } 651 | }, 652 | "isDeprecated": false, 653 | "deprecationReason": null 654 | }, 655 | { 656 | "name": "description", 657 | "description": null, 658 | "args": [], 659 | "type": { 660 | "kind": "SCALAR", 661 | "name": "String", 662 | "ofType": null 663 | }, 664 | "isDeprecated": false, 665 | "deprecationReason": null 666 | }, 667 | { 668 | "name": "args", 669 | "description": null, 670 | "args": [], 671 | "type": { 672 | "kind": "NON_NULL", 673 | "name": null, 674 | "ofType": { 675 | "kind": "LIST", 676 | "name": null, 677 | "ofType": { 678 | "kind": "NON_NULL", 679 | "name": null, 680 | "ofType": { 681 | "kind": "OBJECT", 682 | "name": "__InputValue", 683 | "ofType": null 684 | } 685 | } 686 | } 687 | }, 688 | "isDeprecated": false, 689 | "deprecationReason": null 690 | }, 691 | { 692 | "name": "type", 693 | "description": null, 694 | "args": [], 695 | "type": { 696 | "kind": "NON_NULL", 697 | "name": null, 698 | "ofType": { 699 | "kind": "OBJECT", 700 | "name": "__Type", 701 | "ofType": null 702 | } 703 | }, 704 | "isDeprecated": false, 705 | "deprecationReason": null 706 | }, 707 | { 708 | "name": "isDeprecated", 709 | "description": null, 710 | "args": [], 711 | "type": { 712 | "kind": "NON_NULL", 713 | "name": null, 714 | "ofType": { 715 | "kind": "SCALAR", 716 | "name": "Boolean", 717 | "ofType": null 718 | } 719 | }, 720 | "isDeprecated": false, 721 | "deprecationReason": null 722 | }, 723 | { 724 | "name": "deprecationReason", 725 | "description": null, 726 | "args": [], 727 | "type": { 728 | "kind": "SCALAR", 729 | "name": "String", 730 | "ofType": null 731 | }, 732 | "isDeprecated": false, 733 | "deprecationReason": null 734 | } 735 | ], 736 | "inputFields": null, 737 | "interfaces": [], 738 | "enumValues": null, 739 | "possibleTypes": null 740 | }, 741 | { 742 | "kind": "OBJECT", 743 | "name": "__InputValue", 744 | "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", 745 | "fields": [ 746 | { 747 | "name": "name", 748 | "description": null, 749 | "args": [], 750 | "type": { 751 | "kind": "NON_NULL", 752 | "name": null, 753 | "ofType": { 754 | "kind": "SCALAR", 755 | "name": "String", 756 | "ofType": null 757 | } 758 | }, 759 | "isDeprecated": false, 760 | "deprecationReason": null 761 | }, 762 | { 763 | "name": "description", 764 | "description": null, 765 | "args": [], 766 | "type": { 767 | "kind": "SCALAR", 768 | "name": "String", 769 | "ofType": null 770 | }, 771 | "isDeprecated": false, 772 | "deprecationReason": null 773 | }, 774 | { 775 | "name": "type", 776 | "description": null, 777 | "args": [], 778 | "type": { 779 | "kind": "NON_NULL", 780 | "name": null, 781 | "ofType": { 782 | "kind": "OBJECT", 783 | "name": "__Type", 784 | "ofType": null 785 | } 786 | }, 787 | "isDeprecated": false, 788 | "deprecationReason": null 789 | }, 790 | { 791 | "name": "defaultValue", 792 | "description": "A GraphQL-formatted string representing the default value for this input value.", 793 | "args": [], 794 | "type": { 795 | "kind": "SCALAR", 796 | "name": "String", 797 | "ofType": null 798 | }, 799 | "isDeprecated": false, 800 | "deprecationReason": null 801 | } 802 | ], 803 | "inputFields": null, 804 | "interfaces": [], 805 | "enumValues": null, 806 | "possibleTypes": null 807 | }, 808 | { 809 | "kind": "OBJECT", 810 | "name": "__EnumValue", 811 | "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", 812 | "fields": [ 813 | { 814 | "name": "name", 815 | "description": null, 816 | "args": [], 817 | "type": { 818 | "kind": "NON_NULL", 819 | "name": null, 820 | "ofType": { 821 | "kind": "SCALAR", 822 | "name": "String", 823 | "ofType": null 824 | } 825 | }, 826 | "isDeprecated": false, 827 | "deprecationReason": null 828 | }, 829 | { 830 | "name": "description", 831 | "description": null, 832 | "args": [], 833 | "type": { 834 | "kind": "SCALAR", 835 | "name": "String", 836 | "ofType": null 837 | }, 838 | "isDeprecated": false, 839 | "deprecationReason": null 840 | }, 841 | { 842 | "name": "isDeprecated", 843 | "description": null, 844 | "args": [], 845 | "type": { 846 | "kind": "NON_NULL", 847 | "name": null, 848 | "ofType": { 849 | "kind": "SCALAR", 850 | "name": "Boolean", 851 | "ofType": null 852 | } 853 | }, 854 | "isDeprecated": false, 855 | "deprecationReason": null 856 | }, 857 | { 858 | "name": "deprecationReason", 859 | "description": null, 860 | "args": [], 861 | "type": { 862 | "kind": "SCALAR", 863 | "name": "String", 864 | "ofType": null 865 | }, 866 | "isDeprecated": false, 867 | "deprecationReason": null 868 | } 869 | ], 870 | "inputFields": null, 871 | "interfaces": [], 872 | "enumValues": null, 873 | "possibleTypes": null 874 | }, 875 | { 876 | "kind": "OBJECT", 877 | "name": "__Directive", 878 | "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", 879 | "fields": [ 880 | { 881 | "name": "name", 882 | "description": null, 883 | "args": [], 884 | "type": { 885 | "kind": "NON_NULL", 886 | "name": null, 887 | "ofType": { 888 | "kind": "SCALAR", 889 | "name": "String", 890 | "ofType": null 891 | } 892 | }, 893 | "isDeprecated": false, 894 | "deprecationReason": null 895 | }, 896 | { 897 | "name": "description", 898 | "description": null, 899 | "args": [], 900 | "type": { 901 | "kind": "SCALAR", 902 | "name": "String", 903 | "ofType": null 904 | }, 905 | "isDeprecated": false, 906 | "deprecationReason": null 907 | }, 908 | { 909 | "name": "locations", 910 | "description": null, 911 | "args": [], 912 | "type": { 913 | "kind": "NON_NULL", 914 | "name": null, 915 | "ofType": { 916 | "kind": "LIST", 917 | "name": null, 918 | "ofType": { 919 | "kind": "NON_NULL", 920 | "name": null, 921 | "ofType": { 922 | "kind": "ENUM", 923 | "name": "__DirectiveLocation", 924 | "ofType": null 925 | } 926 | } 927 | } 928 | }, 929 | "isDeprecated": false, 930 | "deprecationReason": null 931 | }, 932 | { 933 | "name": "args", 934 | "description": null, 935 | "args": [], 936 | "type": { 937 | "kind": "NON_NULL", 938 | "name": null, 939 | "ofType": { 940 | "kind": "LIST", 941 | "name": null, 942 | "ofType": { 943 | "kind": "NON_NULL", 944 | "name": null, 945 | "ofType": { 946 | "kind": "OBJECT", 947 | "name": "__InputValue", 948 | "ofType": null 949 | } 950 | } 951 | } 952 | }, 953 | "isDeprecated": false, 954 | "deprecationReason": null 955 | }, 956 | { 957 | "name": "onOperation", 958 | "description": null, 959 | "args": [], 960 | "type": { 961 | "kind": "NON_NULL", 962 | "name": null, 963 | "ofType": { 964 | "kind": "SCALAR", 965 | "name": "Boolean", 966 | "ofType": null 967 | } 968 | }, 969 | "isDeprecated": true, 970 | "deprecationReason": "Use `locations`." 971 | }, 972 | { 973 | "name": "onFragment", 974 | "description": null, 975 | "args": [], 976 | "type": { 977 | "kind": "NON_NULL", 978 | "name": null, 979 | "ofType": { 980 | "kind": "SCALAR", 981 | "name": "Boolean", 982 | "ofType": null 983 | } 984 | }, 985 | "isDeprecated": true, 986 | "deprecationReason": "Use `locations`." 987 | }, 988 | { 989 | "name": "onField", 990 | "description": null, 991 | "args": [], 992 | "type": { 993 | "kind": "NON_NULL", 994 | "name": null, 995 | "ofType": { 996 | "kind": "SCALAR", 997 | "name": "Boolean", 998 | "ofType": null 999 | } 1000 | }, 1001 | "isDeprecated": true, 1002 | "deprecationReason": "Use `locations`." 1003 | } 1004 | ], 1005 | "inputFields": null, 1006 | "interfaces": [], 1007 | "enumValues": null, 1008 | "possibleTypes": null 1009 | }, 1010 | { 1011 | "kind": "ENUM", 1012 | "name": "__DirectiveLocation", 1013 | "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", 1014 | "fields": null, 1015 | "inputFields": null, 1016 | "interfaces": null, 1017 | "enumValues": [ 1018 | { 1019 | "name": "QUERY", 1020 | "description": "Location adjacent to a query operation.", 1021 | "isDeprecated": false, 1022 | "deprecationReason": null 1023 | }, 1024 | { 1025 | "name": "MUTATION", 1026 | "description": "Location adjacent to a mutation operation.", 1027 | "isDeprecated": false, 1028 | "deprecationReason": null 1029 | }, 1030 | { 1031 | "name": "SUBSCRIPTION", 1032 | "description": "Location adjacent to a subscription operation.", 1033 | "isDeprecated": false, 1034 | "deprecationReason": null 1035 | }, 1036 | { 1037 | "name": "FIELD", 1038 | "description": "Location adjacent to a field.", 1039 | "isDeprecated": false, 1040 | "deprecationReason": null 1041 | }, 1042 | { 1043 | "name": "FRAGMENT_DEFINITION", 1044 | "description": "Location adjacent to a fragment definition.", 1045 | "isDeprecated": false, 1046 | "deprecationReason": null 1047 | }, 1048 | { 1049 | "name": "FRAGMENT_SPREAD", 1050 | "description": "Location adjacent to a fragment spread.", 1051 | "isDeprecated": false, 1052 | "deprecationReason": null 1053 | }, 1054 | { 1055 | "name": "INLINE_FRAGMENT", 1056 | "description": "Location adjacent to an inline fragment.", 1057 | "isDeprecated": false, 1058 | "deprecationReason": null 1059 | }, 1060 | { 1061 | "name": "SCHEMA", 1062 | "description": "Location adjacent to a schema definition.", 1063 | "isDeprecated": false, 1064 | "deprecationReason": null 1065 | }, 1066 | { 1067 | "name": "SCALAR", 1068 | "description": "Location adjacent to a scalar definition.", 1069 | "isDeprecated": false, 1070 | "deprecationReason": null 1071 | }, 1072 | { 1073 | "name": "OBJECT", 1074 | "description": "Location adjacent to an object type definition.", 1075 | "isDeprecated": false, 1076 | "deprecationReason": null 1077 | }, 1078 | { 1079 | "name": "FIELD_DEFINITION", 1080 | "description": "Location adjacent to a field definition.", 1081 | "isDeprecated": false, 1082 | "deprecationReason": null 1083 | }, 1084 | { 1085 | "name": "ARGUMENT_DEFINITION", 1086 | "description": "Location adjacent to an argument definition.", 1087 | "isDeprecated": false, 1088 | "deprecationReason": null 1089 | }, 1090 | { 1091 | "name": "INTERFACE", 1092 | "description": "Location adjacent to an interface definition.", 1093 | "isDeprecated": false, 1094 | "deprecationReason": null 1095 | }, 1096 | { 1097 | "name": "UNION", 1098 | "description": "Location adjacent to a union definition.", 1099 | "isDeprecated": false, 1100 | "deprecationReason": null 1101 | }, 1102 | { 1103 | "name": "ENUM", 1104 | "description": "Location adjacent to an enum definition.", 1105 | "isDeprecated": false, 1106 | "deprecationReason": null 1107 | }, 1108 | { 1109 | "name": "ENUM_VALUE", 1110 | "description": "Location adjacent to an enum value definition.", 1111 | "isDeprecated": false, 1112 | "deprecationReason": null 1113 | }, 1114 | { 1115 | "name": "INPUT_OBJECT", 1116 | "description": "Location adjacent to an input object type definition.", 1117 | "isDeprecated": false, 1118 | "deprecationReason": null 1119 | }, 1120 | { 1121 | "name": "INPUT_FIELD_DEFINITION", 1122 | "description": "Location adjacent to an input object field definition.", 1123 | "isDeprecated": false, 1124 | "deprecationReason": null 1125 | } 1126 | ], 1127 | "possibleTypes": null 1128 | }, 1129 | { 1130 | "kind": "SCALAR", 1131 | "name": "Upload", 1132 | "description": "The `Upload` scalar type represents a file upload promise that resolves an object containing `stream`, `filename`, `mimetype` and `encoding`.", 1133 | "fields": null, 1134 | "inputFields": null, 1135 | "interfaces": null, 1136 | "enumValues": null, 1137 | "possibleTypes": null 1138 | } 1139 | ], 1140 | "directives": [ 1141 | { 1142 | "name": "skip", 1143 | "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", 1144 | "locations": [ 1145 | "FIELD", 1146 | "FRAGMENT_SPREAD", 1147 | "INLINE_FRAGMENT" 1148 | ], 1149 | "args": [ 1150 | { 1151 | "name": "if", 1152 | "description": "Skipped when true.", 1153 | "type": { 1154 | "kind": "NON_NULL", 1155 | "name": null, 1156 | "ofType": { 1157 | "kind": "SCALAR", 1158 | "name": "Boolean", 1159 | "ofType": null 1160 | } 1161 | }, 1162 | "defaultValue": null 1163 | } 1164 | ] 1165 | }, 1166 | { 1167 | "name": "include", 1168 | "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", 1169 | "locations": [ 1170 | "FIELD", 1171 | "FRAGMENT_SPREAD", 1172 | "INLINE_FRAGMENT" 1173 | ], 1174 | "args": [ 1175 | { 1176 | "name": "if", 1177 | "description": "Included when true.", 1178 | "type": { 1179 | "kind": "NON_NULL", 1180 | "name": null, 1181 | "ofType": { 1182 | "kind": "SCALAR", 1183 | "name": "Boolean", 1184 | "ofType": null 1185 | } 1186 | }, 1187 | "defaultValue": null 1188 | } 1189 | ] 1190 | }, 1191 | { 1192 | "name": "deprecated", 1193 | "description": "Marks an element of a GraphQL schema as no longer supported.", 1194 | "locations": [ 1195 | "FIELD_DEFINITION", 1196 | "ENUM_VALUE" 1197 | ], 1198 | "args": [ 1199 | { 1200 | "name": "reason", 1201 | "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted in [Markdown](https://daringfireball.net/projects/markdown/).", 1202 | "type": { 1203 | "kind": "SCALAR", 1204 | "name": "String", 1205 | "ofType": null 1206 | }, 1207 | "defaultValue": "\"No longer supported\"" 1208 | } 1209 | ] 1210 | } 1211 | ] 1212 | } 1213 | } 1214 | } --------------------------------------------------------------------------------