Spring Boot REST API: Exposing (or not) associated entities in JSON - spring

I am building a Spring Boot based application to expose a JSON REST API.
In this application I have a 1-to-many relationship: one Order has multiple Items (and one Item belongs to exactly one Order).
I would like to have the following 4 API endpoints:
GET all Orders: In this case I just want the Order itself - so excluding the associated Items
GET a single Order: get the Order itself including the associated Items
GET single Item: get a single Item including the Order it belongs to (here it does not matter whether just the ID (=primary key) of the order is included or the whole order itself
GET all Items: the all the items; the associated Order is not necessary - but it also would not hurt.
Unfortunately I am a bit lost on how to model my associations and/or controller methods that expose the API endpoints.
Do you have some hints for me?
Thanks a lot!

Your first choice should always be to resort to Software Design Patterns. When developing applications which may require remote connections (or not), there is one that should be implemented in your rest api: Data Transfer Object.
Having into account you are developing under Java/Spring Framework, you should take a look at modelmapper library and to this guide.
I have successfully done the same task in my rest api.

Not sure if there is a better method of doing that, but my approach would be to model and fetch the relations using Hibernate, but in a lazy manner (https://howtoprogramwithjava.com/hibernate-eager-vs-lazy-fetch-type/).
In your controller, you do not return the entity but a DTO class that might be pretty similar to your entity. That DTO is created by some mapper component that provides the logic of including or not including associated items, etc.

Related

Where it is necessary to keep the DTO object when interacting with several services

A little background of my problem. I have a set of the following services:
AdapterService - intended for loading certain products from an external system
ApiGateway - accepts requests from UI. In particular, now there is only one request that receives product data to display product in UI from Product Service
ProductService - data storage service for various products. The service itself does not specifically know what kind of product it specifically stores. All types of products are created dynamically by other services that are responsible for these products. Product data is stored as a key-value map (technically it is a json string in DB column)
There is a schema for service interations
So, services in BLUE zone are mine (they can be changed in any way). RED zone describes services of another team (they can't be changed).
Whats the problem
To load product from external system I want to use SpecialProductDto which will store product data. I can use some validation features like Spring annotations and so on. Then to load the product from Adapter Service to ProductService I must transform SpecialProductDto to Map<String, Object> because ProductSerivcie requires it via API.
When I would get product info for UI through ApiGateway, I will need to call ProductService api for getting product that return attribues in Map<String, Object> and then transform this data to some UIReponse which contains some part of product data (because I dont need all product information, just only name and price for example).
But I also want to use SpecialProductDto in my ApiGateway service, because it seems working with Map<String, Object> is error prone... I practically need to fetch data blindly from Map to construct UIResponse. And what if some attribute names will be changed? With Map I only will know it when the request would be made from UI but using special DTO I get such exception in compilation time.
Question
So, what is the best practiсe or maybe patterт should I use in such situation? At the moment I see the following solutions:
Duplicate DTOs in both AdapterService and ApiGateway services. So, any changes in one class must be supported in another
Use Map<String, Object> at my own peril and risk, hoping that nothing will change there
Share SpecialProductDTO between ApiGateway and AdapterSerivce in some separate library and service (seems to be antipattern because of sharing someting can make a lot of problems)
Сan anyone help?
In my opinion, there's nothing wrong on duplicating DTOs.
Also, there's nothing wrong on providing the DTO in a separate library to be imported on each project, you will only be sharing the ProductService's contract and that's it. It does not cause any tight coupling between the Api Gateway and the Adapter. If the contract changes, then it must be changed on all of it's consumers (api gateway and adapter), simple as that.
About using Maps: usually I don't recommend this, because, like you said, you will not be able to take advantages of the built-in Bean Validations that Spring (and other frameworks) provides, but not only that, you'll also, depending on the situation, be using lots of casts and type conversions, which is not good and can be prevented by using DTOs.
Also, be aware that a DTO, in my opinion, should not be named with the suffix of 'DTO'. That's because a name like SpecialProductDTO doesn't clearly states where this object is being used or should be used.
Instead, prefer a something like CreateSpecialProductRequest - this indicates that this object is used when creating a Special Product. Another example is CreateSpecialProductResponse which just represents the response (if needed) after a Special Product creation. Take a look at this StackOverflow answer: Java data transfer object naming convention?

Creational adapter

I have a lot of code like this
additional_params = {
date_issued: pending.present? ? pending.date_issued : Time.current,
gift_status: status,
date_played: status == "Opened" ? Chronic.parse("now") : (opened.present? ? opened.date_played : nil),
email_template: service&.email_template,
email_text: service&.email_text,
email_subject: service&.email_subject,
label: service&.label,
vendor_confirmation_code: service&.vendor_confirmation_code
}
SomeService.new(reward, employee: employee, **additional_params).create
The same pattern applies to many models and services.
What is the name of this pattern?
How to refactor the current solution?
Is there a gem to solve this kind of solution? Like draper or something else
To me, that looks a bit like a god object for every type of entity. You expect your service to take care of everything related to your entity. The entity itself just acts as a data container and isn't responsible for its data. That's called an anemic model.
First of all, you need to understand that there can be several representations of the same entity. You can have several different classes that represent a user. On the "List user" page, the class contains just a subset of the information, maybe combined with information from the account system (last login, login attempt etc). On the user registration page, you have another class as it's not valid to supply all information for the user.
Those classes are called data transfer objects. Their purpose is to provide the information required for a specific use case and to decouple the internal entity from the external API (i.e. the web page).
Once you have done that, your service classes will start to shrink and you need fewer custom parameters for every method call.
Now your service class has two responsibilities: To manage all entities and to be responsible for their business rules.
To solve that, you should start to only modify your entities through behaviors (methods) and never update the fields directly. When you do so, you will automatically move logic from your service class to your entity class.
Once that is done, your service classes will be even cleaner.
You can read about Domain Driven Design to get inspired (no need to use DDD, but get inspired by how the application layer is structured in it).
You can try the builder pattern. I am not familiar with a ruby gem, but you can find information here: https://en.wikipedia.org/wiki/Builder_pattern and https://en.wikipedia.org/wiki/Fluent_interface

Understanding where to put constraints validation for REST api service using Spring

I'm working on a REST api for a model having the following entities:
A Team cannot exists if it has no relationships with a Course and a Student. At the beginning, I created an endpoint for the teams (API/teams) for the CRUD operations. Now I ended up moving all the CRUD operations for the teams under the following URLs:
/API/courses/{courseId}/teams
The same has been done for Machine that cannot exists without any relationships with a Team and Student, so any CRUD operation should be done to the following:
/API/courses/{courseId}/teams/{teamId}/virtual-machines
This makes sense to me, since every time I need to perform an operation on a Machine I have to verify the constraint for which the Machine is owned by a Team related to a Course. For this reason, If I continued to perform any operation on URLs like /API/teams I should have requested the course and team ids to verify those contraints in the request body.
Having said this, my CourseController invokes a VirtualMachineService for all the operations on the Machine entity. What it seems odd to me is that each signature of every method in the VirtualMachineService need to have the course and the team id to verify the above constraints. This caused to have lots of duplicated code in every method.
Are my design choices correct?
The CourseController only have to invoke the methods of VirtualMachineService and to validate the parameters coming from the requests body.
Should those constraints validation be done inside the controller or inside the service?
Neither Configuration nor Model are entities. Entities are classes from the domain (real world representations related to project, if you will), not every class you use.
REST doesn't directly care about your entity model (meaning graph) but you should follow the guidelines for specifying REST endpoints which is
different endpoint for
/courses/... and /teams/... - don't mix these. Any constraints you would like to apply are applied at the backend and have nothing to do with endpoint definitions.
Validation guide https://www.baeldung.com/spring-mvc-custom-validator

HAL clients or examples of accessing HAL API

Question: Any HAL clients or examples of accessing HAL API with admin-on-rest ?
I got started because HAL was mentioned in the first paragraph of the introduction, but now I'm having trouble finding any examples or anyone else using HAL rest client, so I am winding up for now just writing a bunch of simple findAll repositories on top of the already robust existing HAL API.
Adding a more concise answer here that isn't polluted with my thought process now that I've got it all figured out (for anyone's future reference)... Again assuming the HAL API was made with Spring Data Rest.
The four major keys to this integration are:
Exposing foreign key attributes in your JPA entities, which is required in several places by admin-on-rest #Column(name="parentEntity", updatable=false, insertable=false) private Integer parentEntityId;
Exposing all your entity IDs using RepositoryRestConfiguration.exposeIdsFor( MyEntity.class )
Annotate your repositories as #RepositoryRestResource and have them extend PagingAndSortingRepository<MyEntity, Integer>, QueryDslPredicateExecutor<MyEntity> to expose extremely useful search filters by attribute name (e.g. /api/myEntitys?field1=foo&field2=bar).
When submitting create and save requests with foreign keys make sure to adjust your params.data to include the linked resource (e.g. 'http://myserver.com/api/myEntitys/19') on top of (or in place of, HAL has no use for it) the foreign key you exposed in 1. (e.g. myEntityId=19)
Other small items of note:
use PATCH instead of PUT when updating (you may be able to use PUT if you are more of a hibernate expert and can map your entities better than I can but I had trouble getting it mapped perfectly and HAL's PATCH will take partial entities)
When submitting GET_LIST and GET_MANY_REFERENCE you get the total number of items and pagination parameters from the 'page' section of the response, and you use 'size' and 'page' query params in your API requests. (so, no need for headers and stuff)
To change the default 'equals' filter for any string entries (from 3. above) to a 'contains' filter, you will have to also extend QuerydslBinderCustomizer<QMyEntity> and provide your own customize method in each of your repositories. For example:
default void customize( QuerydslBindings bindings, QChampion champion )
{
bindings.bind( String.class ).first( ( StringPath path, String value ) -> path.contains( value ) );
}
We don't have any examples for HAL specifically. However, the point of this introduction was that admin-on-rest is backend agnostic.
You can create your own custom rest client by following the documentation. Read the code of existing ones for inspiration.
For anyone referencing this in the future, if you happen to be in control of your API through Spring Data Rest you can consider the use of an excerptProjection on every one of your existing repositories that shows an inline version of your entity. This would work if there were absolutely nothing besides admin-on-rest accessing your API.
For my case I am planning on writing a custom projection for every rest resource that has entities and naming it the same thing: "inline". Then in the admin-on-rest restClient, just always asking for the inline projection on every GET_MANY or GET_MANY_REFERENCE request.
This is the best I have at the moment. It's not perfect but for the amount of entities I have it's still many weeks faster than building a CRUD interface from scratch so I highly recommend admin-on-rest.

Spring mvc controller getting multiple rows values

I have multiple input values, rows may 1, 10, 20 or 100 or more and columns may be 3 or more as shown here
Questions:
1) In spring controller how do I get the values for each rows? I need exact values for all the corresponding values. e.g: row 1 Expense Activities values match with accounts and corresponding description. Here Expense Activities, Accounts are drop down boxes and description is text field.
2) I have another tab called Expense which is similar to Earnings salary as shown in image. How can get the values for multiple blocks.
I am using Spring mvc with ext-js as front end technologies.
Your questions are fairly hard to answer given the lack of detail as to what you are doing.
In similar spring-ext apps I have written I use a store backed by a rest proxy to back my ext grid. This will give you certain client-server communications for free. for more reading on the ext js side try:
Ext.data.Store
Ext.data.proxy.Rest
Its not too hard to expand the grid example to use a rest proxy which will give you a good ground in how set your grid up for client-server communication.
Then in your spring controller you can will need to implement and annotate the methods for the CRUD operations that the ext proxy will send requests to.
A handy guide for getting started with writing a restful web service with spring:
Spring REST Service
In your specific case (and I'm guessing here because I'm not 100% sure what you're asking) you would need a spring controller method annotated with something like:
#RequestMapping(value="/expense", method=RequestMethod.GET)
You would back this with whatever business logic is used to load the grid and pass the data structure as most likely a JSON object.
For updates from the client you would then have another spring controller method, only this time anotated something like:
#RequestMapping(value="/expense", method=RequestMethod.POST) for create or
#RequestMapping(value="/expense/{id}", method=RequestMethod.PUT) for updates
Obviously if you're data structures are more complicated then the JSON objects sent over the wire will be correspndingly complex.
Hopefully this will set you on the path to getting your app working.

Resources