halacious icon indicating copy to clipboard operation
halacious copied to clipboard

absolute flag does not seem to apply to factory created links

Open travi opened this issue 9 years ago • 12 comments

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?

travi avatar Jul 21 '15 03:07 travi

Try setting absolute: true in the halacious plugin registration options. I'm curious how you are using rep.factory. Can you post a code example?

bleupen avatar Jul 21 '15 12:07 bleupen

First, a little context. I've been slowly building out a simple example api to get my head around the details of HAL as compared to more traditional HATEOAS implementations. There may be better ways to accomplish what I'm after, but I was trying to start simple and get something working in a way that I am more familiar with.

I am trying to get the self links generated and attached to the items in a list. I saw the example in your readme about listing items in the _embedded section, but it seems to me like the list in the common case is the primary content. Therefore, I'm trying to keep it as a top level attribute in the response rather than under _embedded, which is for replacement of links in order to make things less chatty. I haven't seen another example of using _embedded in the particular way that is shown in your readme elsewhere, but would love it if you have a better reference that you could point me to than I've been finding.

Anyway, this is what I landed on to get my approach at least working as I continue to explore what is 'right':

plugins: {
            hal: {
                api: 'users',
                prepare: function (rep, next) {
                    rep.entity.users.forEach(function (user, index) {
                        rep.entity.users[index] = rep.factory.create(user, '/users/' + user.id);
                    });

                    next();
                }
            }
        }

You can find it in context here, if that would be more helpful. The output can be seen here. I do already have the absolute:true flag set here and it is working in other places. Even if there is a better way to accomplish what I'm trying to do here, it seemed like the factory should still honor the absolute flag in this case, so I wanted to pass the observation along.

Lastly, also notice that the absolute links show http for the protocol even though the api is served from https. Is there a way for the plugin to detect this, or at least let me configure it? If you'd like me to log a separate issue for this, just let me know.

travi avatar Jul 21 '15 14:07 travi

I have spent some time with documentation and client-side tools and have updated my api to use the _embedded approach, so this no longer affects me, but I'll leave the issue open as so that you have awareness of this inconsistency. If the factory is exposed as it is, it should probably be consistent with this behavior.

I'll go ahead and open another issue for the question about protocols.

travi avatar Jul 26 '15 02:07 travi

could you post an updated code snippet with your latest approach?

thanks!

bleupen avatar Jul 26 '15 12:07 bleupen

Sure, it's essentially what you have in the example in your readme, which puts the list items under embedded:

plugins: {
            hal: {
                api: 'users',
                prepare: function (rep, next) {
                    rep.entity.users.forEach(function (user) {
                        rep.embed('users', './' + user.id, user);
                    });

                    rep.ignore('users');

                    next();
                }
            }
        }

Therefore, I'm no longer using the factory in the way that fails to build the absolute links correctly.

travi avatar Jul 26 '15 15:07 travi

have you tried declarative embedding? this should preserve the protocol:

plugins: {
       hal: {
                api: 'users',
                embedded: {
                    users: {
                       path: 'users' // payload property to embed,
                       href: './{item.id}'
                    }
                }
        }

bleupen avatar Jul 26 '15 15:07 bleupen

I have not, but the issue with the protocol is not specific to the self links on lists. It is consistent across all of the links in the response, which is why I ended up logging that separately as #61.

travi avatar Jul 26 '15 15:07 travi

I just spun up a quick example on the current release (3.1.5). Here's the code:

'use strict';

var hapi = require('hapi');
var halacious = require('../');
var fs = require('fs');

var server = new hapi.Server();
server.connection({
    port: 8443,
    tls: {
        key: fs.readFileSync(__dirname + '/key.pem'),
        cert: fs.readFileSync(__dirname + '/cert.pem')
    }
});

server.register({ register: halacious, options: { absolute: true }}, function(err){
    if (err) console.log(err);
});

server.route({
    method: 'get',
    path: '/users/{userId}',
    config: {
        handler: function (req, reply) {
            reply({
                id: req.params.userId,
                name: 'User ' + req.params.userId,
                googlePlusId: '107835557095464780852',
                boss: {
                    id: 101,
                    name: 'Boss Man'
                }
            });
        },
        plugins: {
            hal: {
                links: {
                    'home': './{googlePlusId}'
                },
                embedded: {
                    'mco:boss': {
                        path: 'boss',
                        href: '../{item.id}'
                    }
                },
                ignore: 'googlePlusId' // remove the id property from the response
            }
        }
    }
});

server.start(function(err){
    if (err) return console.log(err);
    console.log('Server started at %s', server.info.uri);
});

and here's the response to GET https://127.0.0.1:8443/users/100

{
    "_links": {
        "self": {
            "href": "https://127.0.0.1:8443/users/100"
        },
        "home": {
            "href": "https://127.0.0.1:8443/users/100/107835557095464780852"
        }
    },
    "id": "100",
    "name": "User 100",
    "_embedded": {
        "mco:boss": {
            "_links": {
                "self": {
                    "href": "https://127.0.0.1:8443/users/101"
                }
            },
            "id": 101,
            "name": "Boss Man"
        }
    }
}

is this not correct?

bleupen avatar Jul 26 '15 16:07 bleupen

That does look correct, but I assume it is because of the configuration of tls in your connection setup. I am not configuring tls within my application. Take another look at https://api.travi.org/, and you'll notice that the result there is not the same as yours above.

The signed ssl cert for this api is provided by cloudflare and traffic is routed to heroku with a self-signed cert protecting the traffic between cloudflare and heroku. Hosting details aside, the node app has not been configured in a way that tells it that it is being served over https. I don't imagine the traffic inside the heroku infrastructure is encrypted, so I don't think I would want to configure my app to expect tls, would I?

Admittedly, I'm still figuring out some of these details, so don't hesitate to point out details that I'm overlooking or misunderstanding.

travi avatar Jul 26 '15 16:07 travi

I see.

Would global configuration options for protocol and host work for you?

On Jul 26, 2015, at 12:31 PM, Matt Travi [email protected] wrote:

That does look correct, but I assume it is because of the configuration of tls in your connection setup. I am not configuring tls within my application. Take another look at https://api.travi.org/ https://api.travi.org/, and you'll notice that the result there is not the same as yours above.

The signed ssl cert for this api is provided by cloudflare and traffic is routed to heroku with a self-signed cert protecting the traffic between cloudflare and heroku. Hosting details aside, the node app has not been configured in a way that tells it that it is being served over https. I don't imagine the traffic inside the heroku infrastructure is encrypted, so I don't think I would want to configure my app to expect tls, would I?

Admittedly, I'm still figuring out some of these details, so don't hesitate to point out details that I'm overlooking or misunderstanding.

— Reply to this email directly or view it on GitHub https://github.com/bleupen/halacious/issues/60#issuecomment-125014040.

bleupen avatar Jul 27 '15 01:07 bleupen

Sure, that should work fine. It would probably be ideal if each were independently optional if both are available. Since the host is working properly for me automatically, I would probably choose the minimal route and only configure the protocol.

travi avatar Jul 27 '15 02:07 travi

Can you use the Hapi Connection options uri for this? http://hapijs.com/api#serverconnectionoptions

irothschild avatar Aug 09 '15 21:08 irothschild