UNPKG

sparql-http-client

Version:
219 lines (195 loc) 6.83 kB
import defaultFetch from 'nodeify-fetch' import mergeHeaders from './lib/mergeHeaders.js' import mergeParameters from './lib/mergeParameters.js' import RawQuery from './RawQuery.js' /** * A client implementation based on {@link RawQuery} that prepares URLs and headers for SPARQL queries and returns the * raw fetch response. It does not provide a store interface. * * @property {RawQuery} query * @property {string} endpointUrl * @property {RawQuery} factory * @property {factory} fetch * @property {Headers} headers * @property {string} password * @property {Object} parameters * @property {string} storeUrl * @property {string} updateUrl * @property {string} user * @property {string} updateUrl * * @example * // read the height of the Eiffel Tower from Wikidata with a SELECT query * * import SparqlClient from 'sparql-http-client/SimpleClient.js' * * const endpointUrl = 'https://query.wikidata.org/sparql' * const query = ` * PREFIX wd: <http://www.wikidata.org/entity/> * PREFIX p: <http://www.wikidata.org/prop/> * PREFIX ps: <http://www.wikidata.org/prop/statement/> * PREFIX pq: <http://www.wikidata.org/prop/qualifier/> * * SELECT ?value WHERE { * wd:Q243 p:P2048 ?height. * * ?height pq:P518 wd:Q24192182; * ps:P2048 ?value . * }` * * const client = new SparqlClient({ endpointUrl }) * const res = await client.query.select(query) * * if (!res.ok) { * return console.error(res.statusText) * } * * const content = await res.json() * * console.log(JSON.stringify(content, null, 2)) */ class SimpleClient { /** * @param {Object} options * @param {string} [options.endpointUrl] SPARQL query endpoint URL * @param {factory} [options.factory] RDF/JS factory * @param {fetch} [options.fetch=nodeify-fetch] fetch implementation * @param {Headers} [options.headers] headers sent with every request * @param {string} [options.password] password used for basic authentication * @param {Object} [options.parameters] parameters sent with every request * @param {string} [options.storeUrl] SPARQL Graph Store URL * @param {string} [options.updateUrl] SPARQL update endpoint URL * @param {string} [options.user] user used for basic authentication * @param {Query} [options.Query] Constructor of a query implementation * @param {Store} [options.Store] Constructor of a store implementation */ constructor ({ endpointUrl, factory, fetch = defaultFetch, headers, parameters, password, storeUrl, updateUrl, user, Query = RawQuery, Store }) { if (!endpointUrl && !storeUrl && !updateUrl) { throw new Error('no endpointUrl, storeUrl, or updateUrl given') } this.endpointUrl = endpointUrl this.factory = factory this.fetch = fetch this.headers = new Headers(headers) this.parameters = parameters this.password = password this.storeUrl = storeUrl this.updateUrl = updateUrl this.user = user this.query = Query ? new Query({ client: this }) : null this.store = Store ? new Store({ client: this }) : null if (typeof user === 'string' && typeof password === 'string') { this.headers.set('authorization', `Basic ${btoa(`${user}:${password}`)}`) } } /** * Sends a GET request as defined in the * {@link https://www.w3.org/TR/2013/REC-sparql11-protocol-20130321/#query-via-get SPARQL Protocol specification}. * * @param {string} query SPARQL query * @param {Object} options * @param {Headers} [options.headers] additional request headers * @param {Object} [options.parameters] additional request parameters * @param {boolean} [options.update=false] send the request to the updateUrl * @return {Promise<Response>} */ async get (query, { headers, parameters, update = false } = {}) { let url = null if (!update) { url = new URL(this.endpointUrl) url.searchParams.append('query', query) } else { url = new URL(this.updateUrl) url.searchParams.append('update', query) } parameters = mergeParameters(this.parameters, parameters) for (const [key, value] of parameters.entries()) { url.searchParams.append(key, value) } return this.fetch(url.toString().replace(/\+/g, '%20'), { method: 'GET', headers: mergeHeaders(this.headers, headers) }) } /** * Sends a POST directly request as defined in the * {@link https://www.w3.org/TR/2013/REC-sparql11-protocol-20130321/#query-via-post-direct SPARQL Protocol specification}. * * * @param {string} query SPARQL query * @param {Object} options * @param {Headers} [options.headers] additional request headers * @param {Object} [options.parameters] additional request parameters * @param {boolean} [options.update=false] send the request to the updateUrl * @return {Promise<Response>} */ async postDirect (query, { headers, parameters, update = false } = {}) { let url = null if (!update) { url = new URL(this.endpointUrl) } else { url = new URL(this.updateUrl) } headers = mergeHeaders(this.headers, headers) if (!headers.has('content-type')) { headers.set('content-type', 'application/sparql-query; charset=utf-8') } parameters = mergeParameters(this.parameters, parameters) for (const [key, value] of parameters.entries()) { url.searchParams.append(key, value) } return this.fetch(url, { method: 'POST', headers, body: query }) } /** * Sends a POST URL-encoded request as defined in the * {@link https://www.w3.org/TR/2013/REC-sparql11-protocol-20130321/#query-via-post-urlencoded SPARQL Protocol specification}. * * @param {string} query SPARQL query * @param {Object} options * @param {Headers} [options.headers] additional request headers * @param {Object} [options.parameters] additional request parameters * @param {boolean} [options.update=false] send the request to the updateUrl * @return {Promise<Response>} */ async postUrlencoded (query, { headers, parameters, update = false } = {}) { let url = null const body = new URLSearchParams() if (!update) { url = new URL(this.endpointUrl) body.append('query', query) } else { url = new URL(this.updateUrl) body.append('update', query) } headers = mergeHeaders(this.headers, headers) if (!headers.has('content-type')) { headers.set('content-type', 'application/x-www-form-urlencoded') } parameters = mergeParameters(this.parameters, parameters) for (const [key, value] of parameters.entries()) { body.append(key, value) } return this.fetch(url, { method: 'POST', headers, body: body.toString() }) } } export default SimpleClient