Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle fallbackRegistryUrl for ~info and ~preview #380

Merged
merged 10 commits into from
Mar 10, 2017
32 changes: 23 additions & 9 deletions src/registry/domain/url-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ var querystring = require('querystring');
var url = require('url');
var _ = require('underscore');

function componentForType(component, baseUrl, type) {
if (_.isString(component)) {
component = {name: component};
}

var href = url.resolve(baseUrl, component.name) + '/';

if (!!component.version) {
href += component.version + '/';
}

href += '~' + type;

return href;
}

var build = {
component: function (component, baseUrl) {
if (_.isString(component)) {
Expand All @@ -20,17 +36,15 @@ var build = {

return componentUrl;
},
componentInfo: function (component, baseUrl) {
return componentForType(component, baseUrl, 'info');
},
componentPreview: function (component, baseUrl) {
var href = baseUrl + component.name + '/';

if(!!component.version){
href += component.version + '/';
}

href += '~preview/';

var href = componentForType(component, baseUrl, 'preview');
if (!!component.parameters && !_.isEmpty(component.parameters)) {
href += '?' + querystring.stringify(component.parameters);
href += '/?' + querystring.stringify(component.parameters);
} else {
href += '/';
}

return href;
Expand Down
4 changes: 2 additions & 2 deletions src/registry/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ module.exports.create = function(app, conf, repository){
var routes = {
component: new ComponentRoute(conf, repository),
components: new ComponentsRoute(conf, repository),
componentInfo: new ComponentInfoRoute(repository),
componentPreview: new ComponentPreviewRoute(repository),
componentInfo: new ComponentInfoRoute(conf, repository),
componentPreview: new ComponentPreviewRoute(conf, repository),
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

those two endpoints now need configuration for fallbackRegistryUrl

listComponents: new ListComponentsRoute(repository),
publish: new PublishRoute(repository),
staticRedirector: new StaticRedirectorRoute(repository)
Expand Down
57 changes: 39 additions & 18 deletions src/registry/routes/component-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,10 @@ var parseAuthor = require('parse-author');
var _ = require('underscore');

var urlBuilder = require('../domain/url-builder');
var getComponentFallback = require('./helpers/get-component-fallback');

module.exports = function(repository){
return function(req, res){

repository.getComponent(req.params.componentName, req.params.componentVersion, function(err, component){

if(err){
res.errorDetails = err;
return res.status(404).json({ err: err });
}

var isHtmlRequest = !!req.headers.accept && req.headers.accept.indexOf('text/html') >= 0;

if(isHtmlRequest && !!res.conf.discovery){

var params = {},
author = component.author || {},
parsedAuthor = _.isString(author) ? parseAuthor(author) : author;

function getParams(component) {
var params = {};
if(!!component.oc.parameters){
var mandatoryParams = _.filter(_.keys(component.oc.parameters), function(paramName){
var param = component.oc.parameters[paramName];
Expand All @@ -34,6 +19,15 @@ module.exports = function(repository){
});
}

return params;
}

function getParsedAuthor(component) {
var author = component.author || {};
return _.isString(author) ? parseAuthor(author) : author;
}

function addGetRepositoryUrlFunction(component) {
component.getRepositoryUrl = function() {
if (_.isObject(this.repository)) {
if (this.repository.url) {
Expand All @@ -45,6 +39,21 @@ module.exports = function(repository){
}
return null;
};
}

function componentInfo(err, req, res, component) {
if(err) {
res.errorDetails = err.registryError || err;
return res.status(404).json(err);
}

var isHtmlRequest = !!req.headers.accept && req.headers.accept.indexOf('text/html') >= 0;

if(isHtmlRequest && !!res.conf.discovery){

var params = getParams(component);
var parsedAuthor = getParsedAuthor(component);
addGetRepositoryUrlFunction(component);

return res.render('component-info', {
component: component,
Expand All @@ -59,6 +68,18 @@ module.exports = function(repository){
requestVersion: req.params.componentVersion || ''
}));
}
}

module.exports = function(conf, repository){
return function(req, res){
repository.getComponent(req.params.componentName, req.params.componentVersion, function(registryError, component){
if(registryError && conf.fallbackRegistryUrl) {
return getComponentFallback.getComponentInfo(conf, req, res, registryError, function(fallbackError, fallbackComponent){
componentInfo(fallbackError, req, res, fallbackComponent);
});
}

componentInfo(registryError, req, res, component);
});
};
};
26 changes: 19 additions & 7 deletions src/registry/routes/component-preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,13 @@
var _ = require('underscore');

var urlBuilder = require('../domain/url-builder');
var getComponentFallback = require('./helpers/get-component-fallback');

module.exports = function(repository){
return function(req, res){

repository.getComponent(req.params.componentName, req.params.componentVersion, function(err, component){

function componentPreview(err, req, res, component) {
if(err) {
res.errorDetails = err;
res.errorDetails = err.registryError || err;
res.errorCode = 'NOT_FOUND';
return res.status(404).json({ err: err });
return res.status(404).json(err);
}

var isHtmlRequest = !!req.headers.accept && req.headers.accept.indexOf('text/html') >= 0;
Expand All @@ -31,6 +28,21 @@ module.exports = function(repository){
requestVersion: req.params.componentVersion || ''
}));
}
}

module.exports = function(conf, repository){
return function(req, res){

repository.getComponent(req.params.componentName, req.params.componentVersion, function(registryError, component){

if(registryError && conf.fallbackRegistryUrl) {
return getComponentFallback.getComponentPreview(conf, req, res, registryError, function(fallbackError, fallbackComponent){
componentPreview(fallbackError, req, res, fallbackComponent);
});
}

componentPreview(registryError, req, res, component);

});
};
};
41 changes: 40 additions & 1 deletion src/registry/routes/helpers/get-component-fallback.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,41 @@

var request = require('minimal-request');
var url = require('url');
var urlBuilder = require('../../domain/url-builder');
var _ = require('underscore');

module.exports = function(fallbackRegistryUrl, headers, component, callback) {
function getComponentFallbackForViewType(buildUrl, conf, req, res, registryError, callback) {
var path = buildUrl({
name: req.params.componentName,
version: req.params.componentVersion
}, conf.fallbackRegistryUrl);

return request({
method: 'get',
url: path,
headers: _.extend({}, req.headers, {
'host': url.parse(conf.fallbackRegistryUrl).host,
'accept': 'application/json'
})
}, function (fallbackErr, fallbackResponse) {
if (fallbackErr === 304) {
return res.status(304).send('');
}

if (fallbackErr) {
return callback({registryError: registryError, fallbackError: fallbackErr});
}

try {
return callback(null, JSON.parse(fallbackResponse));
} catch (parseError) {
return callback({registryError: registryError, fallbackError: 'Could not parse fallback response: ' + fallbackResponse});
}
});
}

module.exports = {
getComponent: function (fallbackRegistryUrl, headers, component, callback) {
return request({
method: 'post',
url: fallbackRegistryUrl,
Expand All @@ -28,4 +60,11 @@ module.exports = function(fallbackRegistryUrl, headers, component, callback) {

return callback(res[0]);
});
},
getComponentPreview: function (conf, req, res, registryError, callback) {
getComponentFallbackForViewType(urlBuilder.componentPreview, conf, req, res, registryError, callback);
},
getComponentInfo: function (conf, req, res, registryError, callback) {
getComponentFallbackForViewType(urlBuilder.componentInfo, conf, req, res, registryError, callback);
}
};
2 changes: 1 addition & 1 deletion src/registry/routes/helpers/get-component.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ module.exports = function(conf, repository){
// check route exist for component and version
if(err){
if(conf.fallbackRegistryUrl) {
return getComponentFallback(conf.fallbackRegistryUrl, options.headers, requestedComponent, callback);
return getComponentFallback.getComponent(conf.fallbackRegistryUrl, options.headers, requestedComponent, callback);
}

return callback({
Expand Down
36 changes: 36 additions & 0 deletions test/acceptance/registry/registry-with-fallback.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,41 @@ describe('registry', function(){
expect(result.html).to.equal('Hello world!');
});
});

describe('GET /fallback-hello-world/~info', function(){

before(function(done){
request({
url: 'http://localhost:3030/fallback-welcome-with-optional-parameters/~info',
json: true
}, next(done));
});

it('should respond with requested component', function(){
expect(result.name).to.eql('fallback-welcome-with-optional-parameters');
});

it('should respond with components parameters', function(){
expect(Object.keys(result.oc.parameters).length).to.equal(3);
});
});

describe('GET /fallback-hello-world/~preview', function(){

before(function(done){
request({
url: 'http://localhost:3030/fallback-welcome-with-optional-parameters/~preview',
json: true
}, next(done));
});

it('should respond with requested component', function(){
expect(result.name).to.eql('fallback-welcome-with-optional-parameters');
});

it('should respond with components parameters', function(){
expect(Object.keys(result.oc.parameters).length).to.equal(3);
});
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
_package
package.tar.gz
node_modules
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "fallback-welcome-with-optional-parameters",
"description": "",
"version": "1.0.0",
"repository": "",
"oc": {
"container": false,
"files": {
"template": {
"type": "jade",
"hashKey": "ab16fc5f93c027e4ce2f30db29b9f93586bd1af9",
"src": "template.js"
},
"dataProvider": {
"type": "node.js",
"hashKey": "c10781cef3d4df94e5198d719f446c04a9798ebf",
"src": "server.js"
},
"static": []
},
"parameters": {
"firstName": {
"type": "string",
"mandatory": true,
"example": "John"
},
"lastName": {
"type": "string",
"mandatory": false,
"example": "Smith"
},
"nick": {
"type": "string",
"mandatory": false,
"example": "Smith",
"default": "Johnny"
}
},
"renderInfo": false,
"version": "0.33.12",
"packaged": true,
"date": 1476562431977
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "fallback-welcome-with-optional-parameters",
"description": "",
"version": "1.0.0",
"repository": "",
"oc": {
"container": false,
"files": {
"data": "server.js",
"template": {
"src": "template.jade",
"type": "jade"
}
},
"parameters": {
"firstName": {
"type": "string",
"mandatory": true,
"example": "John"
},
"lastName": {
"type": "string",
"mandatory": false,
"example": "Smith"
},
"nick": {
"type": "string",
"mandatory": false,
"example": "Smith",
"default": "Johnny"
}
},
"renderInfo": false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict';

module.exports.data = function(context, callback){
callback(null, {
firstName: context.params.firstName,
lastName: context.params.lastName,
nick: context.params.nick
});
};
Loading