Sails.js group routes in v1, v2, etc - javascript

I have API with Sails.js and I want to wrap all my routes in v1. Is it possible?
Here is what I tried, but it doesn't work.
routes.js
'use strict';
module.exports.routes = {
'/v1': { //
'get /cron': 'CronController.start' // THIS DOES NOT WORK
}, //
'get /cron': 'CronController.start' // this works
};

Based on my knowledge of Sails the only way to wrap all of your routes in /v1 is to first ensure the actions boolean in config/blueprints.js is set to true (it is by default), and then further down in that file set the prefix string to "/v1". Here is the documentation detailing this config.
Note that having the actions boolean set to true causes Sails to generate GET, POST, PUT, and DELETE routes for the action, make sure to use policies to ensure no unsafe logic is exposed in this way.

Related

Prefix routes with locale in vue.js (using vue-i18n)

I have a locale.js file which is responsible for defining user locale. Here it is:
import store from '#/vuex/index'
let locale
const defaultLocale = 'en_US'
if (store.getters['auth/authenticated']) {
locale = store.getters['auth/currentUser'].locale || defaultLocale
} else {
if (localStorage.getItem('locale')) {
locale = localStorage.getItem('locale')
} else {
locale = defaultLocale
}
}
export default locale
Also I have a i18n.js file which is responsible for making i18n instance which I use when I init my app.
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import locale from '#/services/locale'
Vue.use(VueI18n)
const fallbackLocale = 'en_US'
let i18n = new VueI18n({
locale,
fallbackLocale,
})
i18n.setLocaleMessage('ru_RU', require('#/lang/ru_RU.json'))
i18n.setLocaleMessage('en_US', require('#/lang/en_US.json'))
export { i18n }
Now I think that it'd be more convenient to have URLs prefixed with locale, like /en/profile or /ru/profile. This way I can share a link with locale which would be already set.
Not sure how do to this though. Making all routes child and put /:locale? is not that convenient because router is not yet initialized (I pass i18n and router instances simultaneously when initing root app instance).
How can I achieve that, what would be the best approach?
You can implement router
routes: [{
path: '/:lang',
children: [
{
path: 'home'
component: Home
},
{
path: 'about',
component: About
},
{
path: 'contactus',
component: ContactUs
}
]
}]
and set locale in beforeEach hook
// use beforeEach route guard to set the language
router.beforeEach((to, from, next) => {
// use the language from the routing param or default language
let language = to.params.lang;
if (!language) {
language = 'en';
}
// set the current language for vuex-i18n. note that translation data
// for the language might need to be loaded first
Vue.i18n.set(language);
next();
});
There are two or three problems I can think of that comes with nesting all your routes under a single /:locale?.
Route definitions may become ambiguous. If you have paths /:locale?/foo/bar and /:locale?/bar defined as routes, what will <RouterLink to="/foo/bar" /> match? That will depend on which of those routes is defined first, and if the second of my examples is matched it will lead to an invalid locale. This problem has a simple-enough solution; just constrain your :locale parameter using a regex. If you know the exact list of supported locales statically, you could do something like:
import locales from '#/lang' // Your list of supported locales.
const regexp = locales.join('|') // You may want to filter out 'en' first.
const routes = [{
path: `/:locale(${regexp})?`,
children: [
...
],
}]
If your translations and list of supported locales are otherwise only available at runtime (e.g. they're retrieved via an API), you may be forced to create a regex specific to your locale tag format. If they match BCP-47, I believe that means either 2 or 3 characters for the primary subtag, and the script and region are optional. If you use normalized tags (lowercase primary, titlecase script, uppercase region), that's even better, because that will further reduce ambiguity:
const routes = [{
path: '/:locale([a-z]{2,3}(-[A-Z][a-z]+)?(-([A-Z]{2}|[0-9]{3}))?',
caseSensitive: true,
children: [
...
],
}]
You'll want to read the spec more closely than I have to ensure that regex is correct. You'll also need to guard against unsupported locales in your beforeEach hook, so that you can load a "Not found" error page.
As long as you do not define any routes whose first path segment could be mistaken for a locale tag, the above should fix the ambiguity problem.
Routes may accidentally be defined using root paths. Nested routes are usually defined using relative paths, i.e. paths not anchored with a /. However, nesting is not simply a mechanism for sharing prefixes or parameters among many routes, it is most often used for sharing layout components. Vue-router therefore allows you to override the parent route definition's path by defining an absolute path. The documentation explains:
Note that nested paths that start with / will be treated as a root path. This allows you to leverage the component nesting without having to use a nested URL.
Mistakenly defining an absolute path will cause the route to only be matched for the fallback (I assume English) locale. As developers are likely to prototype and test using English most of the time, it might not appear like anything is amiss.
For a small application where all your routes are defined within a single file, this may not be a big deal as the error is probably easy to spot. But for a large application with many route definition files and many developers, such an error is going to be more difficult to catch.
Every usage of <RouterLink> and programmatic navigation will require injecting the locale parameter. You'll need to remember to interpolate $i18n.locale into every to prop and push() call. Not doing so does not cause an error or break the page, so your tests are unlikely to catch this, and you won't notice any problems if you're only browsing in English. You could wrap or extend <RouterLink> with your own component that does this automatically, but that doesn't prevent someone from accidentally using RouterLink, as it is still globally-registered. You could also write a global mixin to add convenience methods for router.push()/.replace()/.go(), but this again would not protect you against accidental use of those methods.
One not-ideal solution to the above problems is to forego defining the locale as a path parameter, and instead match it prior to initializing the router. To do this, you have to pass it as the base constructor option. Unfortunately, the base path does not appear to be alterable, meaning locale changes will require a new page request. Since most users will likely change locale at most once, this might not be a huge problem, but nonetheless does not give the best user experience.

How to fetch data from Mirage in Ember.js?

I need to return a list of users from Mirage. I need this list for rendering it on the front end. How do I do this?
To install mirage:
ember install ember-cli-mirage
Once this is done, you need to configure Mirage to send data. This can be done by updating the file mirage/config.js.
In the mirage/config.js file, its better you define a namespace so that Ember application's call does not conflict with the routes defined already.
Say you want Mirage to return a sample list of users. You can do something like this in the mirage/config.js file:
export default function() {
this.namespace = '/api';
this.get('/users', function() {
return {
// list of users
};
});
}
Now whenever the Ember application makes a get request to /api/users , a list of users is returned.
Only doing this isn't enough, you need to make your application to default making requests to the namespace /api.
This is done by creating an application adapter.
To create an application adapter:
ember generate adapter application
Then in app/adapters/application.js, add the namespace like this:
export default DS.JSONAPIAdapter.extend({
namespace: 'api'
});
Restarting the Ember server would include Mirage in your build.
Say you were making a request for all users in the model function of a route:
export default Ember.Route.extend({
model() {
return this.get('store').findAll('users');
}
})
Here, when you request for all the users, Ember data will fetch all users from /api/users.

How to correctly use Express 4 multiple routers

I'm attempting to use the Express 4 Router to use a different router based on the path. I want all /api/v2/ routes handled by version2, and every other route handled by version1. The below setup serves me all the version1 routes correctly, but seems to ignore version2 as I get a 'Cannot GET...' message each time I test those endpoints.
routes.js:
var version1 = require('./routes/vers1');
var version2 = require('./routes/vers2');
module.exports = function(app) {
app.all('/api/v2/*', version2);
app.all('/*', version1);
};
Method routes (.get, .post, and of course .all) are terminal. This is why you can use wildcards with them as well. .use is not terminal and doesn't allow wildcards -- it acts as a prefix. This is an implementation choice of express. Use .use without wildcards.
.use does not set the layer route
all other methods set the layer route
if the route is set, layer attempts to handle the request. Otherwise, the layer's path is stripped from the request route (/api/v2 that you set in .use will be stripped).
The fact that app.use("/*", version1) works is purely incidental. This will match any route and fall through to version1[method](path). Since there is no prefix to strip, if the request route matches path, express will consider this a match and serve that route.
Use .use.
You want to use .use not .all
.all is for middleware like authentication
http://expressjs.com/api.html

Getting Error: Unkown provider: $urlMatcherFactory

Unkown provider: $urlMatcherFactory
This is the error message that Angular throws when I try to inject $urlMatcherFactory in the app config.
I have included the ui-router JS file and have been using it for last few months.
I need to do something like this:
var dateMatcher = $urlMatcherFactory.compile("/day/{start:date}");
$stateProvider.state('calendar.day', {
url: dateMatcher
});
as this example shows.
Normally code like this won't identify $urlMatcherFactory. So I tried injecting it as a dependency on the config but then I get this error.
In this Q&A Matching url with array list of words in AngularJS ui-router you can see how to use the $urlMatcherFactory. Also a link to working plunker .
In that example, the $urlMatcherFactory is used in the .run():
.run(['$urlMatcherFactory',
function($urlMatcherFactory) {
var sourceList= ['John', 'Paul', 'George', 'Ringo']
var names = sourceList.join('|');
var urlMatcher = $urlMatcherFactory.compile("/{source:(?:" + names + ")}/:id");
$stateProviderRef
.state('names', {
url: urlMatcher,
templateUrl: 'tpl.root.html',
controller: 'MyCtrl'
});
}
]);
And that would also mean, that if you are about to use it in a config phase, you should ask for
$urlMatcherFactoryProvider (see the Provider at the end)
BUT: using providers in a config phase means - we can configure them. I mean configure the provider itself. To be later evaluable (already configured) in run phase
Configuring Providers
You may be wondering why anyone would bother to set up a full-fledged provider with the provide method if factory, value, etc. are so much easier. The answer is that providers allow a lot of configuration. We've already mentioned that when you create a service via the provider (or any of the shortcuts Angular gives you), you create a new provider that defines how that service is constructed. What I didn't mention is that these providers can be injected into config sections of your application so you can interact with them!
First, Angular runs your application in two-phases--the config and run phases. The config phase, as we've seen, is where you can set up any providers as necessary. This is also where directives, controllers, filters, and the like get set up. The run phase, as you might guess, is where Angular actually compiles your DOM and starts up your app.

Adding prefix in all controllers & services in sails

Hi Im new to node & sails and the same time doing some standards in my codes. In sails.js I currently have this, for example below
api/
controllers/
TestController.js
services/
TestServices.js
Mostly I can access the view with using only this URL format:
http://localhost/test/
http://localhost/test/<action>
If I add some prefixes to my filename, it will become like this:
api/
controllers/
PrtestController.js
services/
PrtestServices.js
URL by right should be accessible via:
http://localhost/prtest/
http://localhost/prtest/<action>
Questions:
1) if I add prefixes to all my controller & services filenames, is it possible to access the url by:
http://localhost/test/
http://localhost/test/<action>
without adding prefix?
I was thinking of configuring config/routes.js in order to achieve this by editing something like this:
'/test': {
controller: 'PrtestController',
action: '<action>'
},
'/test/*': {
controller: 'PrtestController'
}
Honestly, I haven't tried it yet (it's just an idea before I make major changes in my codes else I might messed it up)
2) Is it possible to have this in sails.js
PrtestController.js > prTestController.js
Thanks in advance!
EDITED QUESTION
Btw I'm using default sails config for controllers having values of:
blueprints: {
actions: true,
rest: true,
shortcuts: true,
prefix: ''
...
}
Example: (my routes.js will be looked like this)
'/test' : 'prTestController',
'/test/action2' : 'prTestController:action2',
'/test/action3' : 'prTestController:action3',
'/test/action4' : 'prTestController:action4',
'/test/action5' : 'prTestController:action5',
'/test/action6' : 'prTestController:action6',
'/test/action7' : 'prTestController:action7',
'/test/action8' : 'prTestController:action8',
'/test/action9' : 'prTestController:action9'
Is it possible for routes that if the url is having /test or /test/any_action will automatically used controller prTestController or prTestController:any_action, respectively?
For #2, yup that's what I mean.
Thanks much!
Yes, you have to edit the config/routes.js in order to do custom routing. If your controller is named PrtestController, then (if activated) the blueprints will automagically set up a route for you to host/prtest/. To override this, turn the blueprints off, and add some custom routes.
Sails docs on routes
If you are having difficulties understanding the magic in Sails, I suggest you to turn off all the blueprints, or at least play with the different settings. By doing this, you have to manually configure routes and actions. When you have an understanding of what the blueprint does and the reason for it, turn it back on if you want to use it.
Here is a video tutorial explaining blueprints and routes in more detail.
Not sure what you mean. Do you wonder if lowercase controllernames are allowed? If so, yes, that shouldn't be a problem.

Categories

Resources