zazuko / query-rdf-data-cube

Explore or query RDF Data Cubes with a JavaScript API, without writing SPARQL.
https://zazuko.github.io/query-rdf-data-cube/
9 stars 2 forks source link

Bundle size #10

Closed jstcki closed 5 years ago

jstcki commented 5 years ago

I saw that you're using fetch-sparql-endpoint as a dependency which is a quite large dependency to have in the frontend (https://bundlephobia.com/result?p=fetch-sparql-endpoint@1.4.0), in part because it bundles polyfills that one already may have in their bundle anyway. If I understand correctly, the main benefit is that it supports streaming and other response formats than json – which seems quite unnecessary for our use-case where queries are always using SELECT and requested as application/sparql-results+json. Also, the API for this library is promises/async/await (which is good because simple!), so the potential streaming benefit is kind of lost.

So I wonder if it's necessary to depend on a library which adds a lot of baggage which could (at the moment at least) be replaced with a simple fetch() call. Which is what I've been using so far.

But maybe you have plans for full streaming support or there's something else I missed. Would love to hear your thoughts on this.

vhf commented 5 years ago

Full streaming support is not on the roadmap, your suggestion makes a lot of sense.

Without a closer look I have no idea how much work replacing fetch-sparql-endpoint would require but that's something I'll seriously consider later on.

jstcki commented 5 years ago

FWIW, I used this code which I adapted from https://github.com/zazuko/d3-sparql

const xmlSchema = "http://www.w3.org/2001/XMLSchema#";

/**
 * See https://www.w3.org/TR/2013/REC-sparql11-results-json-20130321/#select-encode-terms
 */
type RDFTerm =
  | {
      type: "uri";
      value: string;
    }
  | { type: "literal"; value: string }
  | { type: "literal"; value: string; "xml:lang": string }
  | { type: "literal"; value: string; datatype: string }
  | { type: "bnode"; value: string };

export type Result = Record<string, string | number | boolean | Date>;

export async function fetchSparql(endpoint: string, query: string) {
  const url = endpoint + "?query=" + encodeURIComponent(query);

  const sparql = fetch(url, {
    method: "GET",
    headers: {
      Accept: "application/sparql-results+json"
    }
  })
    .then(r => r.json())
    .then(body => {
      if (!body.results) {
        throw Error(body.message);
      }

      const results: Result[] = body.results.bindings.map(function(
        row: Record<string, RDFTerm>
      ) {
        var rowObject: Result = {};

        Object.keys(row).forEach(column => {
          rowObject[column] = dataTypeCasting(row[column]);
        });
        return rowObject;
      });

      return results;
    });

  return sparql;
}

function dataTypeCasting(value: RDFTerm) {
  const v = value.value;
  if ("datatype" in value) {
    var dt = value.datatype.replace(xmlSchema, "");
    switch (dt) {
      case "string":
        return v;
      case "boolean":
        return v === "true" ? true : false;
      case "float":
      case "integer":
      case "long":
      case "double":
      case "decimal":
      case "nonPositiveInteger":
      case "nonNegativeInteger":
      case "negativeInteger":
      case "int":
      case "unsignedLong":
      case "positiveInteger":
      case "short":
      case "unsignedInt":
      case "byte":
      case "unsignedShort":
      case "unsignedByte":
        return +v;
      case "date":
      case "time":
      case "dateTime":
        return new Date(v);
      default:
        return v;
    }
  }
  return v;
}
vhf commented 5 years ago

I'll tackle this next. I had issues with big queries sent as a URL query, request header too large.

Replacing this lib would allow us to use POST instead of GET only, and as you mentioned it should keep the bundle size in check.

vhf commented 5 years ago

Fixed: 00ab2a6