diff --git a/README.md b/README.md index 852e66f..ad55dd4 100755 --- a/README.md +++ b/README.md @@ -171,6 +171,90 @@ Now, calling `/` with header `accept: application/json` will render } ``` +## Custom links +restify-json-hal exposes the addLink function that allows you to link to another resource that would normally not be considered related. + +An example: + +```javascript +server.get('/books/:bookname', (request,response,next) => { + /** + * HAL: Gets book and author + * @name getauthor + */ + var author = "alan-watts"; + response.addLink("get", `/authors/${author}`); + response.send({ + title: request.params.bookname, + author: author + }); + return next(); +}); + +server.get('/authors/:authorname', (request, response, next) => { + /** + * HAL: Gets author and published books + * @name getauthor + */ + var books = ["the-way-of-zen"]; + for (var i = 0; i < books.length; i++) { + response.addLink("get", `/books/${books[i]}`, books[i]); + } + response.send({ + author: request.params.authorname, + books: books + }); +}); +``` + +A call to `/books/the-way-of-zen` will render: + +```json +{ + "title": "the-way-of-zen", + "author": "alan-watts", + "_links": [ + { + "href": "/books/the-way-of-zen", + "rel": "self", + "description": "Gets book and author", + "method": "GET" + }, + { + "rel": "getauthor", + "method": "GET", + "description": "Gets author and published books", + "href": "/authors/alan-watts" + } + ] +} +``` + +A call to `/authors/alan-watts` will render: + +```json +{ + "author": "alan-watts", + "books": [ + "the-way-of-zen" + ], + "_links": [ + { + "href": "/authors/alan-watts", + "rel": "self", + "description": "Gets author and published books", + "method": "GET" + }, + { + "rel": "the-way-of-zen", + "method": "GET", + "description": "Gets book and author", + "href": "/books/the-way-of-zen" + } + ] +} +``` + ## todo - `_embedded`, somehow diff --git a/addLink.js b/addLink.js new file mode 100755 index 0000000..e5a7c5c --- /dev/null +++ b/addLink.js @@ -0,0 +1,53 @@ +var parseUrlDocs = require('./parseUrlDocs.js'); +var cache = {}; + +module.exports = (server, options) => { + var attachHALObj = require('./attachHALObj.js')(options); + + var findLink = (method, urlWithoutQuery) => { + for (var i = 0; i < server.router.routes[method].length; i++) { + var route = server.router.routes[method][i]; + if (route.path.exec(urlWithoutQuery)) { + + var halObj = { + // caching is done without the url query part, so we don't put the url in the cache + // href: options.prefix + url, + rel: route.name, + method: method + }; + // if (route.path.restifyParams) { + // halObj.templated = true; + // } + parseUrlDocs({ + chain: server.routes[route.name], + halObj: halObj, + name: route.name + }); + return halObj; + } + } + } + + return (halContainer, response) => { + + // this function is given to the developer + return (method, url, customName) => { + method = method.toUpperCase(); + var urlWithoutQuery = url.indexOf("?") == -1 ? url : url.substring(0, url.indexOf("?")); + cache[method] = cache[method] || {}; + + if (!cache[method][urlWithoutQuery]) { + cache[method][urlWithoutQuery] = findLink(method, urlWithoutQuery) + } + + var result = cache[method][urlWithoutQuery]; + result.href = options.prefix + url; + if (customName) { + result.rel = customName; + } + attachHALObj(result, halContainer); + } + + } + +} diff --git a/index.js b/index.js index 440ac67..60a8177 100755 --- a/index.js +++ b/index.js @@ -6,6 +6,8 @@ module.exports = (server, options) => { options.prefix = options.prefix || ""; options.makeObjects = options.makeObjects || false; + var addLink = require('./addLink.js')(server, options); + // override json formatter // add HAL data to body and then invoke normal json formatter var _formatJSON = server.formatters["application/json"]; @@ -40,6 +42,7 @@ module.exports = (server, options) => { } else { request.hal = halCache[url].slice(0); } + response.addLink = addLink(request.hal, response); next(); } }