Versioning a JavaScript single page web app? (querystring) - javascript

I have a Single Page App with some static routes such as:
example.org/#!/tools/
example.org/#!/stories/story-1/
These are examples of routes that don't need any versioning. Either the "page" exists, it has been redirected or it is non-existent.
But then I have other resources I'd like to version (because they can have internal states - denoted with a querystring of > 10 parameters):
example.org/#!/tools/population-tool/ + ?a=b&c=d[...]
Because the querystring paramaters might change over time (as the tool might allow more options), I'd like to add a version parameter to these "pages":
example.org/#!/tools/population-tool/ + ?v=1.1&a=b&c=d[...]
So that when a user navigates to the URL without any parameters, the default state and version is automatically added:
example.org/#!/tools/population-tool/ =>
example.org/#!/tools/population-tool/ + version + default state
In case the user decides to share/bookmark this URL, the version paramater will always allow me to remap the paramaters from one version to another.
Can you suggest a better approach?
Perhaps the version should be a part of the url for all routes?
example.org/#!/v1/tools/population-tool/
Or perhaps versioning the querystring is the wrong approach
altogether? Perhaps I should have a method that guesstimates the
right "API" based on the parameters given?
Thanks.

Guessing the right API from parameters can be tedious and will lead to unnecessary complexities in your routing sub-system. It is much more cleaner to having the version information clearly specified in the URL.
Now whether the approach to be followed is 1 or 2 is much of a matter of taste. In my opinion it depends on how perceivable your application version is to the end user. If your end user does not perceive an change in the front-end (ie. if you are following an MVC architecture and the change is only the Model layer while the view layer remains unchanged then approach 1 is more recommended. Where as if it is important for the user to be aware of which version he is using or if the user-interface visible to end user is different across versions then approach 2 is a better option because it puts the version information in a prominent position in the url.
Another way of looking at it can be asking the question if application state is different between versions. A url (sans the query parameters) represents the application state and in case the answer is true then 2nd approach should be followed. However if the version information is abstracted away from the main application code and is relevant only to certain abstracted sub-sections eg. only a few model classes then approach 1 should be followed.

Related

In clean architecture between entity layer and use-case layer. What is the use-case boundary?

As I understand Entity caries fundamental properties, methods and validations. An User Entity would have name, DoB...email, verified, and what ever deemed 'core' to this project. For instance, one requires phone number while a complete different project would deem phone number as not necessary but mailing address is.
So then, moving out side of Entity layer, we have the Use-Case layer which depends on entity layer. I imagine this use-case as something slightly more flexible than entity. So this layer allows us to write additional logic and calculations while making use of existing entity or multiple entities.
But my first uncertainty lies whether use-case can create derived values(DoB => Age) from entity properties and even persist them in storage or does it need to already exist in User Entity class already ? Secondly, does use-case layer even NEED to use entity, could I have a use-case that literally just sums(a, b) and may or may not persist that in storage anyways? Thirdly, when persisting entity related properties into database, does retrieving them require once again validation, is this redundant and hurting performance?
Finally, the bigger quesetion is, what is use-case ? should use-case mean to be adaptable by being agnostic of where the inputs comes from and what it serves to? does this just mean the inversion dependency removes the responsibility of what framework it ties to. I.e. using express or Koa or plain http wouldn't force a rewrite of core logic . OR does it mean adaptable to something even greater? like whether it serves directly at the terminal-related applications or api request/response-like-applications via web server?
If its the latter, then it's confusing to me, because it has to be agnostic where it gets/goes, yet these outputs resembles the very medium they will deliver to. for instance, designing a restFUL api, a use case may be...
getUserPosts(userId, limit, offset). which will output a format best for web api consumers (that to me is the application logic right? for a specific application). And it's unlikely that I'll reuse the use-case getUserPost for a different requestor (some terminal interface that runs locally, which wants more detailed response), more or less. So to me i see it shines when the times comes to switch between application-specific framework like between express/koa/httprequest/connect for a restapi for the same application or node.js/bun environment to interact with the same terminal. Rather than all mightly one usecase that criss-cross any kind of application(webservice and terminal simultaneously or any other).
If it is allmighty, should use-case be designed with more generalized purpose? Make them take more configurable? like previously i could've add more parameters getUserPosts(userId, limit, offset, sideloadingConfig, expandedConfig, format: 'obj' | 'csv' | 'json' ), I suppose the forethought to anticipate different usage and scaling requires experience - unless this is where the open-close principle shines to make it ready to be expandable? Or is it just easier to make a separate use-case like getUserPostsWebServices and getUserPostsForLocal , getPremiumUsersPostsForWebServices - this makes sense to me, because now each use-case has its own constraints, it is not possible for WebServieces to reach anymore data fetch/manipulation than PostsForLocal or getPremiumUsersPostsForWebServices offers. and our reusability of WebServices does not tie to any webserver framework. I suppose this is where I would draw the line for use-case, but I'm inexperienced, and I don't know the answer to this.
I know this has been a regurgitation of my understanding rather than a concrete question, but it still points to the quesiton of what the boundary and defintion of use-case is in clean architecture. Thanks for reading, would anyone chime to clarify anything I said wrong?
But my first uncertainty lies whether use-case can create derived values(DoB => Age) from entity properties and even persist them in storage or does it need to already exist in User Entity class already ?
The age of a user is directly derived from the date of birth. I think the way it is calculated is the same between different applications. Thus it is an application agnostic logic and should be placed in the entity.
Defining a User.getAge method does not mean that it must be persisted. The entities in the clean architecture are business object that encapsulate application agnostic business rules.
The properties that are persisted is decided in the repository. Usually you only persist the basic properties, not derived. But if you need to query entities by derived properties they can be persisted too.
Persisting time dependent properties is a bit tricky, since they change as time goes by. E.g. if you persist a user's age and it is 17 at the time you persist it, it might be 18 a few days or eveh hours later. If you have a use case that searches for all users that are 18 to send them an email, you will not find all. Time dependent properties need a kind of heart beat use case that is triggered by a scheduler and just loads (streams) all entities and just persists them again. The repository will then persist the actual value of age and it can be found by other queries.
Secondly, does use-case layer even NEED to use entity, could I have a use-case that literally just sums(a, b) and may or may not persist that in storage anyways?
The use case layer usually uses entities. If you use case would be as simple as sum two numbers it must not use entities, but I guess this is a rare case.
Even very small use cases like sums(a, b) can require the use of entities, if there are rules on a and b. This can be very simple rules like a and b must be positive integer values. But even if there are no rules it can make sense to create entities, because if a and be are custom entities you can give them a name to emphasize that they belong to a critial business concept.
Thirdly, when persisting entity related properties into database, does retrieving them require once again validation, is this redundant and hurting performance?
Usually your application is the only client of the database. If so then your application ensures that only valid entities are stored to the database. Thus it is usually not required to validate them again.
Valid can be context dependent, e.g. if you have an entity named PostDraft it should be clear that a draft doesn't have the same validation rules then a PublishedPost.
Finally a note to the performance concerns. The first rule is measure don't guess. Write a simple test that creates, e.g. 1.000.000 entities, and validates them. Usually a database query and/or the network traffic, or I/O in common, are performance issues and not in memory computation. Of cource you can write code that uses weird loops that mess up performance, but often this is not the case.
Finally, the bigger quesetion is, what is use-case ? should use-case mean to be adaptable by being agnostic of where the inputs comes from and what it serves to? does this just mean the inversion dependency removes the responsibility of what framework it ties to. I.e. using express or Koa or plain http wouldn't force a rewrite of core logic . OR does it mean adaptable to something even greater? like whether it serves directly at the terminal-related applications or api request/response-like-applications via web server?
A use case is is an application dependent business logic. There are different reasons why the clean architecture (and also others like the hexagonal) make them independent of the I/O mechanism. One is that it is independent of frameworks. This makes them easy to test. If a use case would depend on an http controller or better said you implemented the use case in an http controller, e.g. a rest controller, it means that you need to start up an http server, open a socket, write the http request, read the http response, extract the data you need to test it. Even there are frameworks and tools that make such an test easy, these tools must finally start a server and this takes time. Tests that are slow are not executed often, are they? And tests are the basis for refactoring. If you don't have tests or the tests ran slow you do not execute them. If you do not execute them you do not refactor. So the code must rot.
In my opinion the testability is most import and decoupling use cases from any details, like uncle bob names the outer layers, increases the testability of use cases. Use cases are the heart of an application. That's why they should be easy testable and be protected from any dependency to details so that they do not need to be touched in case of a detail change.
If it is allmighty, should use-case be designed with more generalized purpose? Make them take more configurable? like previously i could've add more parameters getUserPosts(userId, limit, offset, sideloadingConfig, expandedConfig, format: 'obj' | 'csv' | 'json' )
I don't think so. Especially the sideloadingConfig, format like json or csv are not parameters for a use case. These parameters belong to a specific kind of frontend or better said to a specific kind of controllers. A use-case provides the raw business data. It is the responsibility of a controller or better a presenter to format them.

Dynamically adding routes and components in Mithril

Mithril's website states:
You can only have one m.route call per application.
So I was almost able to do a work around with code splitting.
But my application is only aware of the first-level components for a given URL which it utilizes the async code splitting to accomplish.
Now the problem: Those first-level components would then like to register their own namespaced routes to leverage URL state change for their own inner components since I can't register their routes ahead of time (and Mithril prevents setting the routes again after the initial route was set by the app/wrapping component).
To further the complexity of the issue, each first level component is loaded on an as-needed basis, so I can't wait for all the first level components to load and then instantiate the m.route; routes have to be added dynamically.
I love this framework, but my use case seems like an edge case that I can't seem to resolve.
The simple solution would be to re-instantiate the m.route object after each first-level component loads, but that's not supported.
UPDATE
The purpose of my post was to find a native way to do dynamic routing and not lose functionality (such as variadic routing), but its been reinforced that that's not possible.
I replaced the entire router with an in-house one so I could support dynamic (and unknown) routes, more flexible variadic routing, better params method, and even provide get/set global data across views without a global window variable or use of the History API in that case. I still provide the rest of the functionality that Mithril does, just a little more simply.
Why not do a pull request? From what I've read on different Github pages, two big pieces of this would not work with the core logic of Mithril; and/or, is too much of an edge-case that they don't want to support it.
I'll still choose Mithril over any other framework though.
In the meantime, I built what I need, and hope Mithril 2 will have dynamic routing baked in.
Mithril's router is intended as a relatively simple solution to easily enable standing up simple SPAs, dynamically registering routes isn't part of the current design.
I think you'll probably be best served by finding a router that supports the dynamic route registration you require and using that.
Integration of that router with Mithril could be naive (using m.mount() when routes change) or more complex by emulating a bit of the logic of the existing router API.
Mithril's router is not the most advanced tool. Although you can work around it pretty much however you want.
There is a way to make new routes dynamic.
I made a little jsfiddle a while ago. https://jsfiddle.net/Godje/cpzLtoyz/
You are interested in lines 2-11 and 63-92.
Although they aren't dynamic in the fiddle, you can make a function, to replace that switch on line 73, which will process your routes and return a component needed to be rendered. That way if you have an array stream with all the URLs or other routes you want, you can have a function process each param on each route-change call and check it with the array.
Sorry for a messy response. Writing an exact solution to the problem requires a local server.

Best practice to change default blueprint actions in sails.js

I'm looking for an answer to what is the best practice to customize default sails.js CRUD blueprints. The simple example of what I mean is let's say I need to create SomeModel, using standard blueprint POST \someModel action, and also I want to get information about authenticated user from req object and set this property to req.body to use values.user.id in beforeCreate function:
module.exports = {
attributes: {
// some attributes
},
beforeCreate: function (values, cb) {
// do something with values.user.id
}
};
I'm very new to sails.js and don't want to use anti-patterns, so I'm asking for inputs on what is the right way to handle such cases. Also it would be great to have some good resources on that topic.
There are a few options open to you which you've identified, and as usual, it depends on your use case. Here are some thoughts on the three options you listed in your comment:
Override controller/create - Of the three, this is the best option because it doesn't clog up code in routes or policies for a single instance.
Write controller/action and add to config/routes.js - While this works, it defeats the purpose of using blueprints, and you have to do all the code in option 1 plus making your routes code messier.
Apply a policy for a single create action - To do this, you will not only have to clutter up your /policies folder but also your policies.js file. This is more code AND it puts the logic for one controller method in two separate places, neither of which is the controller.
Out of these three, option 1 is the best because it contains the code to its context (the controller) and minimizes written code. This is assuming that you only want to alter the create method for one model.
Side note:
As an example of how your use case determines your implementation, here is how I've set my Sails app up which has a few REST routes, each of which responds differently based on the user calling the route (with a valid Facebook token):
Only uses blueprint action routes (not blueprint REST routes)
First goes through the policies:
'*': ['hasFBToken', 'isTokenForMyApp', 'extractFBUser', 'extractMyAppUser'] which store fbuser, myappuser, and other variables in req.body
At this point, my controller function (e.g. controller.action()) is called and can access information about that user and determine if it has the correct permissions to do CRUD.
Pros of this system:
All code for each CRUD operation is contained within its controller function
Minimal to no code in routes.js (no code) or policies.js (one line) or /policies
Works well with API Versioning (e.g. controllers/v1.0/controller.js), which is much easier to do with versioned controllers than versioned models. That means that I can create a new API version and simply by creating a controller in /v2.0 with a function action(), calls such as POST /v2.0/controller/action will exist with no extra routing needed.
Hopefully this example helps illustrate how design decisions were made to offer functionality like API versioning and consolidate code in its specific context.

Best way to detect browser state changes

And with state I mean URL changes, preserving browser history.back() and being able to update the page (through a callback I guess) when there is any change.
I've tried several methods, and each one has its pros and cons.
For example, I like the way Backbone.js manages the URLs with its Router because it works via the window.location.hash (#) and if you change the URL manually it's catched by the Router allowing you to perform manual changes in an easy way.
The thing I don't like about Backbone is the URLs being in this format "#/a/b/c/d/e" (against the classic http standard "?a=1&b=2&c=3". That means that the URL parameters needs to be in certain order and they don't have name. Of course you can fix that parsing the URL and treating the Router expression as a single string, so it's not a big problem.
Also, I think using Backbone just for its Router it's a bit overkill (including the whole BackBone just for that), so I'd like other solutions.
The next one is History.js, which is supossed to provide compatibility for the new HTML5 standard?
But I don't like its behaviour as much as the Backbone's one. I mean, in an HTML5 browser, the # is converted to ? and if you change something in the URL the whole page is reloaded.
Also, due to its lack of Router, you need to set some more listeners, like $(window).bind('statechange') and $(window).bind('hashchange'). Again this is not a big problem, but I'd like to know if there are other ways to do this.
I always say that "there's no a right way to do something, but different ways to achieve it". But to be able to choose one of that ways, I'd like to know about different possibilities.
What do you think about this problem, which is more and more common when developing Single Pages?
I've researched a bit, but all the answers I found are quite old (> 1 year+) so I'm interested on the state of art...

Marionette Event Aggregator vs Backbone Router

I'm pretty new to this world so I need some clarifications on it. Maybe I could be wrong on the subject. So, feel free to correct me.
I'm studying how Marionette and Backbone work together. Oh yeah. Marionette gives us extension to Backbone. Really nice stuff.
The thing that is not obvious to me is when to use the routing mechanism provided by Backbone and when to use publisher/subscriber pattern by Marionette.
Is there any rule of thumb?
Here, Where to use event aggregator in backbone marionette?, a similar discussion but there is no advice on how using that or the other.
My take on the route management is explained in the free preview to my book on Marionette (http://samples.leanpub.com/marionette-gentle-introduction-sample.pdf)
Basically, my opinion (others don't necessarily share it) is that Backbone's routing should be used to configure the application state when the user "enters" the application via a URL. In other words, it will parse parameters, and call proper controller actions.
But once that initial state is setup, routing code should no longer be triggered, even as the user navigates through the application.
Here's an example:
The user enters arrives on the "contacts/2/edit". Backbone routing code will extract the 2 argument and call the edit controller action with that id parameter (which fetches that contact, displays the proper views, etc.). In other words, the initial application state is being configured.
The user clicks on the "show all contacts" link leading to the "contacts" URL. Here, I believe this modification should be handled through Marionette events (i.e. indicating the user wants to see all contacts). After all, we know what the user wants to do, and which URL fragment should be displayed. In other words, there is no reason for the routing code to get involved.
Note that this is my opinion, and other developers simply pass trigger: true when the user clicks a link. But as I explain in the book extract linked above, this tends to lead developers to create "stateless applications in javascript" (e.g. passing lots of parameters in the URL, even though they should be stored in the application's state). Ater all there is a reason that by default, Backbone's navigate method has trigger: false.
Derick Bailey (Marionette's creator) also discussed the issue here: http://lostechies.com/derickbailey/2011/08/03/stop-using-backbone-as-if-it-were-a-stateless-web-server/
Event aggregator is more useful for notifying things. (think small bits of feedback)
Message from server (updated record)
Let other models know things have changed
Lock everything down while saving until saved
Single Moment in time things
Router is for things where you want the state to be save-able (think separate page in a MPA)
Model Edit Page
Model View Page
Something that will stay until another event or activity changes it
If you are not sure if something is an event or a page, then think about it and ask that separate question.

Categories