SailsJS - Create versioned API without blueprint - javascript

I'm trying to figure out how to create a versionned API for my application.
According to this issue https://github.com/balderdashy/sails/issues/322 , I have to use blueprint, but all blueprint is deactivated in my project (a wish from my boss).
I want to be able to have any URL like http://myapi.com/v1/my-custom-route , and so on for any version.
So far, the best way I've found is to duplicate all controller to something like v322AuthController.js and to map all routes like
'POST /v3.2.2/se-connecter' : 'v322AuthController.perform_signin'
But I think that's an ugly trick. I'm currently using Nginx and all my code is versionned with git
Thank you if you have any idea
Kai23

you have to disable all blueprints? Than you have to write all your routes an our own.
If you don't want to duplicate your controllers you can try this:
config/routes.js
module.exports.routes = {
'post /:apiversion/se-connecter' : {
controller: 'AuthController',
action: 'perform_signin',
skipAssets: true
}
....
}
So Sails passes all */se-connecter to the method "perform_signin" at your "AuthController". In your controller you have your api-version:
AuthController.js
module.exports = {
perform_signin: function (req, res) {
var apiversion = req.param('apiversion');
if (apiversion === "0.2.0") {
....
}
}
}

My approach:
Create subfolder for your controllers as:
/controllers/v1/UserController.js
/controllers/v2/UserController.js
In your routes.js file, add as follow:
'POST /api/v2/user': 'v2/UserController.create',
'POST /api/v1/user': 'v2/UserController.create',
And in your policies.js, you can add middlewares like this:
'v2/UserController': {
'create': ['isAuthenticated','isAuthorized']
}
My current sails' version is: 0.12.3

Related

Value not set to global variable in JS/AngularJs

I am using gulp to run and build to run my application. I am getting file contents using $http service in my index.js file and then setting value of a variable like
window.variablex = "http://localhost:8080/appname".
here is how I am doing it (in index.js)
(function ()
{
'use strict';
angular
.module('main')
.controller('IndexController', IndexController);
function IndexController($http){
$http.get('conf/conf.json').success(function(data){
window.variable = data.urlValue;
}).error(function(error){
console.log(error);
});
}
});
And I've created a factory to call the rest APIs of my backend application like
(function(){
'use strict';
angular
.module('main')
.factory('testService',['$resource',testService]);
function agentService($resource){
var agents = $resource('../controller/',{id:'#id'},
{
getList:{
method:'GET',
url:window.variable+"/controller/index/",
isArray:false
}
});
Now, I except a rest call to made like
http://localhost:8080/appname/controller
But it always sends a call like http://undefined/appname/controller which is not correct.
I can get the new set value anywhere else, but this value is not being set in resource service objects somehow.
I am definitely missing something.
Any help would be much appreciated
As you are using Gulp, I advise you to use gulp-ng-config
For example, you have your config.json:
{
"local": {
"EnvironmentConfig": {
"api": "http://localhost/"
}
},
"production": {
"EnvironmentConfig": {
"api": "https://api.production.com/"
}
}
}
Then, the usage in gulpfile is:
gulp.task('config', function () {
gulp.src('config.json')
.pipe(gulpNgConfig('main.config', {
environment: 'production'
}))
.pipe(gulp.dest('.'))
});
You will have this output:
angular.module('myApp.config', [])
.constant('EnvironmentConfig', {"api": "https://api.production.com/"});
And then, you have to add that module in your app.js
angular.module('main', [ 'main.config' ]);
To use that variable you have to inject in your provider:
angular
.module('main')
.factory('testService', ['$resource', 'EnvironmentConfig', testService]);
function agentService($resource, EnvironmentConfig) {
var agents = $resource('../controller/', {id: '#id'},
{
getList: {
method: 'GET',
url: EnvironmentConfig + "/controller/index/",
isArray: false
}
});
}
#Kenji Mukai's answer did work but I may have to change configuration at run time and there it fails. This is how I achieved it (in case anyone having an issue setting variables before application gets boostrap)
These are the sets that I followed
Remove ng-app="appName" from your html file as this is what causing problem. Angular hits this tag and bootstraps your application before anything else. hence application is bootstratped before loading data from server-side (in my case)
Added the following in my main module
var injector = angular.injector(["ng"]);
var http = injector.get("$http");
return http.get("conf/conf.json").then(function(response){
window.appBaseUrl = response.data.gatewayUrl
}).then(function bootstrapApplication() {
angular.element(document).ready(function() {
angular.bootstrap(document, ["yourModuleName"]);
});
});
This will load/set new values everytime you refresh your page. You can change conf.json file even at runtime and refreshing the page will take care of updating the values.

Meteor JS (Iron Router) - Restricting access to server routes

I have a download route in my MeteorJs app which i want to restrict access to. The route code is as follows
Router.route("/download-data", function() {
var data = Meteor.users.find({ "profile.user_type": "employee" }).fetch();
var fields = [...fields];
var title = "Employee - Users";
var file = Excel.export(title, fields, data);
var headers = {
"Content-type": "application/vnd.openxmlformats",
"Content-Disposition": "attachment; filename=" + title + ".xlsx"
};
this.response.writeHead(200, headers);
this.response.end(file, "binary");
},
{ where: "server" }
);
The route automatically downloads a file. This is currently working but I want to restrict access to the route. I only want admins to be able to download it.
I have created an onBeforeAction Hook as below
Router.onBeforeAction(
function() {
//using alanning:roles
if(Roles.userIsInRole(this.userId, "admin"){
console.log('message') //testing
}
},
{
only: ["downloadData"]
}
);
and renamed my route as below
//code above
this.response.writeHead(200, headers);
this.response.end(file, "binary");
},
{ where: "server", name: "downloadData" }
);
The onBeforeAcion hook does not take any effect
Also I noticed neither this.userId nor Meteor.userId works on the route
For the server side hook, I am pretty sure you need the onBeforeAction to have the { where: "server" } part as you do for your route.
Also, I don't think iron:router ever implemented server side user auth on their routing. You may want to check into a package around server routing with larger features such as mhagmajer:server-router that has access to authenticated routes.
https://github.com/mhagmajer/server-router

Switching from iron router to flow router

I'm new to meteor and coding in general. I need to change this to flow router so that I can get the comments to work(I guess). Does anyone want to lend a hand?
Router.map(function () {
this.route('post/:id', {
waitOn: function() {
return [
Meteor.subscribe('post', this.params.id),
Meteor.subscribe('postComments', this.params.id)
]
},
data: function() {
return {
post: Posts.findOne({_id: this.params.id}),
comments: Comments.find({postId: this.params.id})
}
}
});
});
And btw I'm using flow router on everything in the app so I guess iron conflicts with it which gives me this:
Oops, looks like there's no route on the client or the server for url: "http://localhost:3000/recipe-book."

Nested resources and path

I'd like to nest resources in Ember, but to be able to access them with a short URL.
For example: mysite.com/admin will open the route: /routes/profiles/settings/admin
Is it possible to do something like that using Ember?
I'm currently using Ember 1.7 with Ember App Kit.
I tried the following but it doesn't work:
var Router = Ember.Router.extend();
Router.map(function () {
this.resource('profile', function () {
this.resource('profile.settings', { path: '/settings' }, function () {
this.resource('profile.settings.admin', { path: '/admin' });
);
});
Thanks.
Your code doesn't work because your inner most resource is inheriting the /profile path from the outer most resource and /settings from the middle resource. If you want it to be just plain /admin, you'd have to do something like this:
this.resource('profile', { path: '' }, function() {
this.resource('profile.settings', { path: '' }, function() {
this.resource('profile.settings.admin', { path: '/admin' });
});
});
However, this is going to get pretty hairy when you have more routes that each want top-level paths. You might find it easier to just declare a admin route at the top level, then redirect using the redirect hook in the route.

Ember CLI + Ember Data + Simple Auth: authorize gets not called

i am using Ember CLI + Ember Data + Simple Auth. The authenticator is working fine. But when im am doing a Rest Call with Ember Data Rest Adapter this.store.findAll("user"); the authorize function in my custom authorizer don't gets called.
The Rest API Endpoint is on an other domain, so i added the url to the crossOriginWhitelist in my environment.js.
environment.js:
module.exports = function(environment) {
var ENV = {
// some configuration
};
ENV['simple-auth'] = {
crossOriginWhitelist: ['http://api.xxxx.com'],
authorizer: 'authorizer:xxxx',
routeAfterAuthentication: 'dashboard',
};
return ENV;
};
authorizer
import Ember from 'ember';
import Base from 'simple-auth/authorizers/base';
var XXXXAuthorizer = Base.extend({
authorize: function(jqXHR, requestOptions) {
// Some Code, gets not called, damn it :(
}
});
export default {
name: 'authorization',
before: 'simple-auth',
initialize: function(container) {
container.register('authorizer:xxxx', XXXXAuthorizer);
}
};
index.html
....
<script>
window.XXXXWebclientENV = {{ENV}};
window.ENV = window.MyAppENV;
window.EmberENV = window.XXXXWebclientENV.EmberENV;
</script>
<script>
window.XXXXWebclient = require('xxxx-webclient/app')['default'].create(XXXXWebclientENV.APP);
</script>
....
Thanks for help :)
I had a similar problem. For me it was the crossOriginWhitelist config.
I set it like this:
// config/environment.js
ENV['simple-auth'] = {
crossOriginWhitelist: ['*'] // <-- Make sure it's an array, not a string
};
to see if I could get it working (I could), then I could narrow it down to figure out exactly what URL I should use to enforce the restriction (port number and hostname etc).
Don't leave it like that though!
You should actually figure out what URL works for the whitelist, and use that.
I am facing the same issue. I have same setup but the authorize function is not being called. May be you can try by adding the port number in your crossOriginWhiteList url.
I am adding window.ENV = window.MyAppENV line in new initializer which runs before simple-auth. You have added that in index file and may be that is the reason why simple-auth is not able to read your configuration.
Does the other configuration routeAfterAuthentication: 'dashboard', works properly? If not then this might be the reason. Try adding new initializer like
export default {
name: 'simple-auth-config',
before: 'simple-auth',
initialize: function() {
window.ENV = window.MyAppNameENV;
}
};

Categories

Resources