From 7d65a21c1df7eb2bf6cc4828cfb4572bed4cd846 Mon Sep 17 00:00:00 2001 From: Yarmo Mackenbach Date: Sun, 19 Mar 2023 09:51:45 +0100 Subject: [PATCH] feat: Add GraphQL fetcher --- src/enums.js | 2 ++ src/fetcher/graphql.js | 80 ++++++++++++++++++++++++++++++++++++++++++ src/fetcher/index.js | 1 + 3 files changed, 83 insertions(+) create mode 100644 src/fetcher/graphql.js diff --git a/src/enums.js b/src/enums.js index 6fa25e4..f36155f 100644 --- a/src/enums.js +++ b/src/enums.js @@ -43,6 +43,8 @@ const Fetcher = { ACTIVITYPUB: 'activitypub', /** DNS module from Node.js */ DNS: 'dns', + /** GraphQL over HTTP requests */ + GRAPHQL: 'graphql', /** Basic HTTP requests */ HTTP: 'http', /** IRC module from Node.js */ diff --git a/src/fetcher/graphql.js b/src/fetcher/graphql.js new file mode 100644 index 0000000..8b14e6e --- /dev/null +++ b/src/fetcher/graphql.js @@ -0,0 +1,80 @@ +/* +Copyright 2023 Yarmo Mackenbach + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +const axios = require('axios') + +/** + * @module fetcher/graphql + */ + +/** + * The request's timeout value in milliseconds + * @constant {number} timeout + */ +module.exports.timeout = 5000 + +/** + * Execute a GraphQL query via HTTP request + * @function + * @async + * @param {object} data - Data used in the request + * @param {string} data.url - The URL pointing at the GraphQL HTTP endpoint + * @param {string} data.query - The GraphQL query to fetch the data containing the proof + * @returns {object|string} + */ +module.exports.fn = async (data, opts) => { + let timeoutHandle + const timeoutPromise = new Promise((resolve, reject) => { + timeoutHandle = setTimeout( + () => reject(new Error('Request was timed out')), + data.fetcherTimeout ? data.fetcherTimeout : module.exports.timeout + ) + }) + + const fetchPromise = new Promise((resolve, reject) => { + if (!data.url) { + reject(new Error('No valid URI provided')) + return + } + + let jsonData + try { + jsonData = JSON.parse(data.query) + } catch (error) { + reject(new Error('Invalid GraphQL query object')) + } + + axios.post(data.url, jsonData, { + headers: { + 'Content-Type': 'application/json', + 'User-Agent': `doipjs/${require('../../package.json').version}` + }, + validateStatus: function (status) { + return status >= 200 && status < 400 + } + }) + .then(res => { + resolve(res.data) + }) + .catch(e => { + reject(e) + }) + }) + + return Promise.race([fetchPromise, timeoutPromise]).then((result) => { + clearTimeout(timeoutHandle) + return result + }) +} diff --git a/src/fetcher/index.js b/src/fetcher/index.js index b188251..dcaa36e 100644 --- a/src/fetcher/index.js +++ b/src/fetcher/index.js @@ -16,6 +16,7 @@ limitations under the License. exports.activitypub = require('./activitypub') exports.dns = require('./dns') +exports.graphql = require('./graphql') exports.http = require('./http') exports.irc = require('./irc') exports.matrix = require('./matrix')