How to handle subdomains in NancyFX routes - nancy

Really liking the simplicity and the power of the NancyFX framework, but I ran into something which I cannot find a good solution for; how to route based on subdomains?
For example; I want to define a route that matches something like
{account}.website.com/restofroute
While having other parts of my site react to the normal www.website.com routing. So basically I want multi tenant support in my site based on the host name.
I found some ways to create and hookup a TrieNode so I can match the host header against some pattern and extract the account itself, but I don't see how I can link this up with the routes itself. Somehow I need to do this in the rootnode I think, so I override the GetMatches and add my local captures to it. Local captures are generated by some regex and contain something like {'account', 'www'}.
I thought I could create something like:
Get["/", a=>a.IsWwwRoute()] = parameters =>
Where IsWwwRoute is a method extension looking at the parameters collection for the account parameter that I included using the local captures. If set to 'www' let it pass, otherwise we use another route (which then uses the account parameter). But I cant find the value anywhere (parameters is null).
So what is the best way to add subdomain routing to NancyFX?

Related

Add pre-defined parameter to all routes

I have an app that has tons of routes and controllers. Our app allows people to create projects and manage them. All of the routes except user related ones requires the project id, currently we store the project id in cookie but plan to move it to urls so the scheme will become /PROJECT_ID/project-related-endpoint from /project-related-endpoint
I basically need to add a prefix to all my routes that represents the current project id but it requires too much work. All of the routes need to change, all redirection calls ($location.path()) needs to be re-written so I'm looking for a solid way to solve this problem. Should I override $location.path() that adds the prefix automatically and change the routes manually or is there any better way to handle this problem?

Providing different routes/logic if on subdomain

What I'd like to do is if someone shits domain.com, hit a certain set of routes, and if you go to site1.domain.com or site2.domain.com, etc, hit a different set of routes. I considered making the subsites a different app, but a lot of components/logic will be shared, just certain parts will be tailored to the subsite.
I'm having difficulty figuring out where and how I should put the logic to figure out if I'm on a subdomain, and thus do an extra API call to get the subdomain's info (as far as I can tell, I just have to use the regular JS window.location object?), and once I have that info, how to modify routes accordingly.
For example, I'd like to have a system where the subdomains can have dynamically created menus, but with the routes being part of the #NgModule decorator, I'm not sure how I can do logic on the routes array prior to it being put in the injector (which is why I assume it's always shown as an array defined outside the class).
I suspect I'm just missing something fundamental about Angular, but I'm not sure what that may be.

URL handling in a Hypermedia (HATEOAS) driven AngularJS application

We are looking for some advice on handling URLs (and the state related to each URL) in a web application backed by a HATEOAS REST API, more specifically on
how to avoid having the web application URLs coupled with the REST API URLs
how to handle multiple resources in a single view
But let me first provide some more context:
We are building an Angular web application on top of a REST layer with Hypermedia constraint. (Note: I prefer simply using the term 'Hypermedia (constraint)' over HATEOAS).
As dictated by the Hypermedia constraint, the available actions and links in the application at any point in time are provided by the REST API. So the web application should not contain any hardcoded urls of the REST API, except for the 'root' (assuming that concept really exists in a REST API).
On the other hand, each page in the web application needs to be bookmarkable. So we cannot create a black-box application (with a single url and all state changes handled in the SPA without changing the URL). This means the web application also has its URL space, which needs somehow to be mapped to the REST API URL space. Which is already a conflict with the Hypermedia idea.
In the Angular application we use UI Router for handling application state. Here is how we got it working:
We only define states, no URLS
We defined a $urlRouterProvider.otherwise handler that will map the current web application URL to the corrsponding REST API URL, retrieve the representation of the resource that corresponds with that REST URL and pass it to the controller (in $stateParams).
The controller can then use the data (and links and actions) in the representation, just like it would if it would have made the REST call itself (or through a service)
So far so good (or not really) because there are some downsides on this approach:
The Web application URLs are mapped to the REST API URLs, so both URL spaces are coupled, which conflicts with one of the basic assumptions of using Hypermedia constraint: we cannot change the REST API URLs without having to change the web application.
In the $urlRouterProvider.otherwise handler we retrieve the representation of the current web app URL. But in some cases we have two resources in a single view (using UI Router nested states): for example a list of items and a detail of a single item. But there is only a single URL, so only the representation of the item detail is retrieved and the list of items remains empty.
So we would love to hear some suggestions on how we could improve on our approach in handling the two URL spaces. Is there a better way to make the REST API dictate the (available) behaviour of the web application and still have bookmarkable URLs in the webapplication? Because now we have some kind of hybrid approach that does not feel completely right.
Thanks in advance.
Regards,
Luc
that's a tough setup. Roughly you want bookmarks into your API, and RESTful systems somewhat discourage bookmarks.
One possible solution is a "bookmark service" that returns bookmark (bit.ly like) urls for the current resource being presents that are guaranteed to be fowards compatible because as you may change the canonical url structure, the bookmark service can always translate the bit.ly like url into the canonical url. Sounds complicated, but we see this all the time and we call them SEO urls eg: /product-name/ maps to products/ today, but may be /catalog/old-products/ tomorrow.
How you match that up to a UI that shows 2 resources the first being a list of summary like resources, and the second being a specific resource get's really tricky. I would expect such a page to know contain the state of what's it's displaying in it's url (probably in the fragment). As such since it's [likely] the controller that processing such commands it probably needs both (the list resource and the expanded resource) as input. I bet the url would look something like:
list=http://path/to/list/results&expand=http://self/link/of/path
So the last part you have is to make sure that works going forwards. Again this is the bookmark problem. What i may suggest if you don't want to build a bookmark service is that given you want to have such bookmarks you need to transition people to the new URLs. When a request is made to http://path/to/list/results and you want to switch that over you should be 301 redirecting them to the new canonical url and the app should be updating the bookmark. such a redirect can include the &flag=deprecate_message param to trigger the presentation in the UI that the client's bookmark is old and should be replaced. Alternatively the response can be internally forwarded and the deprecation flag & canonical (or latest) link included in the response to the old URL. This causes a phased transition.
In summary: I have yet to see HATEOAS be a cure all for backwards & forwards compatibility, but it's much better than the existing techniques. that said you must still make decisions in v1 of your API about how you want your users to move to v2.

Different base url for page routing and templates/partials/RESTful API

My Angular app is splitted into several subapps. I'm working with laravel which is also responsible for the routing between the subapps.
So there are the following urls handled by laravel:
ModuleX: /moduleX
ModuleY: /moduleY
ModuleZ, Item n: /moduleZ/item-n (unlimited amount of items)
And finally on top of these there are my 3 Angular subapps.
So for example: /moduleZ/item-1/#/hello/world
Additionally the templates, partials and a RESTful API are served by laravel under the following urls:
/templates
/partials
/api
If I set the base url with the html tag <base href="http://www.example.com/app/"> I can use relative urls for templates, partials and the api but not for the routing. I'll allways have to add the module url part like that moduleX/#/hello/world.
If I set the base url like for example <base href="http://www.example.com/app/moduleX/"> I can write all links like #/hello/world but the templates, partials and api requests aren't working anymore.
The whole app also sits in a subfolder so I can't just use for example /templates.
So basically my problem or the question now is, what's the best way for handling the different base urls? I don't really like it to prepend the module name to every link.
Look it's might be a particular solution, but may be you should use filters for urls?
For example:
.filter('routeFilter', [function () {
return function (route) {
if (some condition mean this direct html link){
return 'MODULE-X/' + route;
}else{
return route
}
};
}])
I would suggest you let (sub-)apps know their real base not the parent's one, but you make the server responsible for climbing the path hierarchy to find higher level shared resources for missing local ones. This also makes it very easy to prototype new sub-apps, test changes to common pieces independently first, etc.
In a webserver like Apache, this would look like a rewrite rule (conditional on not finding a file) it just substitutes the same file in the parent hierarchy.
In laravel (according to the router docs) it looks like you can add optional 'directories' to your current rules, i.e.:
Route::get('/.../app/templates/{name}', function($name)
...
becomes:
Route::get('/.../app/{module?}/{item?}/templates/{name}', function($name, $module, $item)
...
You could then use $module and $item if you need to test a resource change with specific sub-app/items.
The drawback in making the server responsible for handling inheritance is the independent client fetch/cache of identical resources with different paths. But you can at least choose between large file inefficiency or access latency by using either rewrites or redirects. You can also always hardcode significant paths in production clients later and still benefit from having a hierarchy for testing and graceful handling of occasional errors in client side links.
You can do it in a simpler way if you use combination of service and directive.
You can implement a directive similar to ngHref which when given a link will transform it and append the given link back. It will be injected with a service which will give it the base url or relative url or anything module specific.
This service which is injected in directive will be configured using serviceProvider in app.config block of each sub-app. Since angular injector have only one instance of each service I think you will need more than one injector or one injector per sub-app. Its unclear whether they share injector among them in your app.
You can configure each service according to module to return different base paths. Which will be appended by directive to each link every time.
With this you can use <base href="http://www.example.com/app/"> and that should solve your problem.
I haven't written any code but I can help if you need it.

How to do good custom routing with CakePHP?

I am planning to rewrite my site into CakePHP and after having spent a full week on learning it, I am still not sure how to do good custom routing in CakePHP.
This is what I want:
Keep the current url structure in www.domain.tld/en/dragons.html, or use a www.domain.tld/en/dragons, but not www.domain.tld/en/nodes/dragons.html. And also be able to use controllers on a similar path structure.
There are about 100 static pages on the entire site. I have read into multi-language routing and I think I can do it. I can also make /en/* or /en/:slug route via a PagesControler or a self-written NodesController.
My problem is that I would like to be able to mix and match url's with and without controllers, so actually what I want is that it checks if a :slug is part of the slug-list, there should still be the option to use that url with a controller.
I have created routes for both /en/contact and /en/:slugid, but it seems all queries were routed to my NodesController, even while I explicitly said that /en/contact should be routed to the ContactsController.
How can I instruct Cakephp to keep my current dictorary structure? I read the routes part of the Cakephp book, but it was extremely short and made me a little unsure about the possibility of such routing. If necessary, I'll just write a php-code that prints all routes for all slugs, so I can still write controller-routes with a similar path structure.
If a file exists in webroot (ie. app/webroot/static.html), the .htaccess file will tell Apache to serve that file before loading the CakePHP framework for requests to www.example.com/static.html.
Cake loads routes in a top-down order and will use the first matching route to handle a request. In your case, /en/contact should be above /en/:slugid, else the slugid rule will always win.
If CakePHP's routing does not accomplish what you are after, you can always implement a custom route class (book / example).

Resources