├── .gitignore
├── README.md
├── examples
├── countriesFlow.json
└── githubLogin.json
├── graphql.html
├── graphql.js
├── graphql.png
├── images
├── customHeaders.png
├── editGraphQL.png
├── flow.png
├── flowOutput.png
├── githubFlow.png
├── githubGraphql.png
└── githubGraphqlConfig.png
├── locales
└── en-US
│ └── graphql.json
├── package-lock.json
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | *~
3 | .DS_Store
4 | .history
5 | icons
6 | node_modules
7 | .vscode
8 | temp.json
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # node-red-contrib-graphql
2 |
3 | [](https://nodered.org)
4 | 
5 | 
6 | [](https://www.codacy.com/gh/rgstephens/node-red-contrib-graphql?utm_source=github.com&utm_medium=referral&utm_content=rgstephens/node-red-contrib-graphql&utm_campaign=Badge_Grade)
7 |
8 | A NodeRed node to execute GraphQL Queries.
9 |
10 | ## Change Log
11 |
12 | | Vers | Changes |
13 | | ----- | -------------------------------------------------------- |
14 | | 2.2.0 | Really fix payload issue |
15 | | 2.1.2 | Fix payload init issue |
16 | | 2.1.0 | Bearer Token Authentication |
17 | | 2.0.1 | Update dependencies (`axios` & `mustache`), fix node-red scorecard issues |
18 | | 2.0.0 | GraphQL response is now on `payload.graphql` instead of replacing `payload`. This is a breaking change. Addresses #32 |
19 | | 1.4.1 | Bump `follow-redirects` to 1.14.8 |
20 | | 1.4.0 | improve debug, bump `follow-redirects` |
21 | | 1.3.0 | bump axios to address CVE-2021-3749 |
22 | | 1.2.0 | [Fix node not showing in palette](https://github.com/rgstephens/node-red-contrib-graphql/pull/24), bump axios |
23 | | 1.1.0 | [Error Handling & Config Templates](https://github.com/rgstephens/node-red-contrib-graphql/pull/11/), [showDebug & customHeaders](https://github.com/rgstephens/node-red-contrib-graphql/pull/22/conflicts), [Bump axios](https://github.com/rgstephens/node-red-contrib-graphql/pull/20) |
24 | | 1.0.0 | pass Authorization via msg.authorization, [PR #21](https://github.com/rgstephens/node-red-contrib-graphql/pull/21)|
25 | | 0.0.6 | Initial Release |
26 |
27 | ## GraphQL Nodes
28 |
29 | Provides a `GraphQL` node to support queries and a configuration node called `graphql-server`.
30 |
31 | ### `graphql-server` Configuration Node Fields
32 |
33 | | Name | Use |
34 | | -------- | ------------------- |
35 | | Name | Node Name |
36 | | Endpoint | URL to the endpoint |
37 | | Token | Bearer Token |
38 |
39 | ### `graphql` Function Node Fields
40 |
41 | | Name | Use |
42 | | ---------- | -------------------------- |
43 | | Name | Node Name |
44 | | Endpoint | Configuration Node Name |
45 | | Query | Query or Mutation template |
46 | | Syntax | Mustache / plain |
47 | | Token | Bearer Token |
48 | | Show Debug | Enable debug |
49 |
50 | ## Countries API Example
51 |
52 | This example flow uses the `node-red-contrib-graphql` node to query the [Countries API](https://github.com/trevorblades/countries) built by GitHub user [Trevor Blades](https://github.com/trevorblades).
53 |
54 | The example flow is in the file `examples/countries.json`. Import this file from the clipboard under the NodeRed menu `Import > Clipboard`. You'll drag the example flow onto NodeRed.
55 |
56 | 
57 |
58 | ### Edit graphql node
59 |
60 | The GraphQL endpoint for is `https://countries.trevorblades.com/`. You can try it out [here](https://countries.trevorblades.com/). Here's the `graphql-node`:
61 |
62 | 
63 |
64 | ### GraphQL Output
65 |
66 | This is the result sent to the debug window.
67 |
68 | 
69 |
70 | ## Authentication Example
71 |
72 | A bearer token can be provided for authentication. This is an example using the GitHub GraphQL API which is documented [here](https://docs.github.com/en/graphql/guides/forming-calls-with-graphql#communicating-with-graphql).
73 |
74 | 
75 |
76 | ### Config Node Token
77 |
78 | If you have an token with a long life, you can provide the token in the `graphql-server` configuration node. For GitHub, user your GitHub PAT.
79 |
80 | 
81 |
82 | You can also provide the token in the `graphql` node. This is useful if a prior node performs the authentication and returns the token to be used for a limited session.
83 |
84 | 
85 |
86 | ## Custom Headers
87 |
88 | You can provide custom headers to the GraphQL node by attaching a `customHeaders` key to the `msg` and passing that to the GraphQL node. Here's an example that sets the `content-type` and a bearer token.
89 |
90 | 
91 |
92 | ## Templates and Variable Use
93 |
94 | There are two template flavors:
95 |
96 | 1. Plain
97 | 2. Mustache
98 |
99 | At the bottom of the template text area, you must select between plain or mustache template.
100 |
101 | If you select mustache, your template will be processed by Mustache with the message's payload as an argument. I.e.
102 |
103 | ```
104 | submitted_template = mustache("template in text area", msg.payload)
105 | ```
106 |
107 | If you select plain, the template is left as it is.
108 |
109 | ### Template variables
110 |
111 | You can add GraphQL query variables to the submitted query by defining them in the `msg.variables` property.
112 | Your variables will be passed over to the GraphQL query.
113 |
114 | For example, if you define
115 |
116 | ```
117 | type Response {
118 | ok: boolean
119 | }
120 |
121 | input doSomethingInput {
122 | myVar: String
123 | }
124 |
125 | type Mutation {
126 | doSomething(input: doSomethingInput!): Response
127 | }
128 |
129 | ```
130 |
131 | you can pass the `messageInput` parameter as such in Node-Red msg:
132 |
133 | ```
134 | msg.variables = {
135 | "input": {
136 | "myVar": "myValue"
137 | }
138 | }
139 | ```
140 |
141 | it will be added to the GraphQL query:
142 |
143 | ```
144 | query: `mutation doSomething($input: messageInput!) {
145 | doSomething(input: $input) {
146 | ok
147 | }
148 | }`,
149 | variables: {
150 | input: {
151 | myVar: "myValue"
152 | }
153 | }
154 | ```
155 |
156 | When using a scalar type like [JSON](https://github.com/taion/graphql-type-json), the entire payload can conveniently be
157 | passed as an input parameter:
158 |
159 | ```
160 | scalar JSON
161 |
162 | type Response {
163 | ok: boolean
164 | }
165 |
166 | input payloadInput {
167 | payload: JSON
168 | }
169 |
170 | type Mutation {
171 | doSomething(input: payloadInput!): Response
172 | }
173 |
174 | ```
175 |
176 | In node-red flow, prepare `payloadInput` variables:
177 |
178 | ```
179 | msg.variables = {
180 | "input": {
181 | "payload": msg.payload
182 | }
183 | }
184 | ```
185 |
186 | which will results in
187 |
188 | ```
189 | query: `mutation doSomething($input: payloadInput!) {
190 | doSomething(input: $input) {
191 | ok
192 | }
193 | }`,
194 | variables: {
195 | input: {
196 | myVar: { whatever: "was in you msg.payload", val: 5, bool: true }
197 | }
198 | }
199 | ```
200 |
201 | The execution will return the value in:
202 |
203 | ```
204 | msg.payload.doSomething
205 | ```
206 |
207 | object.
208 |
209 | ### Outputs
210 |
211 | `payload` is loaded with the output of the Query or Mutation. If the Query is named `doSomething`, the results of the query will be in `payload.doSomething`.
212 |
213 | ```
214 | //msg.payload is:
215 | {
216 | doSomething: {
217 | ok: true
218 | }
219 | }
220 | ```
221 |
--------------------------------------------------------------------------------
/examples/countriesFlow.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "a12eeec2ef7081f3",
4 | "type": "graphql",
5 | "z": "e596e2e15cffe546",
6 | "name": "Get Country",
7 | "graphql": "5ec8b7409ad68ba9",
8 | "format": "json",
9 | "syntax": "mustache",
10 | "template": "{\n country(code: \"DE\") {\n name\n native\n capital\n currency\n phone\n states {\n code\n name\n }\n }\n}",
11 | "showDebug": false,
12 | "x": 290,
13 | "y": 80,
14 | "wires": [
15 | [
16 | "b1909e0fe42ed002",
17 | "b4a00ddbf587d5db"
18 | ],
19 | [
20 | "b4a00ddbf587d5db"
21 | ]
22 | ]
23 | },
24 | {
25 | "id": "8ce305107f24099c",
26 | "type": "inject",
27 | "z": "e596e2e15cffe546",
28 | "name": "",
29 | "props": [
30 | {
31 | "p": "payload"
32 | },
33 | {
34 | "p": "topic",
35 | "vt": "str"
36 | }
37 | ],
38 | "repeat": "",
39 | "crontab": "",
40 | "once": false,
41 | "onceDelay": 0.1,
42 | "topic": "",
43 | "payload": "",
44 | "payloadType": "date",
45 | "x": 100,
46 | "y": 80,
47 | "wires": [
48 | [
49 | "a12eeec2ef7081f3"
50 | ]
51 | ]
52 | },
53 | {
54 | "id": "b4a00ddbf587d5db",
55 | "type": "debug",
56 | "z": "e596e2e15cffe546",
57 | "name": "",
58 | "active": true,
59 | "tosidebar": true,
60 | "console": false,
61 | "tostatus": false,
62 | "complete": "true",
63 | "targetType": "full",
64 | "statusVal": "",
65 | "statusType": "auto",
66 | "x": 490,
67 | "y": 100,
68 | "wires": []
69 | },
70 | {
71 | "id": "b1909e0fe42ed002",
72 | "type": "template",
73 | "z": "e596e2e15cffe546",
74 | "name": "Country Details",
75 | "field": "payload",
76 | "fieldType": "msg",
77 | "format": "handlebars",
78 | "syntax": "mustache",
79 | "template": "Country Name - {{payload.graphql.country.name}} / {{payload.graphql.country.native}}\nCapital: {{payload.graphql.country.capital}}\nCurrency: {{payload.graphql.country.currency}}\nStates:\n {{payload.graphql.country.states.0.name}}\n {{payload.graphql.country.states.1.name}}\n {{payload.graphql.country.states.2.name}}\n {{payload.graphql.country.states.3.name}}\n",
80 | "output": "str",
81 | "x": 520,
82 | "y": 60,
83 | "wires": [
84 | [
85 | "080fbc2ad4668f85"
86 | ]
87 | ]
88 | },
89 | {
90 | "id": "080fbc2ad4668f85",
91 | "type": "debug",
92 | "z": "e596e2e15cffe546",
93 | "name": "",
94 | "active": true,
95 | "tosidebar": true,
96 | "console": false,
97 | "complete": "false",
98 | "statusVal": "",
99 | "statusType": "auto",
100 | "x": 730,
101 | "y": 60,
102 | "wires": []
103 | },
104 | {
105 | "id": "5ec8b7409ad68ba9",
106 | "type": "graphql-server",
107 | "name": "Countries",
108 | "endpoint": "https://countries.trevorblades.com"
109 | }
110 | ]
--------------------------------------------------------------------------------
/examples/githubLogin.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id": "cc97ba59b7f7b1c6",
4 | "type": "inject",
5 | "z": "ecee231023f6944e",
6 | "name": "",
7 | "props": [
8 | {
9 | "p": "payload"
10 | },
11 | {
12 | "p": "topic",
13 | "vt": "str"
14 | }
15 | ],
16 | "repeat": "",
17 | "crontab": "",
18 | "once": false,
19 | "onceDelay": 0.1,
20 | "topic": "",
21 | "payload": "",
22 | "payloadType": "date",
23 | "x": 160,
24 | "y": 140,
25 | "wires": [
26 | [
27 | "5ce1d5e8c233c062"
28 | ]
29 | ]
30 | },
31 | {
32 | "id": "5ce1d5e8c233c062",
33 | "type": "graphql",
34 | "z": "ecee231023f6944e",
35 | "name": "Get Login id",
36 | "graphql": "4a27e34566452125",
37 | "format": "handlebars",
38 | "template": "{\n viewer {\n login\n }\n}",
39 | "syntax": "mustache",
40 | "token": "",
41 | "showDebug": false,
42 | "credentials": {},
43 | "x": 350,
44 | "y": 140,
45 | "wires": [
46 | [
47 | "fe44bcf58ee82812"
48 | ],
49 | [
50 | "35a20afebf41f631"
51 | ]
52 | ]
53 | },
54 | {
55 | "id": "fe44bcf58ee82812",
56 | "type": "debug",
57 | "z": "ecee231023f6944e",
58 | "name": "",
59 | "active": true,
60 | "tosidebar": true,
61 | "console": false,
62 | "tostatus": false,
63 | "complete": "payload.graphql.viewer.login",
64 | "targetType": "msg",
65 | "statusVal": "",
66 | "statusType": "auto",
67 | "x": 660,
68 | "y": 120,
69 | "wires": []
70 | },
71 | {
72 | "id": "35a20afebf41f631",
73 | "type": "debug",
74 | "z": "ecee231023f6944e",
75 | "name": "",
76 | "active": true,
77 | "tosidebar": true,
78 | "console": false,
79 | "tostatus": false,
80 | "complete": "true",
81 | "targetType": "full",
82 | "statusVal": "",
83 | "statusType": "auto",
84 | "x": 570,
85 | "y": 160,
86 | "wires": []
87 | },
88 | {
89 | "id": "4a27e34566452125",
90 | "type": "graphql-server",
91 | "name": "GitHub",
92 | "endpoint": "https://api.github.com/graphql",
93 | "token": ""
94 | }
95 | ]
--------------------------------------------------------------------------------
/graphql.html:
--------------------------------------------------------------------------------
1 |
15 |
16 |
35 |
36 |
82 |
83 |
174 |
175 |
--------------------------------------------------------------------------------
/graphql.js:
--------------------------------------------------------------------------------
1 | module.exports = function(RED) {
2 | // https://github.com/axios/axios
3 | var axios = require("axios");
4 | var mustache = require("mustache");
5 |
6 | var vers = "2.2.0";
7 |
8 | function isReadable(value) {
9 | return typeof value === 'object' && typeof value._read === 'function' && typeof value._readableState === 'object'
10 | }
11 |
12 | function safeJSONStringify(input, maxDepth) {
13 | var output,
14 | refs = [],
15 | refsPaths = [];
16 |
17 | maxDepth = maxDepth || 5;
18 |
19 | function recursion(input, path, depth) {
20 | var output = {},
21 | pPath,
22 | refIdx;
23 |
24 | path = path || "";
25 | depth = depth || 0;
26 | depth++;
27 |
28 | if (maxDepth && depth > maxDepth) {
29 | return "{depth over " + maxDepth + "}";
30 | }
31 |
32 | for (var p in input) {
33 | pPath = (path ? path + "." : "") + p;
34 | if (typeof input[p] === "function") {
35 | output[p] = "{function}";
36 | } else if (input[p] && Buffer.isBuffer(input[p])) {
37 | output[p] = "[object Buffer]";
38 | } else if (input[p] && isReadable(input[p])) {
39 | output[p] = "[object Readable]";
40 | } else if (typeof input[p] === "object") {
41 | refIdx = refs.indexOf(input[p]);
42 |
43 | if (-1 !== refIdx) {
44 | output[p] = "{reference to " + refsPaths[refIdx] + "}";
45 | } else {
46 | refs.push(input[p]);
47 | refsPaths.push(pPath);
48 | output[p] = recursion(input[p], pPath, depth);
49 | }
50 | } else {
51 | output[p] = input[p];
52 | }
53 | }
54 |
55 | return output;
56 | }
57 |
58 | if (typeof input === "object") {
59 | output = recursion(input);
60 | } else {
61 | output = input;
62 | }
63 |
64 | return JSON.stringify(output);
65 | }
66 |
67 | function GraphqlNode(config) {
68 | RED.nodes.createNode(this, config);
69 | var node = this;
70 |
71 | RED.log.debug("--- GraphqlNode v" + vers + " ---");
72 | RED.log.debug("GraphqlNode node: " + safeJSONStringify(node));
73 | RED.log.trace("GraphqlNode config: " + safeJSONStringify(config));
74 | node.endpoint = config.endpoint;
75 | node.token = config.token
76 | RED.log.debug("node.endpoint: " + node.endpoint);
77 | RED.log.debug("node.token: " + node.token)
78 | }
79 |
80 | RED.nodes.registerType("graphql-server", GraphqlNode, {
81 | credentials: {
82 | token: { type: "password" },
83 | }
84 | });
85 |
86 | function GraphqlExecNode(config) {
87 | RED.nodes.createNode(this, config);
88 | var node = this;
89 |
90 | node.graphqlConfig = RED.nodes.getNode(config.graphql); // Retrieve the config node
91 |
92 | node.template = config.template;
93 | node.name = config.name;
94 | node.varsField = config.varsField || "variables";
95 | node.syntax = config.syntax || "mustache";
96 | node.showDebug = config.showDebug || false
97 | node.token = node.credentials.token || "";
98 | node.customHeaders = config.customHeaders || {}
99 | node.varsField = config.varsField || "variables";
100 | RED.log.debug("--- GraphqlExecNode ---");
101 |
102 | if (!node.graphqlConfig) {
103 | node.error("invalid graphql config");
104 | }
105 |
106 | function dataobject(context, msg){
107 | data = {}
108 | data.msg = msg;
109 | data.global = {};
110 | data.flow = {};
111 | g_keys = context.global.keys();
112 | f_keys = context.flow.keys();
113 | for (k in g_keys){
114 | data.global[g_keys[k]] = context.global.get(g_keys[k]);
115 | };
116 | for (k in f_keys){
117 | data.flow[f_keys[k]] = context.flow.get(f_keys[k]);
118 | };
119 | return data
120 | }
121 |
122 | function callGraphQLServer(query, variables = {}, customHeaders = {}) {
123 | let data = dataobject(node.context(), node.msg);
124 | let url = mustache.render(node.graphqlConfig.endpoint, data);
125 | let headers = customHeaders
126 | const token = node.token || node.graphqlConfig.token || "";
127 | if (token) {
128 | headers["Authorization"] = `Bearer ${token}`
129 | }
130 |
131 | if (node.showDebug) {
132 | node.log(safeJSONStringify(data));
133 | node.log(headers.Authorization);
134 | }
135 |
136 | axios({
137 | method: "POST",
138 | url,
139 | headers,
140 | timeout: 20000,
141 | data: {
142 | query: query,
143 | variables: variables
144 | }
145 | })
146 | .then(function(response) {
147 | if (!node.msg.payload) node.msg.payload = {};
148 | switch (true) {
149 | case response.status == 200 && !response.data.errors:
150 | node.status({
151 | fill: "green",
152 | shape: "dot",
153 | text: RED._("graphql.status.success")
154 | });
155 | node.msg.payload.graphql = response.data.data; // remove .data to see entire response
156 | if (node.showDebug){
157 | node.msg.debugInfo = {
158 | data: response.data,
159 | headers,
160 | query,
161 | variables
162 | }
163 | }
164 | node.send(node.msg);
165 | break;
166 | case response.status == 200 && !!response.data.errors:
167 | node.status({
168 | fill: "yellow",
169 | shape: "dot",
170 | text: RED._("graphql.status.gqlError")
171 | });
172 | node.msg.payload.graphql = response.data.errors;
173 | node.send([null, node.msg]);
174 | break;
175 | default:
176 | node.status({
177 | fill: "red",
178 | shape: "dot",
179 | text: "status: " + response.status
180 | });
181 | node.msg.payload.graphql = {
182 | statusCode: response.status,
183 | body: response.data
184 | };
185 | node.send([null, node.msg]);
186 | break;
187 | }
188 | })
189 | .catch(function(error) {
190 | RED.log.debug("error:" + error);
191 | node.status({ fill: "red", shape: "dot", text: "error" });
192 | if (!node.msg.payload) node.msg.payload = {};
193 | node.msg.payload.graphql = { error };
194 | node.error("error: " + error);
195 | node.send([null, node.msg]);
196 | });
197 | }
198 |
199 | node.on("input", function(msg) {
200 | RED.log.debug("--- on(input) ---");
201 | RED.log.debug("msg: " + safeJSONStringify(msg));
202 | node.msg = msg;
203 | node.template = msg.template || node.template;
204 | node.syntax = msg.syntax || node.syntax;
205 | node.customHeaders = {...node.customHeaders, ...msg.customHeaders}
206 | var query;
207 | if (node.syntax === "mustache") {
208 | query = mustache.render(node.template, msg);
209 | } else {
210 | query = node.template;
211 | }
212 | var variables = msg[node.varsField] || {}
213 |
214 | callGraphQLServer(query, variables, node.customHeaders);
215 | });
216 |
217 | node.on("close", function() {
218 | RED.log.debug("--- closing node ---");
219 | node.graphqlConfig.credentials.token = node.token || "";
220 | RED.nodes.addCredentials(
221 | node.graphqlConfig,
222 | node.graphqlConfig.credentials
223 | );
224 | });
225 | }
226 |
227 | RED.nodes.registerType("graphql", GraphqlExecNode, {
228 | credentials: {
229 | token: { type: "password" },
230 | }
231 | });
232 | };
233 |
--------------------------------------------------------------------------------
/graphql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rgstephens/node-red-contrib-graphql/8c20aa77eccbdd08b89ece4e79bc8b081a87704b/graphql.png
--------------------------------------------------------------------------------
/images/customHeaders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rgstephens/node-red-contrib-graphql/8c20aa77eccbdd08b89ece4e79bc8b081a87704b/images/customHeaders.png
--------------------------------------------------------------------------------
/images/editGraphQL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rgstephens/node-red-contrib-graphql/8c20aa77eccbdd08b89ece4e79bc8b081a87704b/images/editGraphQL.png
--------------------------------------------------------------------------------
/images/flow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rgstephens/node-red-contrib-graphql/8c20aa77eccbdd08b89ece4e79bc8b081a87704b/images/flow.png
--------------------------------------------------------------------------------
/images/flowOutput.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rgstephens/node-red-contrib-graphql/8c20aa77eccbdd08b89ece4e79bc8b081a87704b/images/flowOutput.png
--------------------------------------------------------------------------------
/images/githubFlow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rgstephens/node-red-contrib-graphql/8c20aa77eccbdd08b89ece4e79bc8b081a87704b/images/githubFlow.png
--------------------------------------------------------------------------------
/images/githubGraphql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rgstephens/node-red-contrib-graphql/8c20aa77eccbdd08b89ece4e79bc8b081a87704b/images/githubGraphql.png
--------------------------------------------------------------------------------
/images/githubGraphqlConfig.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rgstephens/node-red-contrib-graphql/8c20aa77eccbdd08b89ece4e79bc8b081a87704b/images/githubGraphqlConfig.png
--------------------------------------------------------------------------------
/locales/en-US/graphql.json:
--------------------------------------------------------------------------------
1 | {
2 | "graphql": {
3 | "label": {
4 | "endpoint": "Endpoint",
5 | "syntax": "Syntax",
6 | "tokenplaceholder": "Token if required by API",
7 | "query": "Query",
8 | "mustache": "mustache",
9 | "plain": "plain",
10 | "apivers": "API Vers",
11 | "token": "Bearer Token",
12 | "showDebug": "Show Debug"
13 | },
14 | "status": {
15 | "calling": "calling",
16 | "success": "success",
17 | "gqlError": "graphql error",
18 | "failedConn": "Failed connection",
19 | "failed": "failed",
20 | "connecting": "connecting",
21 | "connected": "connected",
22 | "notLoggedIn": "Not logged in"
23 | },
24 | "errors": {
25 | "tokenExp": "Token has expired or is not good, re-logging in",
26 | "tokenExpLogin": "Token has expired or is not good, re-logging in",
27 | "badRest": "Bad REST endpoint, not a valid call",
28 | "error401": "401 error, calling close",
29 | "badCreds": "Bad credentials",
30 | "error404": "Bad REST endpoint, URL, resource not found",
31 | "error400": "resource not found",
32 | "alreadyLoggedOut": "already logged out?",
33 | "server": "Server not found",
34 | "timeout": "Timeout connecting to server, check port",
35 | "nouserid": "No e-mail userid set",
36 | "nopassword": "No e-mail password set",
37 | "nocredentials": "No Email credentials found. See info panel.",
38 | "nopayload": "No payload to send",
39 | "fetchfail": "Failed to fetch folder: __folder__",
40 | "messageerror": "Fetch message error: __error__"
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "node-red-contrib-graphql",
3 | "version": "2.2.0",
4 | "description": "A Node-RED node to make GraphQL calls",
5 | "dependencies": {
6 | "axios": "~1.2.1",
7 | "follow-redirects": "~1.15.2",
8 | "mustache": "~4.2.0"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "https://github.com/rgstephens/node-red-contrib-graphql"
13 | },
14 | "license": "Apache-2.0",
15 | "keywords": [
16 | "node-red",
17 | "graphql"
18 | ],
19 | "scripts": {
20 | "debug": "node /Users/greg/.nvm/versions/node/v14.16.1/lib/node_modules/node-red/red.js"
21 | },
22 | "node-red": {
23 | "version": ">=2",
24 | "nodes": {
25 | "graphql": "graphql.js"
26 | }
27 | },
28 | "author": {
29 | "name": "Greg Stephens",
30 | "email": "greg@udon.org",
31 | "url": "http://gstephens.org"
32 | },
33 | "engines": {
34 | "node": ">=12"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------