Giter VIP home page Giter VIP logo

alcaeus's People

Contributors

dependabot-preview[bot] avatar dependabot[bot] avatar gitbook-bot avatar github-actions[bot] avatar joseferben avatar shnydercom avatar tpluscode avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

alcaeus's Issues

Adding @types

Hi, could you add types into the package itself or create them in @types/alcaeus ? Thanks

HydraResource.operations blows up when ApiDocumentation is missing

Actual behaviour

When there is no ApiDocumentation and I access the property operations on a HydrarResource, alcaeus fails with: TypeError: Cannot read property 'getOperations' of undefined.

Expected behaviour

When there is no ApiDocumentation and I access the property operations on a HydrarResource, alcaeus either

  • returns null and logs a warning
  • throws a named error with an appropriate message.

Notes

As a newcomer this shows that an API has to implement ApiDocumentation in order to conform to Hydra.

Root selector handling trailing slash or lack thereof

Need a root selector which will attempt to get the correct root for resource returned for a different URI, such as when the actual id does include a trailing slash and the requested URL did not

const rep = await client.loadResource('http://wikibus-test.gear.host/');

/*
{
  "@id": "http://wikibus-test.gear.host"
}
*/

// will be null
rep.root; 

// and should be same as
rep.get('http://wikibus-test.gear.host');

Server-side compatibility

I see this library relies on window.fetch, do you think we could safely switch to isomorphic-fetch to have the full support of server-side?

Handling literal values

Currently RDF literals are simply returned as strings regardless of the @type.

They should be out of the box transformed in their appropriate type and this mechanism should be extensible to allow custom data types to be handled

Implement manages block

The manages block let's the server inform the client what kind of members to expect within a collection. Not unlike generics in some languages like C#

class Person
{
    public string Name { get; set; }
    public string LastName { get; set; }
}

var friends = List<Person>();

Such could be equivalent to having the Person as supported class in the API Documentation and used with the collection's manages block

{
  "supportedClass": {
    "@id": "Person",
      "supportedProperty": [
        {
          "property": {
            "@id": "schema:givenName",
            "range": "xsd:string"
          },
        }
        {
          "property": {
            "@id": "schema:familyName",
            "range": "xsd:string"
          }
        }
      ]
  }
}
{
  "@id": "/friends",
  "@type": "Collection",
  "manages": {
    "subject": "/Tomasz",
    "property": "foaf:knows",
    "object": "Person"
  }
}

Inconsistent handling of URI escaping

Until 0.4.3 alcaeus attempted to escape resource identifiers to to avoid problems with internationalised URIs.

Turns out that this was done only partially, so effectively a graph would get split but breaking correspondence between JSON-LD objects. For example requesting http://example.com/with space would give the following in-memory object

{
  "@id": "http://example.com/with%20space",
  "next": {
    "@id": "http://example.com/with space"
  }
}

Noticing how the two identifiers are actually same but represented with different string, this could lead to wrong objects being returned from a resource.

The fix is to never escape ids, keeping them as returned by JSON-LD processor. Instead, they will be attempted to be escaped when getting a single resource so that the following code should return the same resource both times:

import { Hydra } from 'alcaeus';

const rep = await Hydra.loadResource('http://example.com/with space');

rep.get('http://example.com/with space');
rep.get('http://example.com/with%20space');

Error when use with webpack 2

Here is the error when I try to import heracles

Critical dependency: require function is used in a way in which dependencies cannot be statically extracted

Comparison with Heracles.ts

Hi, I'm really interested in using Hydra in a new project, but I'm having trouble figuring out the best frontend client library.

I've found this project and Heracles.ts, the "Reference implementation of a Hydra client in TypeScript."

I don't really have too much time to figure out the technical differences -- on first glance they seem very similar.

I'd really appreciate a quick explanation of the major differences. Thannks!

ping @tpluscode @alien-mcl

Enabling authentication with the API

It is necessary to allow app authors to authenticate against their API so that the calls can be properly authorised.

To do that, I'll want to provide a hook where the request can be modified before it goes to the server. This will be the point where consumers will add the Authorization header among other things.

Unable to import library in Node environment

Expected Behaviour
The following code (based on the project documentation) should not throw an error when run in a Node environment:

File src/index.js:

const { Hydra } = require('alcaeus')
console.log('testing')

Actual Behaviour
The command node src/index.js results in the following syntax error:

/Users/ejbyne/projects/json-ld/hydra-client-test/src/alcaeus.js:1
(function (exports, require, module, __filename, __dirname) { import { Hydra } from 'alcaeus'
                                                                     ^
SyntaxError: Unexpected token {
    at new Script (vm.js:79:7)
    at createScript (vm.js:251:10)
    at Object.runInThisContext (vm.js:303:10)
    at Module._compile (internal/modules/cjs/loader.js:656:28)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:699:10)
    at Module.load (internal/modules/cjs/loader.js:598:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:537:12)
    at Function.Module._load (internal/modules/cjs/loader.js:529:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:741:12)
    at startup (internal/bootstrap/node.js:285:19)

Workaround
The main entrypoint for the Alcaeus module is configured in package.json as lib/index.js. This code includes ES modules, which are not yet fully supported by Node. I would not expect to need to use Babel to compile my project's dependencies to ES5 (and also came across some problems when I tried to this).

The module is however already compiled to ES5 in the package's dist folder. I was able to get my code running by changing the import as follows:

const { Hydra } = require('alcaeus/dist/alcaeus')
console.log('testing')

Requested Fix
Either the above workaround should be made clear in the documentation or, preferably, the entrypoint for the module should point to Node-compatible code. It should not be necessary for the published code to include ES5, ES6 and TypeScript versions of the source code - ES5 alone should suffice.

** Context **
▶ npm -v
6.4.1
▶ node -v
v10.12.0
OS: Linux, MacOS

Reduce dependencies

Currently a full build, minified, bundling all dependencies is a whopping 632 KB!

This could be reduce by removing or replacing the dependency on:

  • lodash - 87 KB less
  • rdf-ext - 341 KB less
  • rdf-formats-common - 196 KB less

The easiest would be to replace lodash with native code or minimal polyfills.

I'm not sure whether there is a good alternative for rdf-ext at the moment. However, rdf-formats-common is a big packages and individual parsers and serializers could be loaded on demand.

Missing flag to check if property is a link

To simplify clients' implementation it will be beneficial to add a simple getter on the IRdfProperty mixin which returns true if a given property is a hydra:Link

This will be used to limit dereferncable (clickable) links in consumer applications for example when rendering the entrypoint or such as in hypermedia-app/generic.hypermedia.app#6

Performance improvements - make Alcaeus lazy

Currently Alcaeus is very eager to load and process everything it gets.

It works fine for small datasets but apparently the API exposed by @bergos has a large API doc with 4400+ resources. To process that takes over 40 seconds.

The bottleneck turns out to be a little needed function which finds reverse links between resources such as are not easily visible in a free structure. There are two ways to improve that:

  • Make it lazy and only called from resource objects when needed. This alone shaves off 90% of the time
  • Instead of processing JS objects use RDF Ext to run a simple query on the graph
  • Load API Documentation only the first time it is being requested

Unable to use with rollup

By importing hydra (import {Hydra} from 'alcaeus';) I get this error

[!] Error: 'promises' is not exported by node_modules/jsonld/lib/index.js
https://rollupjs.org/guide/en/#error-name-is-not-exported-by-module
node_modules/alcaeus/lib/es/MediaTypeProcessors/RdfProcessor.js (2:9)
1: import JsonLdSerializer from '@rdfjs/serializer-jsonld';
2: import { promises as jsonld } from 'jsonld';
            ^
3: import $rdf from 'rdf-ext';
4: import stringToStream from 'string-to-stream';
Error: 'promises' is not exported by node_modules/jsonld/lib/index.js
    at error (/app/node_modules/rollup/dist/shared/node-entry.js:5400:30)
    at Module.error (/app/node_modules/rollup/dist/shared/node-entry.js:9820:16)
    at handleMissingExport (/app/node_modules/rollup/dist/shared/node-entry.js:9721:28)
    at Module.traceVariable (/app/node_modules/rollup/dist/shared/node-entry.js:10159:24)
    at ModuleScope.findVariable (/app/node_modules/rollup/dist/shared/node-entry.js:8766:39)
    at FunctionScope.findVariable (/app/node_modules/rollup/dist/shared/node-entry.js:3065:38)
    at ChildScope.findVariable (/app/node_modules/rollup/dist/shared/node-entry.js:3065:38)
    at MemberExpression.bind (/app/node_modules/rollup/dist/shared/node-entry.js:6530:49)
    at CallExpression$1.bind (/app/node_modules/rollup/dist/shared/node-entry.js:3152:23)
    at CallExpression$1.bind (/app/node_modules/rollup/dist/shared/node-entry.js:6718:15)

Replication steps:

  1. Create new project yarn init
  2. Add rollup yarn add rollup @rollup/plugin-node-resolve @rollup/plugin-commonjs
  3. Create minimal rollup configuration file rollup.config.js with this content:
import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'

module.exports = {
  input: 'main.js',
  output: {
    file: 'bundle.js',
    format: 'es'
  },
  plugins: [ resolve({ browser: true }), commonjs() ]
};
  1. Create file to compile main.js:
import { Hydra as client } from 'alcaeus';
client.loadResource('https://sources.test.wikibus.org/');
  1. Compile with rollup main.js --config rollup.config.js

Other

Is this package event meant to be used in browser? No demos on website does not work either.
And it isn't specified anywhere what is the primary platform for this package.

Add hydra:collection to resources

As surfaced but HydraCG/api-examples#4, Alcaeus needs to natively support hydra:collection property.

I can think of two ways to add it to the API.

First would be to implicitly treat hydra:collection as a hydra:Link property. I would add a getLinks() method to the base resource type so which gathers explicit links and collections in a single array.

const response = await Hydra.loadResource(url)
const resource = response.root

// will return collections and links defined as `hydra:Link`
resource.getLinks()

I favour this approach as it will play nice with the generic app and is one less place too look at when processing Hydra representations.


Alternatively, a dedicated property/method could be introduced which only accesses the related collections.

I do feel though that it's just bloat.

Testing on older browsers

Older browsers need polyfills for heracles to work. I'd like to add those pop\lyfills to tests on Travis to confirm they work

Handle operations not connected to the resource IRI

We defined an API which also contains the links to the objects. It was designed like this to reduce the number of requests required to use the API. It looks like Alcaeus can only handle objects which are connected to triples with a subject matching the resource IRI. It would be great to have an option to also access the objects not connected to the resource IRI.

Two ideas how it could be implemented:

  • loadResource returns also array objects to manually search for the wanted object
  • A function which returns an array of objects by type (DataSet in our example)

Most of the operations in our API return a lot of triples. This is a good candidate for testing.

Redirect not respected if original URI is present in response

When a request to /foo gets redirected to /bar I would somewhat assume that latter should be the root resource.

Currently, however, /foo will take precedence and if the redirected response contains both resource, the former will be returened

Type inference for supported classes

Alcaeus does not recognise subclassOf statements for supported classes, which might greatly simplify the explicitness of an ApiDocumentation.

For example, where currently it's necessary to duplicated supported properties and operations:

vocab:Issue a hydra:Class ;
  hydra:supportedOperation api:GetIssue ;
  hydra:supportedProperty [
    hydra:property vocab:title
  ] , [
    hydra:property vocab:assignee
  ] , [
    hydra:property vocab:status
  ] .

vocab:DraftIssue a hydra:Class ;
  hydra:supportedOperation api:GetIssue, api:UpdateDraft ;
  hydra:supportedProperty [
    hydra:property vocab:title
  ] , [
    hydra:property vocab:assignee
  ] , [
    hydra:property vocab:status
  ] .

It should instead be possible for DraftIssue to "inherit" from Issue

vocab:Issue a hydra:Class ;
  hydra:supportedOperation api:GetIssue ;
  hydra:supportedProperty [
    hydra:property vocab:title
  ] , [
    hydra:property vocab:assignee
  ] , [
    hydra:property vocab:status
  ] .

# all operations and properties merged with those of vocab:Issue
# practically `a hydra:Class` should also be unneeded
vocab:DraftIssue a hydra:Class ;
  rdfs:subclassOf vocab:Issue ;
  hydra:supportedOperation api:UpdateDraft .

content-type with charset not working

If the content-type contains a charset like application/ld+json; charset=utf-8, the parser is not found. I think in this line the charset should be cropped. In rdf-fetch it's done like this.

Example to reproduce the error:

const Hydra = require('alcaeus').Hydra

Hydra.loadResource('http://ld.stadt-zuerich.ch/api').then(res => {
  console.log(res)
}).catch((err) => {
  console.error(err)
})

Handle responses with different identifier

It is possible that the server returns a representation of a different resource either by redirecting or by setting the Content-Location header. In such case Heracles should honour the header or the redirect URI to look for the root object in the representation

VS Code doesn't find the types/library

I tried using heracles with just the angular quickstart tutorial, and so far Visual Studio doesn't recognize heracles typings unless I add this line to "typings/index.d.ts":
/// <reference path="../node_modules/heracles/heracles.d.ts" />
When running
typings install npm~heracles --global
it says there's no entry for heracles.

So far, when trying to install/run heracles just through the steps in the readme, it won't work. Could you update it, so that newcomers have a simpler start?

And thanks a lot for publishing this repository, looks like a good project!

Indexer signature missing from IHydraResource

It would be useful for HydraResource (IResource?) to include an indexer so that it's type safe to select child resources.

Currently resource['property'] returns causes:

TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'HydraResource'.
  No index signature with a parameter of type 'string' was found on type 'HydraResource'.

Adding { [ prop: string ]: HydraResource } to the interface could be useful

Properties are returned twice

When same property appears on two supported classes implemented by a the same resource.

const { Hydra } = require('alcaeus')

const rep = await Hydra.loadResource('https://sources.test.wikibus.org/book/1081')

rep.root.getProperties()
    .reduce((res, tuple) => {    
      return {
         ...res,
         [tuple.supportedProperty.property.id]: (res[tuple.supportedProperty.property.id] || 0) + 1
      }
    }, {})

Relative Links to ApiDocumentation

Expected behaviour

Given The client at https://client.example loads an API entrypoint at http://api.example/
And The Link-Header of the response contains a relative link to the API doc: Link: </doc>; rel="http://www.w3.org/ns/hydra/core#apiDocumentation"
When the client loads the API doc
Then it uses the absolute URI http://api.example/doc

Actuall behaviour

Then it uses the absolute URI http://client.example/doc

Additional information

https://tools.ietf.org/html/rfc3986#section-5.1.3

5.1.3. Base URI from the Retrieval URI

If no base URI is embedded and the representation is not encapsulated
within some other entity, then, if a URI was used to retrieve the
representation, that URI shall be considered the base URI. Note that
if the retrieval was the result of a redirected request, the last URI
used (i.e., the URI that resulted in the actual retrieval of the
representation) is the base URI.

Convenience method for dereferencing?

Currently, to fetch resources, the client has to be used directly every time

const rep = await client.loadResource('http://www.markus-lanthaler.com/hydra/api-demo/issues/');
const issue = (await client.loadResource(rep.root.members[0].id)).root

It could be useful to have a simple method on each object which would follow the self-link (@id) and return the representation.

const rep = await client.loadResource('http://www.markus-lanthaler.com/hydra/api-demo/issues/');
const issue = await rep.root.members[0].load()

Working with Link headers

While not exactly Hydra-specific, it would be good to add a convenient way to access Link headers attached to loaded resource

Getting the vocabulary is inconvenient

To build hydra terms one has to write

import { Core } from 'alcaeus/lib/es/Constants'

const Class = Core.Vocab('Class')

The import is rather awkward. Should be exported from package main

import { Vocab } from 'alcaeus'

const Class = Vocab('Class')

Support inline operations

Hydra can also include operations inlined in the representation

{
  "@id": "Person",
  "hydra:operation": [
     { "@type": "hydra:DeleteOperation" },
     { "@type": "hydra:ReplaceOperation" }
   ]
}

They should be available on the object along with the Supported Operations from the included in the hydra:ApiDocumentation

Signalling unrecognised media type

Currently Alcaeus silently skips processing of representation which is not of a media type recognised by any media type processor.

This should be handled somewhat differently or at least an additional piece of information added to HydraResponse so that the caller can get more information

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.