How should a React app (or any SPA) interact with a HATEOAS back-end? - reactjs

The basic question is if there should be one HATEOAS entry point per page or one entry point for the entire app?
Most examples I have seen implement a single page with a HATEOAS backend, e.g. a list that is paginated using prev and next links. But what happens when the app navigates to a different page that has completely different capabilities and needs a different entry point? How does one organize such an app?
Concrete example: We have an app with tab navigation. The home tab shows a product catalog so the entry point is /products which returns page 1 of products along with pagination links. However, now I click on the orders tab which must show a list of past orders. This page needs a completely different entry point /orders which the home tab knows nothing about. In fact, user can directly navigate to the orders tab using a deep link.
How to think about this problem? Are there any examples illustrating an approach?

There's a few different ways to solve this. Here's two:
The SPA takes context from the uri (such as an id), and uses it to search on the API. The API can describe templated links/actions to search for resources by their id.
Instead of doing client-side routing, let the server decide what to render.
We're going more towards #2. If we have a uri such as:
https://spa.example/https://api.example/foo/bar
We take the path part of this uri and hit the API. Based on what the API responds with, we decide what to render. This means that most of the routing for these kinds of endpoints is delegated to the server, which feels more in line with HATEOAS.
The path part in this case is an entire absolute URI, but we also support relative uris and have a default base uri. So in practice these two uris are equivalent (for our SPA):
https://spa.example/https://api.example/foo/bar
https://spa.example/foo/bar
We develop & use ketting / react-ketting to do most of the heavy lifting

Related

referrer in segment.io analytics.page() in a SPA

I am trying to integrate segment.io to work with Angular. My angular app is a SPA so I have to add some code to my components to allow segment to register the page visits.
In the code used to register page visits, there is a property called referrer that, according to the docs is:
Full URL of the previous page. Equivalent to document.referrer from
the DOM API.
The problem I am having is the referrer property value sometimes just remains empty, or sticks to one page even if I move to several other different pages.
So my questions are:
Does referrer mean links outside my app or also the previous routes visited within my app?
Am I supposed to set this manually in the app?
Yes, you're supposed to set it manually in your existing pageview hits to Segment.
Basically, in your case, referrer would be just the previous route. If the previous route doesn't exist, then use the document.referrer.
And yes, organically, if your app doesn't have a previous route, then document.referrer may contain an outside url, which is completely fine and expected.
Also, Segment provides pretty neat support for questions like this, so you can confirm with them.

SPA - When to use Location Based or Internal State?

Hopefully this is not too opinionated but I am wondering if there are best practices regarding location-based SPAs and Internal based SPAs.
Internal based SPAs - track state internally
Location-based SPAs - URL location / Sessions , etc
In one part of my site if a user pastes in the url the search results will show.
However if I should be doing it for areas like admin section.
For instance I am allow users to add inventory to this point
admin -> add new Inventory -> choose center -> choose subcategory -> add inventory.
This is pretty much the flow, however if I would make it location based then on the "add inventory page" I would have to set the
company
center
subcategory
Which would require ajax requests to get all the data and basically every page I would have to do setting up data. It just seems like alot of work that every page has to be fully setup if they are coming from a url.
I am already using stuff like react-router to do my routing but in the end of the day I would to make sure that everything is always setup to the page can basically run standalone.
So maybe in some situations it would be better to somehow just redirect users back to the root of everything instead?
I would recommend using React Context for resolving your problem.
Once authorized, you can set the Provider value to be the user or their permissions, then on each ComponentDidMount or render() or whatever lifecycle hook you choose, you can check the users permissions and then allow the functionalities based on that.
Context values persist throughout routing, so you won't have to worry about updating it all the time (although you probably should if your user has a timed session).
So it is fully possible and probably more effective to use a mix of both internal and location based state management.

Rendering Just one module/state of Angular app

I've angular app with lots of states and modules etc. Now, I want to send a link to the user. When user'll hit this url, I want to redirect him to a new tab rendering only that particular state (specified in URL) i-e I don't want anything else to be visible to the user. Or you can say, I want to open a popup window rendering that particular state's html in popup window . This is the approach that comes to my mind to sort it out.
Ps. There are Rest APIs at the backend which I am calling through angular resource service to bind data with the model of the views
Option
I've rest APIs on backend, So, I was thinking to developing s separate Nodejs application, And I will send nodejs application url to the user and in the default/home route I'll call backend API and, the returned resultset will be rendered in html file within nodeJs application and this way, I'll render the corresponding data to user's browser window.
This is the flow for that
I don't know if that is right or clever approach. Please suggest me what will be the best approach to sort it out.
Thanks in advance.
This is what my app looks like
Everything in the left side-nav is a module and clicking on this I am routing to a different state. I am using angular-material and lots of other dependencies in this project.
And this is what I want.
I'll refer a link to the user for example www.myapp.com/specificpage.html. And hitting this url, a new tab/popup will be opened rendering state defined in the same app but with some non-editable url. And it should like.
There are multiple ways to achieve this and each approach has advantage and disadvantage. You have to choose depending on requirement and architecture. Details are below-
Create a separate app - You can do it through separate code base or use the module based build process and include this module only for new app.
Divide application is two part, public pages and private pages - Include this page and required APIs for this page in the public modules for your app.
Send token in the link - If you want to make secure page, send short lived token in the eMail and validate token on the server before displaying page to the user.

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.

Best practices for setting up Routes in AngularJS the RESTful way

I'm building a UI using AngularJS that consumes a REST service:
Here is the Server API
/items/ GET
/items/:id GET
/items/ POST (to create new item)
/items/:id PUT (to edit item)
/items/:id DELETE
What are the best practices when setting up the routes in Angular? These routes would map to the server REST API, but obviously there is a problem. I'm guessing I would need the action as part of the URL, right? Something like this:
Angular Routes:
/items/
/items/:id
/items/new
/items/:id/edit
/items/:id/delete
However the above pattern also has a problem. /items/new will match both /items/:id and /items/new so what is the best practice when setting up a route for create?
Also keep in mind that the client side, Angular, routes you're defining could be dependent on your UI. The routes you've defined are more like a traditional web application where you click an "Add New" button that takes you to a new page that has a form that you fill out. However, this may not be the pattern you use for a Single Page App (SPA) as is often created with Angular.
By this I mean that most of the SPA apps I've done don't actually have a standalone "/items/new" route on the client side. Instead, the "/items/new" functionality is handled on the "/items/" route/partial ("page" in traditional web app terms). This page lists the existing items, and there is a form on this page that you can fill out to create a new item. Or, there is an "Add New" button on this page (just like a traditional web app); but, clicking it either slides in a modal form or ng-shows a form that is already defined (but initially hidden) on the /items/ partial template.
Upon submission, the controller hits against "POST /items/" on the server to create the new item, updates scope with the return value from the POST (assuming success, this would be the new item info), and clears/re-hides the "new" form.
Bottom line -- keep in mind that in a SPA you may not actually need a "/items/new" if the UI is such that the new is handled as a capability of the item list page. Of course, if you're needing it to be a standalone page as an addressable endpoint (i.e. you're planning to link to this from multiple places, not just from within the app), then you'll obviously need a direct route.
In our case, we typically don't need a named route for it in our apps and we just have it serviced as a capability of the "/items/" route.
Using UI-Router we can setup client side routing.
Make sure you disable html5 routes, because some browsers still doesn't support html5 and they hit the server api instead of hitting the client route
You can do this by setting $locationProvider.html5Mode(false); in app.config method while defining angular app
/items/ - this is for listing items
/items/{id:[0-9]{1,4}} - this is for displaying one item in detail
/items/add - for displaying new item form
/items/:id/edit - for displaying existing item in Form for editing
/items/:id/delete - **This is not required, I mean you just hit the API when
use clicks delete, we cant show any deletion form**
You can use regex for params '/items/{id:[0-9]{1,4}}' this means allow only numbers 0 to 9 and 1 to 4 characters long

Resources