Context
I m actually developping a simple application in which I need to use REST level 3 HATEOAS.
I m having two entities :
User
Billing
I need, when I add a billing, to reference the user inside of it.
Questions
What are the informations I should send to my backend, from my frontend app, to add the hateoas reference, inside the billing ressource, concerning the user ?
I mean, inside the body of the request, should I send the url of the user ressource ? Or should I send the id of the user, and then making an url discovering to get the real user url ?
Related
I have to tables users and teams. The application logic is such that every user should belong to atleast one team(No default here, user can initially belong to any team)
If I am using RESTful APIs to create users resource, should I send the info about user's team in this API itself.
POST /api/users
Or should I make 2 requests
POST /api/users
PUT /api/teams/{id}
If I use the second logic, there is an inconsistency in database if second API is never called.
What is the right thing to do in case of REST design?
What about POST /api/teams/{id}/users.
The URI is self explanatory, you are posting a user directly in a the appropriate team.
Im writing a user registration mechanism by hand so I dont want to use existing plugins or something.
Im wondering what the best way would be. I planning to do the following abstract steps:
Writing an component which is in charge to output a button which calls the facebook-api --> login in via facebook (Im getting token and user name/id)
In my route im using that Data to call the REST-Server-Backend of my app. I will pass the token as well as the username/id to the Server. (POST api.myapp.com/users)
The Server recieves the request and will validate via Facebook-API
the user data and token on its own --> if valid: Add new user to
database.
If the user wants to login now (after registration) he will do again
step no.1 and than will ask the server if the user is existing. But
how: Since ember suggest that the REST-Server is somekind of a
CRUD-Server and using the store is for working for model data only, there
is no possiblity to do a "logic"-call to the server like "ask
him if user with id is existing". Should I call "GET ../users/" and than check in my route if the sum of the returned records are smaller than 1?
So is that a common pattern?
Sounds like a fairly simple OAuth workflow but obviously refer to the facebook docs. As far as point 4 is concerned, I would suggest that yes, on login you make a request for the login route on your server (which should abstract the facebook OAuth call), and if the user is authenticated, then send down the user resource, otherwise redirect them to the login and send down some sort of 401 HTTP error.
As all your API calls should be authenticated too your user won't be able to access any protected API resources.
I would also suggest you look into an ember plugin like ember-simple-auth which also supports OAuth.
You can find more information about OAuth2 workflows here.
Context
I m having two microservices :
User that manages users (crud operations)
Billing that manages billing informations, with a reference to a user
Actually, for me (tell if I m wrong) it's a good idea to store user informations into billing data using hateoas. So we can "walk through it" with an hyperlink in the response of the API right ?
We could obtain something like :
billing:{
// some informations
_links:{
owner:"http://80.80.80.80:7000/users/123456789"
}
}
Questions
How should I do, to create a new billing ? In fact, when somebody post a new billing on the microservice, he sends the user too. Does it mean that I need to have a UserEntity in my Billing service AND my User Service ? So the billing service will be able to marshall the request, meaning code duplication between the two services ? Or should I do something else ?
Then, is this the role of the front end (API consumer) to make 2 requests (one for billing, and one for the user related to the billing) to get the ressource ? Or should the BillingService get the User before responding to the front ?
I have seen in an article, that it's a good thing to use amqp / bus when dealing with microservice, to know if a ressource exists, or to check if it exists. Now we need a service container/registry to dynamically discover other services. In my case I use Zookeeper. But how can I do to tell Zookeeper "give me the location of the service(s) related to the ressource with hateoas links : http://80.80.80.80:7000/users/123456789" ? Am I missing an important information in my hateoas schema ?
How should I do, to create a new billing ? In fact, when somebody post
a new billing on the microservice, he sends the user too. Does it mean
that I need to have a UserEntity in my Billing service AND my User
Service ? So the billing service will be able to marshall the request,
meaning code duplication between the two services ? Or should I do
something else ?
The user that the billing service need is not the same one in the user service. Usually, the user's identity is all the consumer need to post a new billing. If the billing service need more information of the user, it may query from the user service. There may be some code duplicates here, but the code plays different roles in each service which means they can evolve without disrupting each other. Some questions may explain further here: Bounded contexts sharing a same aggregate, Handling duplication of domain logic using DDD and CQRS
Then, is this the role of the front end (API consumer) to make 2
requests (one for billing, and one for the user related to the
billing) to get the ressource ? Or should the BillingService get the
User before responding to the front ?
I think it brings the most flexibility to let API consumer navigate the links. What if the consumer is not interested in the owner detail?
I have seen in an article, that it's a good thing to use amqp / bus
when dealing with microservice, to know if a ressource exists, or to
check if it exists. Now we need a service container/registry to
dynamically discover other services. In my case I use Zookeeper. But
how can I do to tell Zookeeper "give me the location of the service(s)
related to the ressource with hateoas links :
http://80.80.80.80:7000/users/123456789" ? Am I missing an important
information in my hateoas schema ?
Not quite understand this one. If the consumer has the link like "http://80.80.80.80:7000/users/123456789" already, it can access the resource directly. Why should it ask the zookeeper? I think the zookeeper helps the billing service assemble the URI for owner. For example, the billing service tell the zookeeper "Give me the location of the service related to user resource".
Another solution would be that you store all the necessary information in both services. E.g., if you need data of the user within a billing, then just store all the data in the billings datastorage as well. The sync between both services you would do through a queue ( subscribe / publish ). This comes with pros and cons but in the end you end up having one synchronous http call, if you want receive the data for a specific billing.
Context
I have to create a RESTFul API which deal with :
Books
Category of books
The application is splitted like this :
Each client has an API key
Each user of a client can manage (get/post/put/delete) multiple books / categories of books related to the client he is linked to.
Following the REST principle, only the person that creates the ressource, "the ressource owner" can manage this ressource.
First problem
However, in this context, it's possible for a user to share a book to another user related to his ecosystem, meaning that he cans share informations only with the users that share the same API key (the same client).
Does it mean that I have to manage an owner_list in my book object ?
Second problem
I told in the before explanations that I have API keys corresponding to a certain client. Should I have a client_id stored in my user object ? Permitting me to quickly know and share informations between users corresponding to this client_id ?
Third problem
Admitting that I want to work with REST Hateoas, in a Java context. Looking at how hateoas work, it seems that I have to create a specific object that permit me to hyperlink my ressources, like (in JSON) : {hateoas:{key:"user", link:"/users/1234"}} ? Or does it exist something better ?
Last problem
Admitting that I want to work with microservices architecture, and that I have :
A user microservice (for authentication)
A book microservice
I know that I should send informations through AMQP protocol when I need an information from a different microservice.
So :
What kind of exchange / queue (topic, fanout etc...) should I use ?
What kind of information should I send over the network ? Because, okay, I know where the ressource is, with hateoas, but what should I put inside the "tunnel" to have a response ?
Background
I have a RESTful API accessed through the domain http://restapi.com
I have a client app using http://restapi.com. The client app has the domain http://myapp.com
The way I have my HATEOAS setup is that the API presents URIs without a domain. So instead of http://restapi.com/some/resource, it contains links to resources like so /some/resource. Example API json resource below:
{"_links":{"self":{"href":"/some/resource"}}}
The benefit this has is that the API doesn't need to know about the client app, and the client app has to do very little to get the correct resource from the API and doesn't have to reformat all the URIs in the resource. For example, in the client app, the following URI would be used by the browser http://myapp.com/some/resource. When the app gets the request, it then needs to call the API to get the resource and simply swaps the domain i.e. http://restapi.com/some/resource.
This has been successful so for, and allows a lot of flexibility to have different clients use the API with the only knowledge required being the initial end point (domain) of the API. It also completely decouples the API from the client apps.
The problem I have run into is that I have started using some external services (specifically PayPal adaptive payments) where I need to provide a redirect URL for cancelled payments and successful payments. For example, the browser navigates to http://myapp.com/payment. The resource returned by http://restapi.com/payment presents a link to PayPal. Without going into too much detail, the API has to ask PayPal for a payment ID, which can then be used to create a link to a PayPal payment e.g. http://paypal.com?PayId-123456. Part of the creation process requires that URLs are provided to redirect on payment cancellation or success. Again, don't want to go into details, but when requesting a PayId from PayPal, the redirect URLs are sent as variables to PayPal, and I guess PayPal stores them against the specific PayId created.
The browser navigates to the link returned in the resource - http://paypal.com?PayId-12345. Payment is made and PayPal then uses the redirect URLs as needed to redirect back to my app e.g. on successful completion of payment, PayPal should redirect to http://myapp.com/paymentcomplete. Note: I realise that this is not a restfully named URI, but it simplifies building up the description of my problem
Problem
The problem I have may now be obvious. I need to redirect back to http://myapp.com/paymentcomplete, BUT its the API that provides the redirect URL to PayPal. It has no knowledge of the client application. Since PayPal is an external service, the full URL must be provided. The best the API can do is send http://restapi.com/paymentcomplete as the redirect URL, but if PayPal redirects to this, the resulting response will be a JSON string (the output format of my API) not the nicely formatted page of the client app.
My question is, what is a good way to correctly provide the redirect URL to PayPal?
One thought I had was to make the client application handle creating the PayPal PayId, but I don't like this option as I would like to keep the creation of the PayPal payment ID on the API side. It would also require every client app to provide its own implementation, something I also don't want.
The other option I though of was to ask the client to provide its domain in the request. Currently the request the client makes to get the resource with the link to PayPal is GET http://restapi.com/payment, but I could use POST http://restapi.com/payment with the client providing its domain as a param. The API can then use this to construct the correct redirect URL. I don't really like this idea either as its seems a bit hackish and also requires the app to know that is must fill in this field i.e. a human user wouldn't fill the domain input in.
Additional solutions, or thoughts greatly welcomed.
As you had already mentioned, PayPal is an external api that requires this additional parameter and you do not have control over it. Looks like the client is the only party that can provide the Redirect URI Information.
Couple of ideas come to mind.
The client could send the redirect uri to restapi via header and thus
keeping your rest urls intact. This is a grey area and not a violation of restful api
in my opinion. (Then again, its just my opinion).
The restapi could return the response with a placeholder for the
client to fill in before rendering. This way the API need not know
about the redirect uri and the responsibility is left to the client
which has this information.
It would be nicer if you could implement option 2 with executing couple of lines on Javascript code on the browser to fill-in the placeholder. Which is easy. Ultimately, only 2 end points of this transaction would be aware of the redirect uri - browser & paypal.
This alleviates most of your concerns. The job of handling PayPal id will continue to remain with your API.
You should be able to use the Referer header to determine the client's full URI. It might be populated automatically for you. If not, you can add it yourself. The URI class has methods to pull out the client's host for you. When the API builds the PayPal URI to return to the client, it can include the client's host.
Note that referer is not always included and sometimes gets stripped by intermediaries, as detailed on the wiki page. Since you control both the client and the server in this case, you should be able to tell everybody to play nicely.
I would keep the GET http://restapi.com/payment and pass in a query param with the client domain
GET http://restapi.com/payment?domain=http://myapp.com (of course, the "http://myapp.com" needs to be encoded)