How do I avoid duplicate fields in Json request payload ? I'm using Apache Camel with REST - rest

I wanted to parse json request by identifying duplicate fields in the request body. E.g. Assume I have below request.
`"employee": {
"name": "abc",
"name": "xyz",
"id": "6754",
"title": "supervisor",
}`
The employee request above has duplicate name field. ideally during json validation/parsing the second duplicate field takes precedence over first but I want to invalidate this kind of json request. How do I achieve this in Camel REST. Below is the approach that I tried but nothing worked. In myorg.apache.camel.builder.RouteBuilder, I tried configuring DataFormatProperty to use DeserializationFeature FAIL_ON_READING_DUP_TREE_KEY but its not failing. How do I fail the request for invalid json request which has duplicate fields.?
`#Override
public void configure() throws Exception {
restConfiguration().bindingMode(RestBindingMode.json).component("servlet")
.jsonDataFormat(JsonParser.Feature.STRICT_DUPLICATE_DETECTION.name())
.dataFormatProperty("prettyPrint", "true")
.dataFormatProperty("json.in.enableFeatures",
"FAIL_ON_NUMBERS_FOR_ENUMS,USE_BIG_DECIMAL_FOR_FLOATS,FAIL_ON_READING_DUP_TREE_KEY"
+ ",FAIL_ON_UNKNOWN_PROPERTIES,ADJUST_DATES_TO_CONTEXT_TIME_ZONE,"
+ JsonParser.Feature.STRICT_DUPLICATE_DETECTION.name())
.dataFormatProperty("json.in.disableFeatures", "FAIL_ON_EMPTY_BEANS").enableCORS(true)`

This may come from the fact that Camel is using XStream as default JSON library (see here).
Did you already try to force the use of Jackson library ?

Related

Mapping template for API gateway to firehose results in avoid invalid json

I am using API Gateway to receive data from a webhook and pushing it to Kinesis. Using mapping template, I create a JSON using data from the webhook payload.
The problem is, when I encode it to base64 and Kinesis decodes it, it ends up becoming an invalid json. The ":" get replaced by "=".
Here's my mapping template:
#set ($account = $util.parseJson($input.params().header.get("some-field")).account) //fetching a field from a header
{
"StreamName": "$input.params('stream-name')",
"Data": "$util.base64Encode(
{"Payload": "$input.json('$.payload')",
"Account": "$account",
"Event": "$input.json('$.event')"
})",
"PartitionKey": "$account"
}
What's happening is, the Data JSON object is getting corrupted when it gets decoded by Firehose for inline parsing (for dynamic partitioning). I get
{
Payload={"a":1,"b":2},
Account=abcdehdds,
Event="abc"
}
Notice the = instead of :, making this an invalid JSON.
What's strange is when the data is pushed from Firehose to s3 without any dynamic partitioning, it's a perfect JSON.
I'm at my wits end trying to solve this. Would appreciate any help.

How to send POST requests with array properties (Ionic 2 HTTP plugin)?

In one of my Ionic 2 projects I need to send a POST request to a server with a JSON body that looks like this:
var body = { "prop" : 1,
"prop2" : "Test",
"prop3": [{ "id" : "1", "qty": 1, "details": "Test" }]
}
I am using the following code to call the server using the native HTTP plugin (1.2.0) in Android:
http.post(url, body, {}).then(function() { ... })
But my server is receiving the following:
{ "prop" : 1,
"prop2" : "Test",
"prop3": "[{ \"id\" : \"1\", \"qty\": 1, \"details\": \"Test\" }]"
}
As you can see, the array property "prop3" is being turned into a string, so my server is failing to parse it because it's expecting an array, not a string.
One of the things I could do is to change the server side code to parse this string back into an array (but that would be far from ideal). The other thing I could do is to parse the JSON object manually with JSON.stringify.
So, is this just a bug in the plugin or am I missing something here?
Native HTTP plugin
Try set http.setDataSerializer("json");
And send data as usual: http.post(url, body, {})
Then http plugin will send data with application/json content type and support deep structure of json, as stated in the documentation:
https://github.com/silkimen/cordova-plugin-advanced-http#setdataserializer
So, after taking a look at the plugin's source code (the Java one, I'm testing my application in Android) it seems that I won't be able to use the plugin as is (I would need to modify it). What I found was this:
In CordovaHttpPost.java, the body of the request is sent as Form data (simple key-values).
request.form(this.getParams()); //Map<?, ?>
That's why my array property is converted into a string (and any other complex object for that matter)
TL;DR this plugin is only useful to send simple JSON key-value objects (no nesting, no complex objects, no arrays, etc.).

Facebook: field expansion in batch requests ->

How can I define the requested fields for the 2nd part of my batch request?
Example:
[
{
"method": "GET",
"name": "get-friends",
"relative_url": "me/friends?limit=5",
"omit_response_on_success": false
},
{
"method": "GET",
"relative_url": "?ids={result=get-friends:$.data.*.id}"
}
]
This works so far. But now I want to define the requested fields for the 2nd part.
When I add &fields=address ("relative_url": "?ids={result=get-friends:$.data.*.id}&fields=address") I get a "Batch parameter must be a JSON array" exception :-(
Ralph
I get a "Batch parameter must be a JSON array" exception
That probably just means your query could not be understood, because you invalidated the syntax somehow. & has a special meaning in a URL, so you most likely just need to encode it properly.
URL-encode the whole value of the batch parameter (so basically your whole JSON string that you got from your object.)
(What function/method to use for that, depends on how you build your request, resp. in what language. PHP has urlencode, JavaScript has encodeURIComponent, etc.)

JAX-RS passing parameters to a PUT request

I've heard that in REST world, POST is recommended to create an entry, while PUT is recommended to update an entry.
First, I'd like a confirmation of this statement.
Then, using this assumptions, let's say I have a #POST method to create a user and a #PUT method to update a user (with a #QueryParam to pass the user ID).
What is the correct way to pass parameters to POST and PUT?
Is #FormParam appropriate for #PUT? Or should I pass a JSON in the body?
Should I pass parameters the same way for both #POST and #PUT or a different way?
Or should I use POST for both?
Edit: This question initially showed an example that did not work for me, but it was because my testing tool was doing it wrong. It works with POSTMAN now.
Yes, with REST, you typically use the following:
The method POST of the element list resource to add an element
The method PUT of the element resource to completely update an element
The method PATCH of the element resource to partially update an element
Since what you must send corresponds to the state of the resource, you have to provide it within the request body.
The two bodies (for adding and updating) is similar but there are some differences. For example, if you expect the RESTful service to autogenerate some fields, you don't have to provide corresponding ones.
Here are sample requests:
POST /contacts
{
"lastName": "my last name",
"firstName": "my first name",
}
(corresponding response status code: 201 - Created)
PUT /contacts/contactid
{
"lastName": "my last name",
"firstName": "my first name",
}
(corresponding response status code: 204 - No content)
You can notice that JSON isn't the only format you can use. XML, YAML, and so on could also be used.
I think that the following link could give you some hints:
Designing a Web API - https://templth.wordpress.com/2014/12/15/designing-a-web-api/
Hope it helps you,
Thierry

HTTP service API error message best practise

For a error case when calling some HTTP Rest service API, the response is as follows:
{
"statusCode": "400",
"error": "Bad Request",
"message": "Can not construct instance of java.math.BigDecimal from String value 'a': not a valid representation\n at [Source: org.apache.cxf.transport.http.AbstractHTTPDestination$1#2f650e17; line: 1, column: 2] (through reference chain: com.foo.services.dto.request.ItemToUpdate[\"quantity\"])",
"validation": {
"source": "PAYLOAD",
"keys": ["key"]
},
"errorIdentifiers": [],
}
I am wondering if the message field in the response is appropriate. It does reveal certain level of implementation to the end user. Is this considered as
no particular problem at all
just a bad cosmetic issue that won't cause serious problem, just not readable to end user
potential security risk that definitely needs to be fixed
I think that you should only log the stacktrace on the server side. IMO it's technical hints (in addition, perhaps the end user even doesn't use Java to interact with your API) and the only thing that interests the end user of your API is that there is here a validation error within the provided data.
Another remark is that you use the status code and statusmessage within your response payload. I think that you don't need to duplicate this since it's already present in the response.
I would suggest an error message like that:
{
"messages": {
"quantity": "this must be a valid number"
}
}
I use a JSON structure for the field messages since there could be several validation errors within the provided data. Note that it's only a suggestion and you could extend this to your exact needs.
Hope it helps.
Thierry