bleupen / halacious Goto Github PK
View Code? Open in Web Editor NEWa better HAL processor for Hapi
License: MIT License
a better HAL processor for Hapi
License: MIT License
Custom response headers, such as Last-Modified, are currently being omitted from the hal response.
Hi there,
I don't seem to be able to specify self using the pathing syntax, eg.
links: {
meAgain: '.'
}
Output: meAgain: {href: '.'}
Nor can I specify parent without a trailing slash:
links: {
myParent: '..',
myParentSlash: '../'
}
Output: myParent: {href: '..'}, myParentSlash: {href: '/the/parent/'}
Not the end of the world, can work around programmatically but this was what I tried first...
Currently relative locations are not fully resolved in the hal response
I'm using elasticbeanstalk to do my deployments. This is done simply by pushing to a git branch hosted on aws.
I normally commit all of my dependencies to minimize any issues with deployment, but in this case I am getting the following error:
Error: Cannot find module './tags'
at Function.Module._resolveFilename (module.js:338:15)
at Function.Module._load (module.js:280:25)
at Function._load (/var/app/current/node_modules/newrelic/lib/shimmer.js:209:38)
at Module.require (module.js:364:17)
at require (module.js:380:17)
at Object.<anonymous> (/var/app/current/node_modules/halacious/node_modules/swig/lib/swig.js:2:11)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
If I remove my node_modules/halacious
folder and let the deployment process npm install
for me this problem goes away. Something up in your package maybe?
Under certain circumstances Halacious seems to cause Hapi to set an HTTP header with a value of undefined. With node 0.12 this causes an exception to be thrown because of this change (from what I can tell) nodejs/node-v0.x-archive@979d0ca which looks legitimate to me. The Error('"name" and "value" are required for setHeader().') is the case which is triggered, and some minor hacking indicates this is related to the HTTP location field.
Using curl as below
$ curl -i http://localhost:8080/api/
calling the following code
'use strict';
var hapi = require('hapi');
var server = new hapi.Server();
server.connection({
host: '0.0.0.0',
port: 8080,
});
server.route({
method: 'get',
path: '/test',
config: {
handler: function (req, reply) {
reply('hello, world');
}
}
});
server.register({
register: require('halacious'),
options: {apiPath: '/api'}
}, function (err) {
if (err) throw err;
var ns = server.plugins.halacious.namespaces.add({
name: 'acano',
description: 'Acano Corningstone API',
prefix: 'acano'
});
ns.rel({
name: 'provisioningcert',
description: 'A provision certificate'
});
server.start(function (err) {
if (err) throw err;
console.log('Server started...');
});
});
causes the issue to manifest for me as
Debug: internal, implementation, error
Error: "name" and "value" are required for setHeader().
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:333:11)
at Object.internals.transmit (/home/vagrant/hapi-test/node_modules/hapi/lib/transmit.js:250:25)
at /home/vagrant/hapi-test/node_modules/hapi/lib/transmit.js:34:26
at Function.internals.Auth.response (/home/vagrant/hapi-test/node_modules/hapi/lib/auth.js:381:16)
at /home/vagrant/hapi-test/node_modules/hapi/lib/transmit.js:139:25
at internals.Response._streamify (/home/vagrant/hapi-test/node_modules/hapi/lib/response.js:484:12)
at internals.Response._marshal (/home/vagrant/hapi-test/node_modules/hapi/lib/response.js:433:21)
at /home/vagrant/hapi-test/node_modules/hapi/lib/transmit.js:119:18
at /home/vagrant/hapi-test/node_modules/hapi/lib/transmit.js:535:20
at Object.exports.parallel (/home/vagrant/hapi-test/node_modules/hapi/node_modules/items/lib/index.js:47:9)
In case its relevant
$ uname -a
Linux precise64 3.2.0-23-generic #36-Ubuntu SMP Tue Apr 10 20:39:51 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
I may be doing something wrong, but when using rep.factory
from the prepare
function, links from both create()
and link()
get defined directly rather than having the host prepended. Am I missing something or is this intended behavior?
Have an object like:
{
parent: {
prepare: function(rep, next) { next(); },
embedded : {
child: {
prepare: function(rep, next) {
someLongRunningAsyncMethod(function() {
rep.link("foo", "/foo");
next();
});
}
}
}
}
}
I don't see the foo
link. I've tested and even if I remove the next()
call from the child's prepare
method, the next()
call in the parent still runs...
Unlike links, empty embedded arrays are currently stripped from the response. Fix to make consistent with links.
What is the best way the handle multiple content-types?
One solution I can think of is:
Is there something that plugin provides to help with this?
Make halacious work with Hapi 6
plugin.register fails in hapi11 with TypeError: server.after is not a function.
Hi,
Issue #58 allows empty arrays of embedded entities, but I can't see how to use it where I need to map objects that have self-refs defined by their own properties (eg. '/people/{id}') in an array that might be empty.
I think I'm looking for rep.embed
to support an array-arg based variant (like rep.link
) such as embed(rel, embeddables)
where toEmbed is an object with self and entity properties. Then, I can call
rep.embed('friends', rawFriendsArray.map(function(friend) {
var selfHref = '/people/'+friend.id;
delete friend.id;
return {self: selfHref, entity: friend};
}));
...and rawFriendsArray happens to be empty it'll just embed an empty array.
Happy to submit a PR for this if I'm not missing a better way to do it already!
The /rels pages are pretty ugly to look at. Add basic styling to the pages. Markdown-based rel documentation can be enhanced just by adding this bower plugin: https://github.com/sindresorhus/github-markdown-css
The current implementation relies on hoek.merge(), which performs a deep clone on additional props.
Change to use a shallow clone.
I ended up having to install swig into my application:
npm install --save swig
Error: Cannot find module 'swig'
at Function.Module._resolveFilename (module.js:338:15)
at Function.Module._load (module.js:280:25)
at Function._load (/Users/chadkouse/src/myco/mi-api/node_modules/newrelic/lib/shimmer.js:209:38)
at Module.require (module.js:364:17)
at require (module.js:380:17)
at /Users/chadkouse/src/mycompany/my-api/node_modules/hapi/lib/views.js:64:58
at Array.forEach (native)
at new exports.Manager.internals.Manager (/Users/chadkouse/src/myco/my-api/node_modules/hapi/lib/views.js:39:16)
at Object.root.views (/Users/chadkouse/src/myco/my-api/node_modules/hapi/lib/pack.js:324:21)
at exports.register (/Users/chadkouse/src/myco/my-api/node_modules/halacious/lib/plugin.js:641:12)
I am unable to use [email protected]. It is requiring in URI.js. URI.js changed their npm registration to urijs
. halacious is requiring in as URIjs
in https://github.com/bleupen/halacious/blob/master/lib/representation.js#L6.
Error: Cannot find module 'URIjs'
at Function.Module._resolveFilename (module.js:337:15)
at Function.Module._load (module.js:287:25)
at Module.require (module.js:366:17)
at require (module.js:385:17)
at Object.<anonymous> (/var/app/current/node_modules/our-app/node_modules/server-framework/node_modules/halacious/lib/representation.js:6:11)
at Module._compile (module.js:435:26)
at Object.Module._extensions..js (module.js:442:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:311:12)
at Module.require (module.js:366:17)
at require (module.js:385:17)
The marked
dependency has currently a security flow reported on https://nodesecurity.io/advisories/101 .
What is your idea on how to do pagination? Currently I am adding properties like offset
and limit
to my entity and then writing a prepare
function that ignores them and does the linking..
Any shortcut here?
Path works on both mac and windows in halacious for filesystem operations, but is also being used to generate a URL for the rels/{namespace}/{rels} route. This yields an invalid URL on windows. In this case path.join() returns '\rels{namespace}{rel}'. Hapi accepts the \ on mac, but on windows throws an error:
E:\halaciousTest\node_modules\hapi\node_modules\hoek\lib\index.js:425
throw new Error(msgs.join(' ') || 'Unknown error');
^
Error: Invalid path: \rels\{namespace}\{rel}
Replacing the path.join() with string contatenation using / allows the test/server-test.js and examples to execute on both platforms.
201 status codes are swallowed and burped out as 200's with the wrong self link. The location header should be detected and used for newly created entities.
I would like to throw my analytics links into a bucket within the _links object called "analytics", is this achievable? Currently i'm loading in links like we discusses in issue #55 Thanks!
Current:
_links: {
self: {
href: "/phonesheets/{?Id}"
},
calls-per-day: {
href: "/analytics/calls-per-day{?Id}",
templated: true
},
keywords: {
href: "/analytics/keywords{?Id}",
templated: true
},
last-contact: {
href: "/analytics/last-contact{?Id}",
templated: true
}
}
Desired:
_links: {
self: {
href: "/phonesheets/{?Id}"
},
analytics: {
calls-per-day: {
href: "/analytics/calls-per-day{?Id}",
templated: true
},
keywords: {
href: "/analytics/keywords{?Id}",
templated: true
},
last-contact: {
href: "/analytics/last-contact{?Id}",
templated: true
}
}
}
While some links are getting updated to be absolute, the ones that are added to the automatically generated root, by adding the api
route configuration, don't seem to get updated.
I see #78, but this is more of a feature request.
Something as simple as this could be used to mark a route as a form.
server.route({
method: 'POST',
config: {
handler: (req, reply) => {/*...*/},
plugins:{
hal:{
form: true,
},
},
},
})
There seems to be an incompatible change in Hapi starting at 9.0.0. Unable to run tests from this version with server.views being undefined
Hi, I'm trying to add halacious to an existing REST api and can't find how to do so for collection end points.
For example the following returns an array of pieces:
{
method: 'GET',
path: '/volumes/{id}/pieces',
config: {
tags: ['api'],
handler: function (request, reply) {
var query = request.db.piece.findAll({
where : { volumeId: request.params.id }
});
return reply(query);
},
validate: {
params: {
id: Joi.number().required()
}
}
}
}
Is this possible already or would this be a new feature?
Clients don't like having to check if something is an array or not every time before they use it.
Hi,
I am fairly new to HAL and I found this plugin pretty useful to get started.
I basically want to achieve this:
{
"_links": {
"items": [{
"href": "/first_item"
},{
"href": "/second_item"
}]
}
}
as described under Representing Multiple Links With The Same Relation
here
How could I do this using halacious ?
in my database this is stored as
items:[
{
"name":"first_item",
"id":"first_item_id"
},
{
"name":"second_item",
"id":"second_item_id"
}
]
Thanks
Hi,
I ran a nsp check today and got this:
βββββββββββββββββ¬βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β Regular Expression Denial of Service β
βββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Name β uglify-js β
βββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Installed β 2.4.24 β
βββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Vulnerable β <2.6.0 β
βββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Patched β >=2.6.0 β
βββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Path β 'MYPKG' > [email protected] > [email protected] > [email protected] β
βββββββββββββββββΌβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β More Info β https://nodesecurity.io/advisories/48 β
βββββββββββββββββ΄βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
I wasn't aware of a query
config parameter.. don't see it in the readme.
Is there a way that I can programmatically get a hold of the representation that is used to generate the root /api
response? I would like to decorate it with a _forms
object ala HAL Forms.
As I mentioned in #60, absolute links do not include the correct protocol when the api is served from https.
I have not spent significant time investigating if this is even possible to detect at the server level, but thought it would be valuable to log this to give visibility to the issue.
If not possible to detect on the server, is there at least a way to configure halacious
to make absolute links use https
as the protocol that I'm overlooking?
auth in hapi is either false for unauthenticated, or an object such as { strategies: [ 'session' ] }
.
For instance if the client sends application/json
I want to also send the hal representation.
Any plans on streaming representations?
It may be possible already but it's unclear how/if I can specify the self link within my object. For instance I have a group of embedded objects that appear embedded in various different places within my API. In an effort to DRY this code I'd rather have a "selfUrl" property on my object (or something like that) which can be picked up and used when embedding.
I'd like to be able to represent an empty array of links - for example, a link rel 'items' that connects a resource to 0..* items.
I'd like to guarantee that there will always be an 'items' property present in the _links map, and that it will contain an empty array if there are no 'items' links.
Halacious errors if I do: rel.link('items', [])
, but it's fine for rel.link('items', ['./items/1'])
and rel.link('items', ['./items/1', './items/2'])
.
Is there a reason this isn't supported? I imagine it's an oversight rather than by design, as it'd be easy to accidentally wind up with an empty array there.
Hi,
I noticed that (in particular) curly brace characters are url encoded (%7b) in the href of _link objects. Is there a way to make halacious not url encode the _link's href?
Thanks.
Embedding an entity that defines a toHal method on it inside another method with a toHal method on it works perfectly well, iff the embedding is done by use of configuration. If it is done using code in the toHal method of the outer entity then it does not work as expected.
The following works as expected:
function InnerModel(id, name, owner) {
this.id = id;
this.name = name;
this.owner = owner;
}
InnerModel.prototype.toHal = function(rep, next) {
rep.link('owner', '/users/' + this.owner.id);
next();
}
function PageModel(items, totalCount) {
this.items = items;
this.totalCount = totalCount;
}
PageModel.prototype.toHal = function(rep, next) {
rep.link('first', '?index=0'); // To prove that the toHal method runs
next();
}
server.route({
method: 'GET',
path: '/items',
config: {
handler: (req, reply) => {
reply(new PageModel([new InnerModel(1, 'Name', {id: 1001, name: 'Graham'})], 10));
},
tags: ['api'],
plugins: {
hal: {
embedded: {
item: {
path: 'items',
href: './{item.id}'
}
}
}
}
}
});
And this produces the following output:
{
"_links": {
"self": {
"href": "/items"
},
"first": {
"href": "?index=0"
}
},
"totalCount": 10,
"_embedded": {
"item": [
{
"_links": {
"self": {
"href": "/items/1"
},
"owner": {
"href": "/users/1001"
}
},
"id": 1,
"name": "Name",
"owner": {
"id": 1001,
"name": "Graham"
}
}
]
}
}
However, if I try and do this with code instead, as follows:
function InnerModel(id, name, owner) {
this.id = id;
this.name = name;
this.owner = owner;
}
InnerModel.prototype.toHal = function(rep, next) {
rep.link('owner', '/users/' + this.owner.id);
next();
}
function PageModel(items, totalCount) {
this.items = items;
this.totalCount = totalCount;
}
PageModel.prototype.toHal = function(rep, next) {
this.items.forEach(function(i) {
rep.embed('items', './' + i.id, i);
});
rep.ignore('items');
rep.link('first', '?index=0'); // To prove that the toHal method runs
next();
}
server.route({
method: 'GET',
path: '/items',
config: {
handler: (req, reply) => {
reply(new PageModel([new InnerModel(1, 'Name', {id: 1001, name: 'Graham'})], 10));
},
tags: ['api'],
plugins: {
hal: {
}
}
}
});
And this produces the following output:
{
"_links": {
"self": {
"href": "/items"
},
"first": {
"href": "?index=0"
}
},
"totalCount": 10,
"_embedded": {
"item": [
{
"_links": {
"self": {
"href": "/items/1"
}
},
"id": 1,
"name": "Name",
"owner": {
"id": 1001,
"name": "Graham"
}
}
]
}
}
Note in this case the inner Item does not have a link of "owner" even though the actual InnerModel class is exactly the same in both cases. The only difference is the one embeds the items using the "embedded" configuration and the other does it using "rep.embed" in the toHal method.
Note that I wanted to do it this way so that I can have a single PageModel class that is used everywhere instead of repeating the configuration everywhere that I want to do this.
Hey guys,
New to hypermedia, so please inform me if this usecase is ridiculous, but I have a situation where I'd like to pass the uri template I'm attaching to the href all the way through to the response without it being expanded. Once my object hits resolveHref() my template gets expanded into and empty string and I lose the template.
This is desired result:
/call/123876213876{?id}
Gets nuked to this
/call/123876213876
The reason I want the template to pass through is because these links will not always appear on a route that requires the actual {id} parameter to be passed in. In this case I'd like the api consumer to be aware of the possible routes they can hit if they supply the paremeters specified in the uri template.
If the "params" entry is not included on the route configuration then no querystring parameters are included on the self link at all.
If a "params" entry is included on the route configuration then the values are appended but not correctly formatted.
For example, when requesting a URL of '/items?offset=10&pageSize=5&q=item'. A configuration of:
hal: {}
will produce a Self link of '/items'
Whereas a configuration of
hal: {
query: '{offset,pageSize,q}'
}
will produce a Self link of '/items10,5,item' instead of the URL that I would have expected, which is '/items?offset=10&pageSize=5&q=item'
if an embedded entity is configured and it isn't present in the parent entity - you get a basically blank representation in the output.
self href's contain backslashes.
I've always included querystring parameters in my self link. I've treated self as a link that should take you to exactly the same place you currently are.
Edit: I'm referring to the self link on the top level representation -- not the embedded ones.
example:
You have a user who has purchased a song. So you have a purchase
entity with an embedded song
entity and you want to include links within the song
entity to a 30 second sample, or a download or whatever...
empty embedded arrays are being lost when added via route configuration
Halacious 3.4.0 (latest available version)
depends on swig in version 1.4.2 (latest available version, but no longer maintained)
which depends on uglify-js in version ~2.4.0
Versions of uglify < 2.6.0 are vulnerable to Regular Expression Denial of Service.
Below the result of nsp check
> nsp check
(+) 1 vulnerabilities found
βββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β Regular Expression Denial of Service β
βββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Name β uglify-js β
βββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Installed β 2.4.24 β
βββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Vulnerable β <2.6.0 β
βββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Patched β >=2.6.0 β
βββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Path β swig > uglify-js β
βββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β More Info β https://nodesecurity.io/advisories/48 β
βββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Thanks for this great lib!
Are you writing utilities to provide fully qualified urls inside your _links ? If so, how are you doing so with the generated curies href
urls? Are you relying on downstream fiddling of the urls to mint them properly?
So instead of
{
_links: {
self: { href: '/api' }
, curies: [ { name: 'foo', href: '/rels/Foo/{rel}' }]
}
Client really should be seeing
{
_links: {
self: { href: 'https://myhost.com/api' }
, curies: [ { name: 'foo', href: 'http://developer.foo.com/rels/Foo/{rel}' }]
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.