I'm create an API with Spring boot and I'm trying to think of the best way to handle two requests that have the same endpoint. So if the request has paramenters X, Y and Z it does A thing, else does B thing.
What is the best way to handle it? Maybe a middleware who handle the request and point to right method? Or maybe evaluate if the parameter X is null? Thanks for helping.
For Example:
Request A:
/payment
{
"holder_name": "John Doe",
"payment_method":
{
"card_number" : "5478349021823961",
"exp_date" : "2018-10-16",
"cvv" : "713"
}
}
Request B:
/payment
{
"holder_name": "John Doe",
"payment_method":
{
"boleto_number" : "123456789"
}
}
These two requests have the same endpoint but the payment methods are different.
The best way, depends on the specific details and needs of the application. Checking that the values are missing or null may not be the best thing to do, e.g. if you receive the four fields card_number, exp_date, cvv, boleto_number what would be the correct action to perform.
You could request the type in the json in an extra field at root level.
<!-- language: json -->
{
"holder_name": "John Doe",
"payment_method": "TICKET",
"payment_details": {
"ticket_number": "123456789"
}
}
Or with a field indide the current payments object.
<!-- language: json -->
{
"holder_name": "John Doe",
"payment_method": {
"type": "TICKET"
"ticket_number": "123456789"
}
}
This way you could first check the method type, and then check that the other fields and details match the fields you are expecting for that type, to then redict to the correct handler.
Also you should decide if you allow unknown fields or fields that do not belong to the specified method. For instance, if you decide not to be that strict, then receiving the 4 fields mentioned before, with the type of CREDIR_CARD, can be process effectively as a credit cards payment, and the extra field ignored. If you decide to be more strict, an error could be thrown indicating that unexpected fields were received.
You could use a enum to define the types.
public enum PaymentType {
TICKET,
CREDIT_CARD,
CASH
}
Finally, depending whether you are using classes or map-like objects as structure for the processed json, you could use a custom converters to transform the object easily, depending on the type.
Related
I am trying to generate swagger on a spring boot rest service, with the following sample schema.
{
"title": "HouseholdOperationsRequest",
"type":"object",
"properties": {
"operation": {
"type": "string",
"enum": ["Electrical","Plumbing","Paint","Handyman",""]
}
}
}
When testing directly (hitting the server), the validation works fine with an empty string sent in the request. However, the swagger that is generated from this represents the empty enum at the end as "__EMPTY__" and causes a validation failure for the clients sending the request with the operation value as "".
Is there a setting with swagger that can help get around this problem?
Edit: --removing Is it a bad practice using empty string in the enum.--
My requirement is a bit unusual since the downstreams treat nulls differently than empty strings. The field itself is not required and is nullable.
In my opinion, it's not good to have Empty Strings in Enum, rather you should keep this field as Optional in Swagger (if not already), so user can send Null value in that case.
Enum are generally a Group Of Constants and Empty String is not a constant. Rather it should be replaced with Null value in general.
I am aware that in a Spring Boot project, I can filter out null valued attributes in response using #JsonInclude(JsonInclude.Include.NON_NULL). But what if I want to return null values for certain use cases which I am driving based on input from consumers?
I have a search API being consumed by multiple consumers. Below are the scenarios I want my API to be able to handle using the same response object.
Scenario
Expected Request
Expected Response
Null Values are expected in response
{ "nullsInResponse": true }
{ "attribute1": "value1", "attribute2": null }
Null Values are not expected in response
{ "nullsInResponse": false }
{ "attribute1": "value1" }
on class level you can do
#JsonSerialize(include = JsonSerialize.Inclusion.ALWAYS)
on attribute level
#XmlElement(nillable = true) #JsonProperty("error") private Error error;
In my opinion, the best option for your case is creating 2 different DTOs for response with null values and without them, based on #JsonSerialize annotation.
It's reasonable, because you have two different business cases, so you can provide different transfer objects with names based on that cases (ResponseWithNullValues and Response for example).
Of course, you can always use reflection to add annotation dynamically, but... we should avoid reflection whenever possible. Your business logic doesn't see anything about building specific rules for every field, so for me it's clear place to use two separated DTOs.
I am about to start development on a new rest api in Java.
My question is about the use of PATCH - Why?
Lets say, we have an entity named Address.java
public class Address {
#Id
private Long id
#NotNull
private String line1;
private String line2; //optional
#NotNull
private String city;
#NotNull
private String state;
}
To create a new Address, I would do this http request:
POST http://localhost:8080/addresses
with the following request:
{
"line1" : "mandatory Address line 1",
"line2" : "optional Address line 2",
"city" : "mandatory City",
"state" : "cd"
}
Assume the record created has an id 1
The corresponding #RestController AddressResource.java will have this method :
#PostMapping(value = "/addresses")
public ResponseEntity<Address> create(#valid Address newAddress) {
addressRepo.save(newAddress);
}
#valid will ensure the entity is valid before storing the data into the table.
Now assume, I move from my apartment above to a house down the street. If I use a PATCH, it becomes
PATCH http://localhost:8080/addresses/1
with request payload:
{
"line1" : "1234 NewAddressDownTheStreet ST",
"line2" : null
}
The corresponding #RestController method would be :
#PatchMapping(value = "/addresses/{id}")
public ResponseEntity<Address> patchAddress(#PathVariable Long id, Address partialAddress)
{
Address dbAddress = addressRepo.findOne(id);
if (partialAddress.getLine1() != null) {
dbAddress.setLine1(partialAddress.getLine1());
}
if (partialAddress.getLine2() != null) {
dbAddress.setLine2(partialAddress.getLine2());
}
if (partialAddress.getCity() != null) {
dbAddress.setCity(partialAddress.getCity());
}
if (partialAddress.getState() != null) {
dbAddress.setState(partialAddress.getState());
}
addressRepo.save(dbAddress)
}
Now if you query the table, won't my address be ?
"line1" : "1234 NewAddressDownTheStreet ST",
"line2" : "optional Address line 2", <-- INCORRECT. Should be null.
"city" : "mandatory City",
"state" : "cd"
As can be seen, the above updates results in an incorrect value for line2.
This is because in java all instance variables in the Address class are initialized to null (or default initial values if they are primitives) when a class is instantiated. So there is no way to distinguish between line2 being changed to null from the default value.
Question 1) Is there a standard way to work around this?
Another disadvantage is that, I cannot use #Valid annotation to validate the request at the entry point - coz it is only a partial. So, invalid data could get into the system.
For example, imagine there was additional field with the following definition:
#Min(0)
#Max(100)
private Integer lengthOfResidencyInYears,
And the user accidentally typed 190 (when they really meant 19 years), it would not fail.
Instead of PATCH, if I had used PUT, the client would need to send the complete address object.
This has the advantage that I can use #Valid to ensure that the Address is indeed valid
If one makes the premise that a GET MUST always be done before doing any updates, why wouldn't one use PUT over PATCH?
Am I missing something?
Aside
My conclusion is that developers using dynamically typed languages are the proponents of using PATCH as I cannot see any benefit to using it from a statically typed language line Java or C#. It just seems to add more complexity.
Using PATCH to upload a modified version of an existing object is almost always problematic for exactly the reason you have outlined. If you want to use PATCH with JSON, I strongly suggest you follow either RFC 6902 or RFC 7396. I won't speak to 7396 because I'm not that familiar with it, but to follow 6902 you would define a separate resource for PATCH operations. In the example you gave, it would look like:
PATCH http://localhost:8080/addresses/1
[
{ "op": "replace", "path": "/line1", "value": "1234 NewAddressDownTheStreet ST" },
{ "op": "remove", "path": "/line2" }
]
You would then process this, making a new entity object that started at the current server state and applied the changes in the PATCH. Run validation on the new entity object. If it passes, push it to the data layer. If it fails, return an error code.
If PUT doesn't add too much overhead, it is a good idea. Idempotency is a nice thing to have. The tradeoff is that you're pushing more data over the wire. If your resource is not large and not accessed often, that's maybe not such a big deal. If your resource is large and is accessed often, that can start to add significant overhead. Of course, we can't tell you the tipping point.
You also seem to have completely tied your resource model to your database model. Good database table design and good resource design often look very different for non-trivial projects. I understand that many frameworks drive you in that direction, but you if you haven't seriously considered decoupling them, you might want to.
I've got an object design question.
I'm building a json api in Java. My system uses pojos to represent json objects and translates them from json to pojo using Jackson. Each object needs to take different forms in different contexts, and I can't decide whether to create a bunch of separate classes, one for each context, or try to make a common class work in all circumstances.
Let me give a concrete example.
The system has users. The api has a service to add, modify and delete uses. There is a table of users in a database. The database record looks like this:
{
id: 123, // autoincrement
name: "Bob",
passwordHash: "random string",
unmodifiable: "some string"
}
When you POST/add a user, your pojo should not include an id, because that's autogenerated. You also want to be able to include a password, which gets hashed and stored in the db.
When you PUT/update a user, your pojo shouldn't include the unmodifiable field, but it must include the id, so you know what user you're modifying.
When you GET/retrieve the user, you should get all fields except the passwordHash.
So the pojo that represents the user has different properties depending on whether you're adding, updating, or retrieving the user. And it has different properties in the database.
So, should I create four different pojos in my system and translate among them? Or create one User class and try to make it look different in different circumstances, using Jackson views or some other mechanism?
I'm finding the latter approach really hard to manage.
In my opinion you should create only one POJO - User which has all needed properties. And now you should decide whether your API is rigorous or lenient. If your API is rigorous it should return error when it receives wrong JSON data. In lenient version API can skip superfluous (unnecessary) properties.
Before I will provide an example, let me change the 'passwordHash' property to 'password'.
Add new user/POST
JSON data from client:
{
id: 123,
name: "Bob",
password: "random string",
unmodifiable: "some string"
}
Rigorous version can return for example something like this:
{
"status": "ERROR",
"errors": [
{
"errorType": 1001,
"message": "Id field is not allowed in POST request."
}
]
}
Lenient version can return for example something like this:
{
"status": "SUCCESS",
"warnings": [
"Id field was omitted."
]
}
For each CRUD method you can write a set of unit tests which will be holding information which way you choose and what is allowed and what is not.
It may seem crazy but I'm having trouble with JAX-RS partial JSON requests. For example suppose we have an entity:
public class Data {
private String a;
private String b;
private Integer c;
/* this is flat and large object with many fields */
}
#PUT
#Consumes(MediaType.APPLICATION_JSON)
#Path("/data")
public Response updateData(Data d) {
/* update database */
}
Now I want to let user update some fields. So user sends request like this:
{ "a": "data of field a" }
This means only update field "a". When user wants to set field "a" to null he will send { "a": null }. The problem is on server side I can't decide Whether client wants to set field "a" to null or there is no field "a" in the request thus I should not touch field "a"(In both cases "a" will be null). One solution is to read Map<String, Object> instead of Data. In this way I can differentiate these two cases, but I will loose bean validation framework plus I should do lots of type casting(Object to String/Integer/List<Integer>). Is there any concise way to handle such partial update requests? I'm using Jersey 2.9 with Jackson 2.3 on Jetty.