RESTful Endpoint that returns single entity by two different unique parameters but not both at the same time - api

I want to understand what would be the best way to represent this in a RESTful way, taking in consideration that the codebase it's a very large - inherited - legacy project and I have to add a lot of new functionality on top of it.
The API Definition is built with OpenaAPI3.
Let's take in consideration the following example:
/v1/{customer}/types/{id}
But the Types collection also has a database constraint of Unique(customer, code) - customer and code being columns from the Types table.
What I need to implement now is a new endpoint that will retrieve a single entity, based on the customer path param and code path param, without having to use the ID path param.
It's a matter of reducing the number of calls, that's why I don't want to make use of the ID path param also.
One solution would be to use query params:
/v1/{customer}/types?code=123
But this will basicaly return a Singleton List so it's not that trivial and definetley not a best practice.
What would be your take on this? I know I should have the ID in the place I want that entity to be returned, but this some case I want to get resovled without having to do another call to get the ID of the entity so I can call the initial endpoint.

Related

Building Rest API response Object based on consumers requests

I am building rest API & below are my end points.
EndPoint 1:
/products/{code} --> giving product inforamtion
Endpoint 2:
/products/{code}/packages --> provides packages for a given productcode
Endpoint 3:
/products/{code}/suppliers --> provides suppliers for a given product code
Endpoint 4:
/products/{code}/shelfTags --> provides shelfTags for a given product code
We have multiple down stream systems(more than 20 downstream systems) which require products & it's related information.
Note: Not all users require the nested collection information, some clients need only product information and they are good and below are the combinations and it varies by consumers
1. product info only --> **consumer 1**
2. product , packages --> **consumer 2**
3. product, suppliers, packages--> **consumer 3**
4. product, supplier, packages, shelfTags--> **consumer 4**
5. product, supplier, shelfTags --> **consumer 5**
6. product, shelfTags --> **consumer 6**
7. etc...
From above example, consumer 4 makes Http call to get product code and now has to make multiple Http calls to get packages (Endpoint 2) or suppliers (Endpoint 3) or shelfTags (Endpoint 4) etc... Is this a good design ?
Is there a way consumers can get only what they want in response on one request ? (Now is it a good design to give data needs in one request ? or it's good to ask consumers to make multiple Http calls to get nested collection ?)
Note : I cannot include all nested collection along with Products Endpoint 1 itself as it's requires huge data querying so I am planning to only provide what consumer may need, that will reduce unnecessary querying and also providing irrelevant information to few consumers who don't need that data.
Current Design:
I have below now:
Approach 1:
/products/{code}?Options = packages, Suppliers
Above would give Product details and have options query parameter based on that I can decide whether to pass Packages & supplier, shelftags etc, but here we are not filtering on resource to pass query parameter, I believe this is not a good approach as query params are only used to filter on the resources.
Approach 2:
Form a different endpoint as query parameter on the resource is for only filters if I am not wrong so looking at below option:
/products/{code}/extendedProductDetails?Options = Packages, Suppliers
In option2 extendedProductDetails is an operation rather than resource itself and I am filtering on the operation.
Can anyone provide solution on how to solve this requirement
Approach 1 vs. Approach 2
Assuming that you want to use REST, from my point of view, between the options you gave, I would go with something like Approach 2, since it is a proper collection for extended information. However, I think I'd prefer to model it such as /products-extended/{code}?options=packages,suppliers, since it defines a different collection.
Besides enhancing the readability of the API, in this way, you have the products collection and the products-extended collection: each of them can be consumed independently and with different query string filters (of course that less filtering is prone to increase complexity and latency, but in my opinion, query string parameters should be optional). If they must really not be optional and there is always the need to provide a product id and at least one nested collection, then, you can also consider designing something like products-extended/{code}/{packages,suppliers,etc}. Either way, this would "protect" your products collection.
Moreover, this would allow you to perform different operations (POST, PUT,...) to both collections, if your use case requires such.
Other approaches
Besides the other suggestions on GraphQL - would be great, yes :) -, OData or the custom types, couldn't you keep only with the individual collections? Depending on your use case, maybe you could perform parallel calls to /products/{code}/packages, /products/{code}/suppliers and so on, since you already know the product id. Perhaps, the major drawback of this design would be, for example, to create new products. However, the GET requests became super easy :)
Maybe a solution would be to use custom media types in the request header:
application/json+info-only
application/json+supplier
application/json+supplier+packages
etc.
In your controller action you would check for the selected media type and respond to the request based on them. Simply return an IActionResult and your consumer will get the data within one request.
It's very similar to your approaches but with custom extended media types you would have still one endpoint without additional parameters.

Returning objects on CQRS commands with MediatR

I have been reading about MediatR and CQRS latelly and I saw many people saying that commands shouldn't return domain objects. They can return values but they're limited to returning erros values, failure/success information and the Id of the newly created entities.
My question is how to return this new objetct to the client if the command can return only the Id of the new entity.
1) Should I query the database again with this new Id? If so, isn't that bad that I making a new trip to the database to get an object that was in the memory a few seconds ago?
2) What's the correct way of returning the entities created by the commands?
I think the more important question is why you shouldn't return domain objects from commands. If the reason for that seems like a valid reason for you, you should look into alternatives such as executing a query right after the command to fetch the domain object.
If, however, returning the domain object from the command fits your needs and does not impose any direct problems, then why not just do it and keep things simple and straightforward?

O.O.P and Class Properties

I'm new to O.O.P and would like advice on best practice.
Say for example I have a Course class which holds course information, and a Location class which holds location details. Classes have corresponding repository classes. Now, each Course HAS A location which I have added Location as a property.
When I am pulling the details of a Course from the database, is it best practice to:
A – Populate the Location object from within the CourseRepository Class meaning SQL would return both course and location details
B – Only populate Course object, returning the Location ID, then use the LocationRepository class to find the location details
I’m leaning more towards B as this is a separation of responsibility, however, the thing that’s getting me is performance. Say I need a List instead which returns a result of 50. Would it be wise to query SQL 50 times to seek location details? Would appreciate your thoughts on this.
Lewis
In part, you're thinking in a wrong conceptual direction. It should be: one location can have many courses, not the reciprocal.
That said, theoretical, a Course domain object should not contain a location as class member, but just a location id. On the other hand, a domain object Location could contain an array of Course objects as class member, if needed. You see the difference?
Now, in your case, indeed pass a Location as argument to a Course object. And, in the Course repository, define a method like fetchCoursesWithLocations() in which you run only one sql query to fetch 50 courses TOGETHER WITH the corresponding location details - based on your criterias - into an array. Then loop through the records array. For each of the record item build a Location object and a Course object (to which you pass the Location object as argument). Then pass each so created Course object to another array holding all resulting Course objects, or to a CourseCollection object (which I recommend). In the end return the Courses array (or the CourseCollection content) from the method.
Now, all is somehow too complex to present in here. But I'll give you here three great articles (a serie) which will make the whole process very clear to you. You'll find out in there how a CourseCollection should see, too. In the articles (from the second one upwards), it is used the term "Mapper", which I'm pretty sure it's the same as your "repository". Actually, there are two abstraction layers for data access in the db: mappers and repositories. Plus the adapters.
Look to the part with the PostMapper and the CommentMapper. They are the parallels to your CourseRepository, respectively your LocationRepository. The same roles have Post and Comment models (domain objects!): as parallels to your Course and Location.
The articles are:
Building a Domain Model - An Introduction to Persistence
Agnosticism
Building a Domain Model - Integrating Data Mappers
Handling Collections of Aggregate Roots - the Repository Pattern

Work with dto's to build an API with DDD

I'm starting to work with dto's (data transfer objects) and I have some doubts about the best way to build the system architecture of the API.
Imagine a domain entity 'A', with relations to 'B', 'C' and 'D'. We have a service 'S' that return a json list with all "A's". It's correct to create an 'ADTO' in that service, fill with "BDTO's", "CDTO's" and "DDTO's"? If then we have another service "S2", and we need to return an specific set of "B's", then we need to create another tree of "B2DTO's" with "C2DTOS's", "D2DTO's"... ? Is this the correct way to do it?
I see that this way, we'll have a huge and complex tree of DTO's, with an specific DTO's for each use case.
EDIT:
I forgot the assemblers part. Is necessary to implement a different assembler for every DTO? for example, for an entity A, we have two DTO's. Can I use the same assembler or is better to have A1Assembler and A2Assembler?
Your DTOs should represent a set of data that you want your client to have. Usually, you should never 'copy' your entities into DTOs because you may have fields that you don't want to share with the world. Let's supposed that you are creating automatically a 'tracking' column with the ID of who entered that data, or say that you have a Customer entity with password fields. You don't want that to be part of your DTOs. That's why you must be EXTRA CAREFUL when using AutoMapper etc.
When you design DTOs think about what your client needs from that endpoint specifically. Sometimes DTOs may look the same and that's ok. Also, your DTOs can be as simple or as complex as needed. One crazy example, lets say that a page where you show an artist, his songs, the voting rate for those songs and some extra data.
If your use case justifies it, you may very well put all of that into a DTO. DTO all they do is carry data.
YES, your services should return DTOS (POCO).
Also, DTO is just naming convention. Don't get caught up in the "dto" suffix. A 'command' coming from a client is a DTO, but in that case you would call it AddNewCustomerCommand for example.
Makes sense?
I think you mistake what your DTO's are. You'll have 2 kind of DTO's Roughly speaking
1) they can be your domain entities, then you can return ADTO, BDTO and CDTO. But those DTO's can be fairly consistent (why would B2DTO be any different from BDTO)
If you look at what your json would look at
{
Id: 1
name: "foobar",
$type: "A",
B: [ {
name: "b-bar",
$type: "B"}]
CIds: [ 2,23, 42]
}
Here you see 2 kind of objects, some (B's) are returned in full in your DTO as subobjects. Others (like C) are turned by Id and can be queried separately. If it's S2 which implements the C query or not you don't care about.
2) When you get to an architecture like CQRS then you do get different DTO's. (projections or commands) but then you would also see this in the naming of the DTO's. Forexample are
AListOnOverviewPageDTO, AUserEditDetailDTO, etc.
Now it makes very much sense to have different DTO's since they are projections representing very different usecases. (and not a full object as is common in DDD)
Update The reason you want different DTO's are twofold. First of all it allows you to optimize each call separately. Maybe the list needs to be faster so (using CQRS) you can put the right indexes on your data so your listDTO will be returned faster. It allows you to reason about usecases more easily. Since each DTO represents 1 usecase/screen (Otherwise you get cases ok in the userlistDTO i need to populate only these 3 fields in this case ..etc.).
Furthermore you need to make sure you API is honest. NEVER EVER return a "age" field with empty data but have some other call return the same user but with another call return the same user with a real age. It makes your backend appear broken. However if i had a call to /users/list and another call to /users/1/detail it would be natural if the detail calls returned more fields about a specific user

Getting specific Backbone.js models from a collection without getting all models first

I'm new to Backbone.js. I'm intrigued by the idea that you can just supply a URL to a collection and then proceed to create, update, delete, and get models from that collection and it handle all the interaction with the API.
In the small task management sample applications and numerous demo's I've seen of this on the web, it seems that the collection.fetch() is used to pull down all models from the server then do something with them. However, more often than not, in a real application, you don't want to pull down hundreds of thousands or even millions of records by issuing a GET statement to the API.
Using the baked-in connection.sync method, how can I specify parameters to GET specific record sets? For example, I may want to GET records with a date of 2/1/2014 or GET records that owned by a specific user id.
In this question, collection.find is used to do this, but does this still pull down all records to the client first then "finds" them or does the collection.sync method know to specify arguments when doing a GET to the server?
You do use fetch, but you provide options as seen in collection.fetch([options]).
So for example to obtain the one model where id is myIDvar:
collection.fetch(
{
data: { id: myIDvar },
success: function (model, response, options) {
// do a little dance;
}
};
My offhand recollections is that find, findWhere and where would invoke all models being downloaded and then the filtering taking place on the client. I believe with fetch the filtering takes places on the server side.
You can implement some kind of pagination on server side and update your collection with limited number of records. In this case all your data will be up to date with backend.
You can do it by overriding fetch method with you own implementaion, or specify params
For example:
collection.fetch({data: {page: 3})
You can also use find where method here
collection.findWhere(attributes)