The value is not valid put request - json

I'm developing a web api using net core 5 and I'm getting the following error message after executing a put request from POSTMAN
"errors": {
"id": [
"The value '44' is not valid."
]
}
I have a breakpoint inside my controller method but doesn't hit any part of that code. So maybe this is a problem with the url that I'm using or some parameters configuration.
This is my httpmethod in my controller:
[HttpPut("Edit/{id}")]
public IActionResult Update(Guid id, [FromBody]Model mod)
{
return mod.SomeValue;
}
And this is my request from POSTMAN:
https://localhost:8820/api/controller/Edit/44
I'm sending params from body as a JSON object (the same object works using my POST method)
What can be the problem?

The problem is from using Guid type for storing a number.
you can't store 44 value in a Guid variable so change it to int.
[HttpPut("Edit/{id}")]
public IActionResult Update(int id, [FromBody]Model mod)
{
return mod.SomeValue;
}

Related

How to parse a JSON response for APEX REST Service

I have written a REST class that sets a url as an endpoint to call an API. The API returns a timezone value. The url passes longitude and latitude as a parameter. The response I am getting is a complicated JSON list and I just need the Id value of the Timezone object. This is what I get as a JSON response for a lat/long value I passed:
{
"Version":"2019c",
"ReferenceUtcTimestamp":"2019-12-10T21:14:23.7869064Z",
"TimeZones":[
{
"Id":"America/Los_Angeles",
"Aliases":[
"US/Pacific",
"US/Pacific-New"
],
"Countries":[
{
"Name":"United States",
"Code":"US"
}
],
"Names":{
"ISO6391LanguageCode":"No supported language code supplied",
"Generic":"",
"Standard":"",
"Daylight":""
},
"ReferenceTime":{
"Tag":"PST",
"StandardOffset":"-08:00:00",
"DaylightSavings":"00:00:00",
"WallTime":"2019-12-10T13:14:23.7869064-08:00",
"PosixTzValidYear":2019,
"PosixTz":"PST+8PDT,M3.2.0,M11.1.0",
"Sunrise":"2019-12-10T07:42:22.383-08:00",
"Sunset":"2019-12-10T16:18:49.095-08:00"
},
"RepresentativePoint":{
"Latitude":34.05222222222222,
"Longitude":-118.24277777777777
},
"TimeTransitions":[
{
"Tag":"PST",
"StandardOffset":"-08:00:00",
"DaylightSavings":"00:00:00",
"UtcStart":"2019-11-03T09:00:00Z",
"UtcEnd":"2020-03-08T10:00:00Z"
},
{
"Tag":"PDT",
"StandardOffset":"-08:00:00",
"DaylightSavings":"01:00:00",
"UtcStart":"2020-03-08T10:00:00Z",
"UtcEnd":"2020-11-01T09:00:00Z"
},
{
"Tag":"PST",
"StandardOffset":"-08:00:00",
"DaylightSavings":"00:00:00",
"UtcStart":"2020-11-01T09:00:00Z",
"UtcEnd":"2021-03-14T10:00:00Z"
}
]
}
]
}
Here is my REST Service in APEX:
public class LPP_AccountTimeZone {
public static List<String> getTimeZone(String latitude, String longitude){
Http http = new Http();
HttpRequest req=new HttpRequest();
String url = 'https://atlas.microsoft.com/timezone/byCoordinates/json?subscription-key=XXXXXXXXXXXXXXXXXXXXXXXXXXXX&api-version=1.0&options=all&query='+latitude+','+longitude;
req.SetEndPoint(url);
req.setMethod('GET');
HttpResponse res=http.send(req);
if (res.getStatusCode() == 200) {
List<String> TimeZone = new List<String>();
TimeZoneJSON result = TimeZoneJSON.parse(res.getBody());
for(TimeZoneJSON.TimeZones t : result.timeZones){
System.debug('TimeZone is' + t.Id);
TimeZone.add(t.Id);
}
}
else{
System.debug('The status code returned was not expected: ' + res.getStatusCode() + ' ' + res.getStatus());
}
return TimeZone[0];
}
The response I got with this code (when I ran it in anonymous window) was:
TimeZone is{Aliases=(US/Pacific, US/Pacific-New), Countries=({Code=US, Name=United States}), Id=America/Los_Angeles, Names={Daylight=Pacific Daylight Time, Generic=Pacific Time, ISO6391LanguageCode=en, Standard=Pacific Standard Time}, ReferenceTime={DaylightSavings=00:00:00, PosixTz=PST+8PDT,M3.2.0,M11.1.0, PosixTzValidYear=2019, StandardOffset=-08:00:00, Sunrise=2019-12-12T07:44:13.44-08:00, Sunset=2019-12-12T16:18:47.934-08:00, Tag=PST, WallTime=2019-12-12T11:49:25.0802593-08:00}, Representativ
That is a lot of info. I just want the America/Los_Angeles part which is what Id equals (I have that bold in the response).
Another problem with this code is that it is not returning anything/is void class.
I need t return that value because a trigger is calling that method and will use this value to update a field.
Can anyone please correct my code so that it passes the correct json value and returns the value?
EDIT/UPDATE: The error I am now getting is "Variale does not exist: TimeZone (where the return statement is)
You could use JSON2APEX to easily generate an apex class from your JSON response. Just paste your full response in and click 'Create Apex'. This creates a class that represents your response so that you can easily retrieve fields from it (Keep in mind this will only really work if your response is static meaning the structure and naming stay the same). Have a look through the class that it generates and that will give you an idea of what to do. The class has a parse(String JSON) method which you can call passing in your JSON response to retrieve an instance of that class with your response values. Then it's just a matter of retrieving the fields you want as you would with any object.
Here is how getting the timezone id code would look if you take this route.
(Note: This assumes you keep the name of the class the standard 'JSON2Apex')
if (res.getStatusCode() == 200) {
JSON2Apex result = JSON2Apex.parse(res.getBody());
for(JSON2Apex.TimeZones t: result.timeZones){
System.debug('TimeZone is' + t.id);
tId.add(t);
}
}
To return a value just change void in the method signature to List<String> and return the tId list as follows return tId;

How to get my topic name from message header and publish

I am new to spring-integration. I am trying to build a spring rest service where it will get any HTTP requests with some json message and publish to kafka topic.
My json message will be posted thru RequestBody which will contain the topic name in the message header.
I am able to post the message from my controller to kafka channel, however I am getting hard time to get the topic name from my json message header.
Can anyone suggest a way to get the topic name from my message header (typically a HTTP request consists a json message with topic name) and use the topic to publish the message.
my json :
{"resourceType": "MessageHeader",
"topicName": "testToptic",
"messagePayload":{
"location": "chennai",
"messageDetail": {
"department-id": 123,
"department-name": "SSS",
"pincode": 600009
}
}
}}
here my bean and handler
#Bean
public IntegrationFlow hanldeGenericKafka() {
return IntegrationFlows.from(sendToKafkaChannel)
.handle(
kafkaGenericMessageHandler(producerFactory),
e -> e.id("kafkaProducer2"))
.get();
}
public KafkaProducerMessageHandlerTemplateSpec<String, String> kafkaGenericMessageHandler(
ProducerFactory<String, String> producer) {
return Kafka
.outboundChannelAdapter(producer)
.sync(true)
.headerMapper(kafkaDefaultHeaderMapper())
.messageKey(m -> m.getHeaders()
.get("topicname"))
.configureKafkaTemplate(t -> t.id("kafkaTemplate"));
}
You can use an expression with the built-in JsonPath SpEL function to extract a field value from a JSON payload.
Use the expression in the adapter's .topicExpression().

.NET Core - How to upload JSON file?

I am trying to upload JSON file in order to read values from it and save them in database, but I have problem with that. Code of my controller looks as following:
[Produces("application/json")]
[Route("api/[controller]")]
[ApiController]
public class ImportController : ControllerBase
{
private readonly DatabaseContext dbContext;
public ImportController(DatabaseContext dbContext)
{
this.dbContext = dbContext;
}
[HttpPost]
public IActionResult ImportData(IFormFile file)
{
var content = string.Empty;
using (var reader = new StreamReader(file.OpenReadStream()))
{
content = reader.ReadToEnd();
}
List<UserModel> userObjects = null;
try
{
userObjects = JsonConvert.DeserializeObject<List<UserModel>>(content);
}
catch
{
return BadRequest();
}
foreach (var user in userObjects)
{
UserModel us = new UserModel
{
Username = user.Username,
Password = user.Password
};
dbContext.User.Add(us);
dbContext.SaveChanges();
}
return Ok();
}
}
I'm using Postman to send JSON data, but anytime I try to do it, I get following response:
{"Username":["The input was not valid."]}
when I try to send JSON data as raw->application/json OR
{"":["The input was not valid."]}
when I try to send it by form-data with key called "file" and test.json file as value.
Could you direct me to the right path? I tried to use [FromBody] UserModel user as parameter of my action, but it only allows me to process one JSON string.
You can use [FromBody] IEnumerable<UserModel> users to process many rows. In this case json should look like:
[
{
"userName": "name",
"password": "password",
},
{
"userName": "name1",
"password": "password1",
}
]
You need to standardize your approach one way or another. If you want to accept JSON, then bind to an action param of type List<UserViewModel> with the [FromBody] attribute, and client-side, use JavaScript's FileReader to get the actual content of the upload loaded file and post the content, rather than the file.
If you want to do it by file upload, then you can keep the action as it is, but you'll need to then send your own "JSON" as a file upload as well. This can be achieved by using FormData in JavaScript and creating a Blob manually from your JSON object as a string.
Long and short, whichever path you choose, be uniform about it. There's no way to handle both posting a JSON object and a file upload that happens to be a text file with a .json extension in the same action.
I resolved it... All I had to do was deleting [ApiController] attribute. Having that attribute caused application to didn't visit my ImportData method at all.

Wrapping default REST error response in custom object

I'm building a simple REST api for integration purposes, and i want the response to be as consistent as possible (the same regardless of errors).
I've used the #ExceptionHandler method in the past - so I'll most likely go with the class version of this...#ControllerAdvice if i remember correctly.
I know it works, I've used SO before to help me, it just requires setting up. This is not my question...
The API allows creating messages and searching messages (two separate requests), and thus, accepts date values which are internally validated. Upon testing this i received a really nicely formatted and incredibly detailed error response:
{
"timestamp": "2018-08-31T10:35:10.748+0000",
"status": 400,
"error": "Bad Request",
"errors": [
{
"codes": [
"typeMismatch.IntegrationMessageFilter.fromDate",
"typeMismatch.fromDate",
"typeMismatch.java.util.Date",
"typeMismatch"
],
"arguments": [
{
"codes": [
"IntegrationMessageFilter.fromDate",
"fromDate"
],
"arguments": null,
"defaultMessage": "fromDate",
"code": "fromDate"
}
],
"defaultMessage": "Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'fromDate'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [#com.fasterxml.jackson.annotation.JsonFormat java.util.Date] for value '213-456-45'; nested exception is java.lang.IllegalArgumentException",
"objectName": "IntegrationMessageFilter",
"field": "fromDate",
"rejectedValue": "213-456-45",
"bindingFailure": true,
"code": "typeMismatch"
}
],
"message": "Validation failed for object='IntegrationMessageFilter'. Error count: 1",
"path": "/Integration/get"
}
What i want to do is intercept this error and wrap it in my own response object which will be the same response object for every API method available:
e.g.
{
"success": Boolean,
"messageId": Integer, (null on search, int on successful create)
"messages": Array, (searched IntegrationMessage objects)
"errorMessage": String, (error message during manual validation (e.g. range validation depending on the field))
"error" [SPRING DEFAULT ERROR] (this is what i want to intercept from spring-boot and include in this response object)
}
It just sees a bit pointless to manually faff about creating a detailed error message when the system does it already...I don't know what object it uses to create the first JSON message above, or even if i can intercept it.
NOTE: This is purely for the convenience of the API users not having to differentiate between different response objects, and the convenience for me, not having to re-develop the wheel (so to speak).
OK so I've found how to acheive (sort of) what i want.
I was under the impression i could intercept the full exception response message and just put it inside my object, regardless of the type of exception. Turns out, i can get most of the default information, but it is specific to each error type (obviously).
First Attempt:
My first attempt was to simply "test" the default error response with the following. This was meant to identify what spring was doing (which error it was using - I genuinly thought it would have been the handleTypeMismatch exception) - the method below is just one in the class (the one that I'm currently dealing with):
#ControllerAdvice
public class IntegrationExceptionHandler extends ResponseEntityExceptionHandler
{
#Override
public ResponseEntity<Object> handleBindException(final BindException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request)
{
return super.handleBindException(ex, headers, status, request);
}
}
I expected exactly the same error message as the default one, however this produced no response (or an empty response?).
My "Solution":
While i don't have to re-develop the wheel, i do have to do some hoop jumping:
#Override
public ResponseEntity<Object> handleBindException(final BindException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request)
{
IntegrationResponse response = new IntegrationResponse(ex.getMessage());
response.setErrors(ex.getBindingResult().getAllErrors());
return new ResponseEntity<Object>(response, headers, status);
}
Where errors is private List<ObjectError> errors; (org.springframework.validation.ObjectError)
So I'll have to try and replicate each overridable error in the ResponseEntityExceptionHandler (that applies to my situation) and treat it slightly differently, you can see now why i just wanted to wrap the existing response.
Just as a side note, I did try adding: private Object error; and private BindingResult error; as variables in my response object, however both attempts seem to reject my response object and show JUST the default message (as if there is no controller advice) with no hint as to why.
If anyone does discover how to skip the ResponseEntityExceptionHandler step and just wrap the default exception response object, I'll happily accept that answer.

Reading HttpRequest Body in REST WCF

I got a REST WCF Service running in .net 4 and I've tested the web service it is working and accepting HttpRequest I make to it. But I ran into a problem trying to access the HttpRequest body within the web service. I've tried sending random sizes of data appended on the HttpRequest using both Fiddler and my WinForm app and I can't seem to find any objects in runtime where I can find my request body is located. My initial instinct was to look in the HttpContext.Current.Request.InputStream but the length of that property is 0, so I tried looking in IncomingWebRequestContext that object doesn't even have a method nor properties to get the body of the HttpRequest.
So my question is, is there actually a way to access the HttpRequest request body in WCF?
PS:
The data inside the request body is JSON strings and for response it would return the data inside response body as JSON string too.
Much simpler, this answer on WCF + REST: Where is the request data? works fine.
Also, if your request body is deserializable, you can just pass a class. Barring some typos, this should work:
public class Banana
{
public string Colour;
public int Size;
}
...
[WebInvoke(
Method = "POST",
UriTemplate = "bananas",
ResponseFormat=WebMessageFormat.Json,
RequestFormat=WebMessageFormat.Json)]
string CreateBanana(Banana banana);
...
public string CreateBanana(Banana banana)
{
return "It's a " + banana.Colour + " banana!";
}
Doing POST with data {"Colour": "blue", "Size": 5} to this resource should return "It's a blue banana!".
Try with ((System.ServiceModel.Channels.BufferedMessageData)(((System.ServiceModel.Channels.BufferedMessage)((OperationContext.Current.RequestContext).RequestMessage)).MessageData)).Buffer
it has type System.ArraySegment<byte>
or read WCF + REST: Where is the request data?