fix: Add content-negotiation when fetching dataset from url

* Solution works but tests don't

* refactor(FetchUtil): use arrayifyStream

* refactor(FetchUtil): split fetchDataset into 2 separate functions

* style(FetchUtil): onelining instead of declaring new local var

* test: trying to mock rdfDereferencer

* refactor: promise can't have async function as arg

* test(FetchUtil): pass Quad array to mockDereference instead

* test: all tests should pass now and coverage is back to 100%

* style: comment typo

* chore: make package.json and package-lock.json compatible with main

* chore: fix package.json double entries

* chore: updated package.json to be alfabetical again

* refactor(AgentGroupAccessChecker): Remove converter from contructor and config

* refactor(TokenOwnerShipValidator): Remove converter from constructor and config

* refactor(FetchUtil): Return BadRequestHttpError instead of generic Error

* test(FetchUtil): return Response object instead of mocking fetch

* style: typos and newlines
This commit is contained in:
Thomas Dupont
2022-02-15 13:44:03 +01:00
committed by GitHub
parent c5052625d1
commit ce754c119f
11 changed files with 113 additions and 85 deletions

View File

@@ -1,5 +1,8 @@
import type { Readable } from 'stream';
import type { Quad } from '@rdfjs/types';
import arrayifyStream from 'arrayify-stream';
import type { Response } from 'cross-fetch';
import { fetch } from 'cross-fetch';
import rdfDereferencer from 'rdf-dereference';
import { BasicRepresentation } from '../http/representation/BasicRepresentation';
import type { Representation } from '../http/representation/Representation';
import { getLoggerFor } from '../logging/LogUtil';
@@ -12,24 +15,32 @@ const logger = getLoggerFor('FetchUtil');
/**
* Fetches an RDF dataset from the given URL.
* Input can also be a Response if the request was already made.
*
* Response will be a Representation with content-type internal/quads.
*/
export async function fetchDataset(url: string): Promise<Representation> {
// Try content negotiation to parse quads from the URL
return (async(): Promise<Representation> => {
try {
const quadStream = (await rdfDereferencer.dereference(url)).quads as Readable;
const quadArray = await arrayifyStream(quadStream) as Quad[];
return new BasicRepresentation(quadArray, { path: url }, INTERNAL_QUADS, false);
} catch {
throw new BadRequestHttpError(`Could not parse resource at URL (${url})!`);
}
})();
}
/**
* Converts a given Response (from a request that was already made) to an RDF dataset.
* In case the given Response object was already parsed its body can be passed along as a string.
*
* The converter will be used to convert the response body to RDF.
*
* Response will be a Representation with content-type internal/quads.
*/
export async function fetchDataset(url: string, converter: RepresentationConverter): Promise<Representation>;
export async function fetchDataset(response: Response, converter: RepresentationConverter, body?: string):
Promise<Representation>;
export async function fetchDataset(input: string | Response, converter: RepresentationConverter, body?: string):
export async function responseToDataset(response: Response, converter: RepresentationConverter, body?: string):
Promise<Representation> {
let response: Response;
if (typeof input === 'string') {
response = await fetch(input);
} else {
response = input;
}
if (!body) {
body = await response.text();
}