Assuming a resource X(http://example.com/a/foo/7) from rest-service A needs to hold a reference to a second resource Y(http://example.com/b/bar/1) from rest-service B.
How would one persist the reference?
Currently I'm storing the whole URI (as a string) of Y in the persistence layer of service A. Is this a common/valid approach?
It seems wrong to me to extract the id(1) out of Y's URI as I would implement assumptions about the URI structure of service B in service A. Is this correct?
How do you solve this problem?
Thx!
Lets discuss it with some actual business domain , then the answers will make sense.
So first example:
X represents Order Entity in Amazon Order Service, Y represent Customer in Customer Service.
Now while fetching the order from Amazon from Order Service, you also want to show some basic customer detail and link to customer Object to go to Customer Detail Page.
In this case what I would do is while creating the order copy some basic attributes of the customer in Order Entity (customerName , customerArea).
Also store customerId, customerType. And as the API for fetching customer is Public and also exposed to various internal services, Order Service will do a Service discovery and create URL and call. In these cases generally customer service will not stop supporting the old way (even if they are building a new one).
So storing just the id is a solution.
CASE 2:
Amazon Order Entity wants to store delivery details and delivery partner is some third party entity like DHL , then if DHL provides a URL to fetch the delivery updates to the order, in those cases I will just store the URL.
Generally I will prefer to store id and service type and some basic details to create a good customer experience and also avoid hitting one extra service api for getting the basic detail like customer name.
Storing direct URL makes sense when its a third party URL.
Also if you can give certain example of your business case like this, we can discuss better
IMO references should be stored as is. How you get the actual data from reference should not be part of the data but the logic which may change from time to time.
I will store them as reference of external reference (just to paint the picture that reference is out side our service) and coupled it with a logic to query the data.
URL is very volatile and may change. As a rule of thumb you should never keep urls in you database and should rely on service discovery to identify where the service is even if its within you own infra.
Its not an assumption, its a contract, which may changes and if it does, your service will be dependent service and has to make due changes
Also by your logic, even if you keep url, response to it is still a contract that both of you adhere to.
Related
Make-up scenario:
Let's say I am building a RESTful Web API backend for managing the payment plans for members:
It's for members so you would have to register with us. Each member would have a member ID internally.
There are various payment plans: 0% interest for 6 months, 0% interest for 12 months, etc. Each payment plan would have an ID internally.
The relationship between member and payment plan is many-to-many.
Each member also would have 1 active plan at a time. You can change it, but there is only 1 active plan allowed for a member.
Now if I want to design an API endpoint to return the information about the member active payment plan, I would normally do something like:
/members/{member-id}/plans/active
I understand that it might be a bad idea to put state on the URI (I had a separate question for that matter), but please bear with me.
Now here is the tricky part: the company's policy states that I can't have the member ID in the URI. They will have some kind of tokens in HTTP header, which is required in order to access the RESTful API endpoints, that contains the member ID.
My API application, which is ASP.NET Core Web API by the way, has no problem creating a filter to parse that token and transform it into member ID, in the code. It's just that my API URIs can't have the member ID anymore.
How would you design the URI in this case?
Without the member ID on the URI, mine would look like
/plans/active
And the data now would be all driven/filtered by that member ID, securely inside the API backend. Is this normal?
the data now would be all driven/filtered by that member ID, securely inside the API backend. Is this normal?
It sounds to me as though things are going sideways; as though people don't understand REST, or that people don't understand that what they are trying to achieve isn't a good fit for REST.
In order to obtain a uniform interface, multiple architectural constraints are needed to guide the behavior of components. REST is defined by four interface constraints: identification of resources.... -- Fielding, 2000
REST uses a resource identifier to identify the particular resource involved in an interaction between components. REST connectors provide a generic interface for accessing and manipulating the value set of a resource, regardless of how the membership function is defined or the type of software that is handling the request. The naming authority that assigned the resource identifier, making it possible to reference the resource, is responsible for maintaining the semantic validity of the mapping over time (i.e., ensuring that the membership function does not change). -- Fielding, 2000
The web works on the shared understanding that uniform resource identifiers identify resources. The URI is the key of the key/value store. When you start moving identifying information into other parts of the request, then you are opting out of the "uniform interface" that is shared by everyone else. This puts interop at risk.
On the other hand, much of the web also assumes that identifiers are published, and there isn't in general a lot of discipline to restrict the copying of them. So you certainly don't want secrets and/or sensitive information included.
The answer in REST is to use another layer of indirection. The rule is that we should be using a URI, and each identifier should map to one resource. But there's no rule that says that the spelling of the URI must match the semantics of the resource.
In other words: URL shorteners work!
GET /99bfb1e3-89a4-4a44-a6d7-0e70c209f447 HTTP/1.1
As far as REST is concerned, that's a perfectly valid request, with an entirely satisfactory identifier. As long as your server understands how to find the secrets using that key, then that's fine.
Of course, you could add semantic information to the URI that isn't sensitive, to help the humans orient to the context
GET /members/99bfb1e3-89a4-4a44-a6d7-0e70c209f447/plans/active HTTP/1.1
GET /members/plans/active/99bfb1e3-89a4-4a44-a6d7-0e70c209f447 HTTP/1.1
GET /members/plans/active?99bfb1e3-89a4-4a44-a6d7-0e70c209f447 HTTP/1.1
These are all also fine (again, assuming that you can use the information provided to discover the sensitive information you need to produce/modify the corresponding resource).
On the other hand, if your organization's concerns are related to leaking the identifier itself... then somebody with seniority should really be challenging the assumption that REST/HTTP is the right answer to the problem.
As your deviate further from the "standard" for HTTP messages, you increase the risk that some general purpose component isn't going to understand what is going on, and if that results in significant loss of property, your lawyers aren't going to be happy.
In my opinion this is pretty normal. This is usually the case when you are using a JWT token for authentication for example. The token not only authenticates the user but also contains relevant information about it.
In these cases, you will also see APIs with that kind of endpoints without any information about the user (like an ID or something) explicitly in the path.
Just a suggestion or a point of view from my side, I would actually keep the members part in the path: /members/plans/active.
I am trying to add user and friend services using lagom framework. I read lagom persistent doc but still not able to understand how should I decide on entity id? Since it should be unique to retrieve it back. The random uuid generated is one option but that would be unusable since while sending command those uuid will not be available to other user/services.
Here are two solutions I can think of:
1) use email as entity id.
2) push the uuid and user name/id in database so that service retrieve uuid and then send command.
As per my understanding Solution 2 is two step process and defeats the purpose.
Solution 1, for other services like friend service there might be cases which can be duplicated or needs to send more information to retrieve the entity id.
Also I couldn’t find a better way to implement dean on services in this framework. Is there a way to do that?
There are no simple answers to your question, because it all depends on how the interaction between the services will look. But you should think about Entity Id as a unique identifier which also doesn't change in time. Changing Entity Id means creating new entity. In my opinion, email is not a good candidate for an Entity Id, because user may change it and also use more than one. I would go for UUID and would keep track on emails, plus expose methods which can handle communication between the services using for example user email (one of his emails), phone number(s), 3rd party service Ids, etc.
I'm refactoring a application to DDD, and so far so good but i got a doubt about some responsibility and what are the best approaches to solve it.
The application is a web app that call center agents use, with CRM features, the backend is a REST API.
The use case is as follows: The agent calls to a customer and need to collect some information / offer promotions etc.
After calling the customer and talked to him, he needs to fill some information for this contact attempt, some of that information is combo box with data filled from the database, and it sends a POST with the IDs of the entities to a endpoint to register it.
So we have a endpoint contactAttempt that receive the data, customerId, agentId, some combo box info (subjectId, reasonId, extraInfo1, extraInfo2), the extra info doesn't call that, but just to simplify.
That information is deserialized to a DTO object that is passed to a application service, which consult the respective repository to check if the ids are valid and return the Entities, if the entities are not found, it throws a exception that the controller catches and answer the client with a message.
If all the entities are valid, there are some domain rules, like if is the first contact with the customer, sends a welcome e-mail, and other stuff.
My doubt is with this steps of fetching entities from the Repository, it should be like that or should i fetch it in the controller, and if all that i need is present, then i pass to the domain service with just the logic needed to apply the business rules?
What are the pros and cons of the mentioned approaches?
Is there other approaches?
In the context of a MVC, what is the responsibility of the Controller?
The MVC is responsible to deserialize the HTTP request in a message for the "application layer".
So it should get from the querystring/body/headers all the values needed and pass to a service as immutable values (command). This because the application service (handler, whatever) should execute the command transactionally, and if the entities (so, the behavior) are accessed outside the application layer, you can't assure that no modification happens outside the application layer.
For example: We have a User model, which in turn has several Company entities. I see 2 solutions:
1) Classical. Make an API like:
/users/
/users/3/
/users/3/companies/
and issue /users or companies request separately. However, if we need to have both user and his/her companies information in one view (on Angular2) - we need to send 2 requests to the server.
2) Put the related/nested data inside the level-1 object model. In request:
/users/3/
the server will provide information about the User, together with his Companies. In this case we get all information for 1 request. But again, the company has an unlimited number of Storage entities. What if they are required in one separate view?
I'm more inclined to the first option, but I'm confused by the description of the REST style: "The view must fully represent the resource." Satisfaction of this requirement can lead to a partition of the resource into child resources and, accordingly, to smaller representations. "
Please, help with advice, I doubt in connection with the lack of experience what decision will be correct in this case. Oh yes, I forgot, Backend on Django (Python) using Django-Rest-Framework - All this is a SaaS for ~ 1000 users.
Approach 1 is an an ideal approach for REST. But when it comes to designing APIs for the displaying information on the UI it involves much more than just partitioning the APIs as per resources.
So I would suggest including the Company information in the User API. But as you suggested Company object can have very large list of Storage objects, in this case I would recommend including only the necessary and sufficient fields of Company model into User API. So that you will be able to render one view. And then later when user expands the Company section then you can pull the left-over fields from /company/<id> API.
This way you will have lesser API calls for the hits where user doesn't look for Company details and your API will be light weight as well.
I am supposed to make web services for an app and thought I could do a nice job practicing the good practice. As I found out it's using REST. But there is one thing that makes very little sense in it.
Why use URI to pass any variable?
What we did in our last project is use POST only and pass whatever as raw POST data (which was JSON). That's not very RESTful. But it has some advantages. It was quite simple on the client side - I had a general function that takes URI and data as arguments and then it wraps it up and sends it.
Now, if I used proper REST, I would have to pass some data as part of the URI (user ID, for instance). All the other data (username, email and etc.) would have to go as raw data, like we did, I guess. That means I would have to separate user ID and the other data at some point. That's not so bad but still - why?
EDIT
Here is a more detailed example:
Let's say you want to access (GET) and update (POST) user data. You may have a service accessible under /user but what RESTful service would do is accept user's ID as part of the URI (/user/1234). All the other data (name, email and etc) would go to request content (probably as JSON).
What I pose is that it seems useless to make put user id in the URI. If you wanted to update user data - you would send additional data as content anyway. If you wanted to access it - you could use same generic method to request web service.
I know GET gets cached by a browser but I believe you have to cache it manually anyway if you use AJAX (web) or any HTTP client library (other platforms).
From point of scalability - you can always add more services.
You use the URI to identify the resource (user/document/webpage) you want to work with, and pass the related data inside the request.
It has the advantage that web infrastructure components can find out the location of the resource without having any idea how your content is represented. For example, you can use standard caches and load balancers, all they need to know is the URL and headers (which are always represented the same way) Whether you use JSON, protobuf or WAV audio to communicate with your resource is irrelevant.
This will for example let you keep different resources in totally different places, if you send it all as content you won't have the advantage of being able to place the resources in totally different locations, as for example http://cloud.google.com/resource1 and http://cloud.amazon.com/resource2.
All this will allow you to scale massively, which you won't be able to do if you put it all on http://my.url.com/rest and pass all resource info as content.
Re: Your edit
Passing the user id in the URL is the only way to identify the individual resource (user). Remember, it's the user that's the resource, not the "user store".
For example, a cache that caches http://my.url/user won't be much good, since it would return the same cached page for every user. If the cache can work with http://my.url/user/4711, it can cache every user separately. In the same way, a load balancer could know that users 1-5000 are handled by one machine, 5001-10000 by another etc. and make intelligent decisions based on the URL only.
Imagine a RESTful web service as a database.
To get or modify specific object you need to identify it by providing its primary key.
You identify a user by his ID, not his Name+Nickname+e-mail+mother's maiden name.
The information that identifies an object or selects a set of objects goes to the URL. The information that modifies objects should be POSTed to the corresponding URL.