Partial fields update REST API - java

There is this MongoBean: SuperBean
class SuperBean extends MongoBaseBean{
private String id;
private String title;
private String parent;
//And getters, setters
}
Need is to write an update API, which is capable of performing partial attributes update. Common approach seen across the web as well as heard from my peers is to check the fields in the request for Null and update if not null. But what if the update request is for the value to be updated to Null??
After few discussions, we came up with three approaches:
Set default value for the field in the bean. Hence instead of non-null parent field, if it does not have $ in the request, this will be considered for update.
class SuperBean extends MongoBaseBean{
private String id;
private String title;
private String parent = "$";
//And getters, setters
}
Let the update API Implementation accept a Map. The actual bean is fetched and all the fields that are present in the request map will be updated.
#Post
public SuperBean updatePartial(Map<String,Object> dataObject) {}
Let the update API accept DTO, that contains 2 maps. One to contain old values, other for new values. This could be advantageous in scenarios, where the update has to happen only if the database contains the values as sent in oldDataObj. But this increases the payload size.
class SuperBeanUpdateDTO {
private Map<String, Object> oldDataObj;
private Map<String, Object> newDataObject;
//getters, setters
}
#Post
public SuperBean updatePartial(SuperBeanUpdateDTO updateDTO) {}
What factors should be considered to chose one of these approaches? Is there another better way to approach this problem?

In my projects, we usually choose the way that similar with your second way. but not exactly the same.
for example, in your client side, you have a page or a view to modify your profile info, includes name, birthday, gender, although you just modify the name value, when you click save button, it still will send the data to server includes birthday and gender with name field, but just keep its value as old. and the server API will directly update these three values in database, won't check whether its value changed or not.
if you have another page or view to modify other parts of the profile, likes password, it need add a new method in client and a new API in server. the API URL likes PATCH /reset_password, and the sent data should include old_password and new_password field.
PS:
1. we use PUT or PATCH to update a resource, not POST, POST is used to create a new resource.
2. when you update a resource, in the above example, the API likes PATCH /profiles/:id (other's profile) or PATCH /profile (yourself profile), so the sent data doesn't need id field anymore, it includes in your API URL.

Related

Single POJO for different REST operations with validation

I'm designing a REST service and am running into the issue that for a given object, I have multiple "states".
The object as it arrives on the initial POST operation.
The Object I store in our DB
The Object I return on a GET
The Object I expect on a PATCH
e.g.
class MyObject {
// Unwanted on POST
// Required on PATCH
// Included on GET
#JsonProperty("id")
private UUID id;
// Everywhere
#NonNull
#JsonProperty("name")
private String name;
// Field I need for internal processing but don't want included in REST.
private AuditTrail stuff;
#JsonCreator
#Builder
public MyObject(...) { ... }
}
...
#Get
public ResponseEntity myFunction(HttpServletRequest request,
#RequestBody #Valid MyObject requestBody) {
...
}
The issue I am running into is that on POST, when the id is omitted, the deserialization fails. I got around it using #JsonIgnoreProperties(), but now on PATCH, where I do want the id present, things work if it is omitted.
Another alternative we toyed with was to have two objects. The first one with the common fields for POST and the other extending from it with the rest, but it feel messy, especially as we deal with objects more complex than the simple example.
It's not actually a problem since I validate and sanitize inputs anyway, but I was wondering if there is a clean way in Jackson to solve this issue.
If you are planning a rest service then you don't need the id in the body anyway. The id will come from the url as a pathvariable:
POST myobjects
GET myobjects/{id}
PATCH myobjects/{id}

Add RequestDTO and ResponseDTO in common DTO or use them separately?

I'm working on a web service in java. I need help and advice on the issue of Request and Response DTOs. having gone through this question here on stackoverflow:
Reusing DTO for various request/response types vs explicitness of what is required / what should be returned
What is better between the two implementation below:
public class PropertyRequestDTO {
private String province;
private String propertyType;
private String propertyArea;
...
public class PropertyResponseDTO {
private String address;
private String street;
private String province;
....
or this:
public class PropertyDTO {
private PropertyRequestDTO propertyRequestDTO;
private PropertyResponseDTO propertyResponseDTO;
In my implementation in setting these DTOs, is better and maintainable to use the PropertyDTO or use the PropertyRequestDTO and PropertyResponseDTO separately?
I think Request and Response Should be different. There is not need to define PropertyDTO . According to rules you will pass data on user end Response Object no need to pass Request Object again. So it will help to decrease network data. COntroller layer only need PropertyRequestDTO no need to pass PropertyResponseDTO object. so no need to combining this two object to another object. These two Objects purpose is different.
First thing:
if you keep both request and response in 1 object then that object will be heavier than one single element and always you will be adding unnecessary load to application for every request and response.
Second thing :
Request and response should not be in same object unless both are identical, so separate those objects. This may leads to other problems in future.

Map as parameter for all fields for EJB backend calls

I am designing backend EJB calls to be called by REST api.
Example for EJB calls;
Get all Systems
getSystems(String systemId)
Now I know that i would get system id to get all systems.
There is a possibility of retrieving them by some another unique id as well
getSystemsByOtherId(String otherId)
There is requirement that there could be sort parameter passed in
getSystems(String systemId, String sort_by, String sort_how)
Would it be better to have something like Map as param and have it passed in with every information
getSystems(Map criteria)
So the key- value pair for Map would have systemId, otherId, sort_by, sort_how and more if needed in future. Or is it better to follow other approach to have unique methods for different params. Or if there is some other better approach.
Thank you.
The first solution is a little cumbersome, in case you want to add or remove parameters you'd have to modify the signature of your EJB every time, the map solution is a little dirty since you'd have to keep track of your parameters names at runtime and if you want to use parameters of a type other than String you'd lose typing info at runtime as well.
This is how I would do it, define a class that encapsulates your parameters:
public class Criteria {
private String systemId;
private String otherId;
private String sortBy;
private String sortHow;
.
.
.
}
and in your EJB,
getSystem(Criteria criteria)

Limiting Fields in JSON Response for REST API?

I am using Spring and Java and implementing REST Based services. I have a set of developers who develop for mobile,iPad and Web too. Consider I have a bean
Class User{
private String Name;
private Integer id;
private String photoURL;
private ArrayList<String> ProjectName;
private ArrayList<String> TechnologyList;
private ArrayList<String> InterestList;
//Getters and setters
}
While the Web Developers need the entire fields and mobile developers just require two fields from it whereas the iPad requires something in between mobile and web.
Since I am using jackson as a parser, is there a way where while requesting to the controller I can specify which all data I require and avoid the others. For example consider I do a GET request like
GET>http://somedomain.com/users?filter=name,id,photoUrl
Which returns me a JSON structure something like
{
"name":"My Name",
"id":32434,
"photoUrl":"/sss/photo.jpg"
}
Sameway if someone asks for some more fields, they could be filtered. Please let me know how this can be done so that my API remains generic and useable for all.
You can achieve what you want but some extra work is necessary. I can offer you two solutions.
1. Return a Map
Simply put every property that is requested into the map.
2. Use Jacksons Object Mapper directly
Jackson lets you set filters that specify which properties are serialized or ignored.
FilterProvider filter = new SimpleFilterProvider().addFilter("myFilter",
SimpleBeanPropertyFilter.filterOutAllExcept(requestedProperties));
String json = objectMapper.writer(filter).writeValueAsString(value);
You can then return the JSON string directly instead of an object.
For both solutions you would ideally write a class that does the job. But if you do that you could as well write your own message converter. You could extend the MappingJackson2HttpMessageConverter, for instance, and overwrite the writeInternal method to suit your needs. That has the big advantage that you don't need to change your controllers.
The straightforward solution is to implement custom Jackson JSON serializer that will get field names that should be serialized from thread local storage and then serialize only fields which names are presented in that context. For other hand, in controller you can grab all allowed fields names from url and store them into thread local context. Hope this helps.

How to access Session information on service layer?

Is there a way I can share Http/Wicket Session information to the service layer without introducing servlet api/Wicket dependency?
I'll provide some context to why am I asking this question, just in case I'm missing something and asking the wrong question.
I've got several entities that have groups of attributes that can be validatable.
Being validatable means there are fields indicating the validation value, the user who made the validation and the date it was validated in.
This is how these entities are modelled:
#Embeddable
public class ValidationBean<T> implements Serializable {
private T validated;
private String user;
private Date date;
// Constructors, getters, setters ahead.
// ...
}
#Entity
#Table(name="SOME_TABLE")
public class SomeEntity implements Serializable, SomeInterface {
// Some attributes which conform validation group 1
public String attribute11;
public String attribute12;
public String attribute13;
private ValidationBean<Integer> validationBean1 = new ValidationBean<Integer>();
// Some attributes which conform validation group 2
public String attribute21;
private ValidationBean<String> validationBean2 = new ValidationBean<Integer>();
// Constructors, various attribute getters with JPA annotations
// ...
#Embedded
#AttributeOverrides(/*various overrides, each entity/validation group has its own validation column names...*/)
public ValidationBean<Integer> getValidationBean1() { return validationBean1; }
#Embedded
#AttributeOverrides(/*various overrides, each entity/validation group has its own validation column names...*/)
public ValidationBean<Integer> getValidationBean2() { return validationBean2; }
}
ValidationBean's user and date fields are automatically modified in the presentation layer when a change in the validated field is detected.
All of this is working correctly. Now, I'm trying to find an elegant & general solution that integrates with the current modelling to the following requirement: When any of the attributes in a validation group gets its value changed, and the related ValidationBean.validated doesn't change, user and date must also be modified with the current user's id and the current date.
There are, as I see it, two alternatives; putting that logic in the presentation layer, or in business/service layer
Putting it in the presentation layer would have an efficieny advantage. Entities are stored in session so that the DB doesn't have to be queried again to check for field changes. But unfortunately, some entities have some of their fields ajax-updated and it would be hard to tell if the entity really changed. Apart from not being the presentation layer's responsability to fulfill this requirement.
Putting it in the service layer seems the best alternative, and I've already found a possible way to handle this properly. I've come up with #PreUpdate. It would be easy to implement a #PreUpdate method on the #Entities to compare the values in DB with the values about to be updated, and modify the related ValidationBeans accordingly. The problem here, and I suppose it's a common problem, is that in the business layer, I don't have where to get the user id from. The current user Id is stored in the Session, which belongs to the presentation layer.
So, any tips, comments, recommendations on how can I share http session information to the service layer (not necessarily Wicket-specific), or even alternatives to fulfill this requirement will be welcome.
UDPATE : Following gkamal's suggestion, I'll try to integrate spring-security in the less intrusive way I can, just to take advantage of SecurityContext. I'd also appreciate tips on this matter.
The common approach used to solve this is to introduce a SecurityContext class that holds the details of the current user as a static thread local variable. The variable is initialized (from the httpsession) by the security filter or some other filter and cleared after the request processing is complete. The SecurityContext class will itself be part of the business layer which provides a set / get methods and hence doesn't have any web layer dependency.

Categories

Resources