HttpMediaTypeNotSupportedException - java

I have this class in my .NET application to send some data from client(.NET) to server(Spring) :
class NetworkController
{
private static readonly HttpClient client = new HttpClient();
public static async Task SendUserDataAsync()
{
var values = new Dictionary<string, string>
{
{ "firstName", "sunny" },
{ "lastName", "leone" },
{ "timeStamp", "test" }
};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("http://localhost:8080/user", content);
var responseString = await response.Content.ReadAsStringAsync();
}
}
Reference
And in my Spring Boot application, I a class called User :
#Entity
public class User
{
#Id
private String firstName;
private String lastName;
private String timeStamp;
public User(){}
#Override
public String toString() {
return "firstName : "+this.firstName + "\n"+"lastName : " + this.lastName;
}
}
In my rest-controller I have this method to insert User :
#PostMapping("/user")
User addUser(#RequestBody User user)
{
System.out.println(user);//this always prints an empty line, maybe receiving nothing
return userRepository.save(user);
}
I get this warning Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported]
I have created this class(with the concept of Spring) in .NET, but it seems no use :
class User
{
String firstName;
String lastName;
String timeStamp;
public User()
{
firstName = "1"
lastName = "2"
timeStamp = "test"
}
}
Wouldn't sending an object instead of dictionary be more gentle and tidy ? How to do so ?
How can I resolve this problem ?

In your .NET application, the line var content = new FormUrlEncodedContent(values); indicates that the request will have a HTTP header Content-Type set to application/x-www-form-urlencoded.
It means the data stored in var values = new Dictionary... will be formatted by .NET as a query string such as firstName=sunny&lastName=leone&timeStamp=test.
That is what your Sprint server receives. However it wants to receive JSON data, not a query string. So it complains.
In order to get rid of the miscommunication, your .NET application should send JSON data, such as
{"firstName": "sunny", "lastName": "leone", "timeStamp": "test"},
as expected by the Spring server.
Here is an example code:
HttpClient client = new HttpClient();
object anonymousObject = new
{
firstName = "sunny",
lastName = "leone",
timeStamp = "test"
};
string jsonContent = JsonConvert.SerializeObject(anonymousObject);
var request = new HttpRequestMessage(HttpMethod.Post, "http://127.0.0.1:8080/user");
request.Content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.SendAsync(request);
Console.WriteLine(await response.Content.ReadAsStringAsync());
You need to install the package Newtonsoft.Json in order to call JsonConvert.SerializeObject(anonymousObject), as pointed by this SO answer mentionned by #alfcope.

Related

Passing a BODY of a POST request to the server

I have built a Restful-API Java(SpringBoot) and created the needed requests.
The following request is a POST Request to add new Category.
I have tested the POST request by POSTMAN, and it working as expected.
I am building the client-side in ASP.NET 5.x.x.
Now the problem appear when I am calling the post request, it seems the API doesn't receive the data (#RequestBody category) that has been send from the client.
Here is a code simple of how I have created them
Server Side:
#ResponseStatus(HttpStatus.CREATED)
#PostMapping(value = "/add", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public CategoryDTO create(#RequestBody CategoryDTO category) {
log.info("Adding new Category Name: " + category.getName());
return categoryMapper.asCategoryDTO(categoryService.save(categoryMapper.asCategory(category)));
}
Client Side
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Category category)
{
Category newCategory = new Category();
// Serialize the concrete class into a JSON String
var stringPayload = JsonConvert.SerializeObject(category);
// Wrap the JSON inside a StringContent which then can be used by the HttpClient class
StringContent content = new StringContent(stringPayload);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.PostAsync("http://localhost:8080/category/add", content))
{
string apiResponse = await response.Content.ReadAsStringAsync();
newCategory = JsonConvert.DeserializeObject<Category>(apiResponse);
}
}
return RedirectToAction("Index");
}
I don't know what is wrong there, could anybody help!
EDIT--
Here is the request via postman
EDIT
I have created another POST request but as a RequestParam instead of RequestBody
#ResponseStatus(HttpStatus.CREATED)
#PostMapping(value = "/add", produces = MediaType.APPLICATION_JSON_VALUE)
public CategoryDTO addCategory(#RequestParam(name = "categoryName") String categoryName){
return categoryMapper.asCategoryDTO(categoryService.addCategory(categoryName));
}
and created in the client side the request as following
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Category category)
{
Category newCategory = new Category();
var parameters = new Dictionary<string, string> { { "categoryName", category.Name } };
var encodedContent = new FormUrlEncodedContent(parameters);
using (var httpClient = new HttpClient())
{
using (var response = await httpClient.PostAsync("http://localhost:8080/category/add", encodedContent))
{
string apiResponse = await response.Content.ReadAsStringAsync();
newCategory = JsonConvert.DeserializeObject<Category>(apiResponse);
}
}
return RedirectToAction("Index");
}
And It's works fine!
So the problem is how to pass the data via the httpClient, which need to be of type RequestBody (the data in the body not in the header!) also as a application/json.
So how to pass the data?
I suppose that your spring boot application just blocks POST request because you didn't provide instruction how to handle requests. Try to disable csrf protection like it did here: https://stackoverflow.com/a/48935484/13314717
It might be a problem in the naming convention. Starting with capital letters in properties in C#, and starting with lowercase in Java.
If your class looks like this in C#
class Category {
int Id;
string Name;
...
}
And like this in Java
class Category {
int id;
string name;
...
}
It is not going to work so you have to match the property names. So make either both id or both Id.

How I get RESTful response correctly?

I am consuming a restful with spring but I do not achieve get all data successfully.
RESTful response detail:
{
"errorCode": "0",
"errorMessage": "OK",
"transactionUUID": "2e48d6e7-f1fb-4271-b282-d74d3df1ef23",
"data":{
"price": "123",
"quantity" : "1",
"productname" : "Anystuff"}
}
My classes:
public class ResponseRest{
private String errorCode;
private String errorMessage;
private String transactionUUID;
private ResponseDetail data;
//get and set methods
}
public class ResponseDetail {
private String price;
private String quantity;
private String productname;
//get and set methods
}
Piece of my method in my controller class:
HttpHeader headers;
//headers.set....
String jsonParam = "{\"transactionToken\":\""+transactionToken+"\","
+ "\"sessionToken\":\""+sessionToken+"\"}";
RestTemplate restTemplate = new RestTemplate();
HttpEntity<String> entity = new HttpEntity<String>(jsonParam, headers);
response = restTemplate.exchange(URL_API_AUTH, HttpMethod.POST, entity, ResponseRest.class);
When I got result by console, I only get the properties from the ResponseRest class but not their detail from class ResponseDetail, console result:
System.out.println("-> Result - status ("+ response.getStatusCode() + ") has body with: " + (response.getBody().toString()));
Result - status (200) has body with: ResponseRest[errorCode="0", errorMessage="OK",transactionUUID="2e48d6e7-f1fb-4271-b282-d74d3df1ef23", data[price=null,quantity=null,productname=null]]
What I doing wrong?
Thanks a lot for their time.

How to pass object containing list of other custom objects to call REST service using HttpPost

I am trying to call REST service by passing object as parameter which contains list of other custom objects. I am getting "Error 405: Request method POST not supported" error.
Client side code-
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(SSLConnectionSocketFactory.getSystemSocketFactory()).build();
httpPost = new HttpPost("http://api100.abc.xyz.com:9080/abcd/api/sscws/v1/saveContributions");
httpPost.addHeader(WebAppConstants.CONTENT_TYPE, WebAppConstants.APPLICATION_JSON);
httpPost.addHeader(WebAppConstants.ACCEPT, WebAppConstants.APPLICATION_JSON);
httpPost.addHeader(WebAppConstants.X_USERNAME, userContext.getUserID());
httpPost.addHeader(WebAppConstants.X_ENTERPRISE_ID, "123456");
httpPost.addHeader(WebAppConstants.X_UNIQUE_ID, "A548742ATG"); //to do
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
String requestParamJson = ow.writeValueAsString(contribRequestParamDto);
httpPost.setEntity(new StringEntity(contribRequestParamDto, WebAppConstants.UTF_8));
In above code contribRequestParamDto is a object of ContributionsRequestParamDto class which will look this-
public class ContributionsRequestParamDto {
private String tokenID;
private String taxID;
private String affiliateID;
private long planID;
private String accountNumber;
private String bankAccountNumber;
private String transitId;
private BigDecimal eftAmt;
private Date ppeDate;
private String taxYear;
private Short planType;
private List<ParticipantsDeferralDto> participantsDeferrals;
private List<EmployersContributionDto> employersContributions;
}
REST endpoint will look like this-
#Transactional
#RestController
#RequestMapping("/v1")
#Api(value="v1", description="")
public class SscRestController {
#RequestMapping(value="/saveContributions",
method=RequestMethod.POST, produces={MediaType.APPLICATION_JSON_VALUE}, consumes={MediaType.APPLICATION_JSON_VALUE})
#ApiOperation(value="Returns the saved contributions object")
public String saveContributions(#RequestBody ContributionsRequestParam contributionsParam) throws Exception {
return "success";
}
}
Json request body is-
{
"tokenID" : "123456789",
"taxID" : "123456",
"affiliateID" : "123456789",
"planID" : 123456,
"ppeDate" : "2017-10-24",
"taxYear" : "2017",
"planType" : 1,
"participantsDeferrals" : [ {
"taxId" : "555555",
"participantDeferralAmt" : 22.00
} ],
"employersContributions" : [ {
"taxId" : "555555",
"employerContributionAmt" : 22.00
} ]
}
This is not working as I am getting "Error 405: Request method POST not supported" error. It will work if remove list fields for 'participantsDeferrals' and 'employersContributions' from JSON request body by removing those list fields from 'ContributionsRequestParamDto' object. So I am sure that there is something wrong with list of custom objects and its corresponding JSON request body. Am I missing something here? Please help. Thanks!
I have changed the type of the Date. Now it is normal String and not SQL date. After changing its type to string in object, it is working fine

415 Unsupported Media Type (JAVA + Angular + RestFULL JSON)

I hava a problem with my one controller. When i send (POST) data from angular to java controller using ( jason content type ) i see error which is visible in the topic. So I can't catch response from server. Controller catch this request good so in this case book is added to database correctly. Firebug show 404 error but when I checked in Postman I saw 415 Unsupported Media Type. Why there is such an exception if the controller is working properly.
This is example JSON:
{"title":"fgthbfgd","authors":[{"author_id":24,"author":"danielle steel"}],"genres":[{"genre_id":1,"genre":"Dramat"}],"description":"rthg","path_image":"19296.png"}
and this is controller:
#SuppressWarnings("finally")
#RequestMapping(value = "/rest/book", consumes = "application/json", produces = "application/json", method = RequestMethod.POST)
public MessageDTO addNewBook(#RequestBody BookDTO newBook) {
MessageDTO message = new MessageDTO();
try {
bookService.addNewBook(newBook);
message.setCheck(true);
} catch (BookTitleException e) {
message.setCheck(false);
message.setDescription("Ksiązka o tym tytule juz istnieje.");
e.printStackTrace();
} finally {
return message;
}
}
This is BookDTO
public class BookDTO implements Serializable{
private static final long serialVersionUID = -5057364006691079475L;
private Integer id;
private AuthorEntity [] authors;
private String description;
private GenreEntity [] genres;
private String title;
private String path_image;
private double rate;
private Integer progressBar;
private boolean flagRate;
private double userRate;
/* geters and seters */
}
This is Angular code:
var bookResource = $resource( $rootScope.restUrl + 'book');
var book = {
title : $scope.title,
authors : $scope.author,
genres : $scope.genre,
description : $scope.description,
path_image: null
}
service.addNewBook = function(book){
var deferred = $q.defer();
bookResource.save(book)
.$promise.then( function(data){
deferred.resolve( data );
}, function(){
deferred.reject("Error during adding new book.");
});
return deferred.promise;
}
This is only a problem in my aplication. In another case all working correctly.
You have a 415 error because you send your request without the right content-type header
var bookResource = $resource( $rootScope.restUrl + 'book',{}, {
save:{
method:"POST",
headers:{'Content-Type':'application/json; charset=UTF-8'}
}
});
I hope it will solve your problem

How to annotate Play 2 webapp model for swagger?

I'm an android/java developer new to Play2 framework. I'm trying to generate documentation to my RESTful API with swagger.
I've managed to include swagger into my Play2 webapp and generate simple api-docs.json. The only part I am missing is model description. I have User controller and User model in /controllers and /models accordingly.
#Api(value = "/user", listingPath = "/api-docs.{format}/user", description = "User registration and authorisation")
public class User extends Controller {
#POST
#ApiOperation(value = "Create user", notes = "Used to register new user.")
#ApiParamsImplicit(#ApiParamImplicit(name = "body", value = "Created user object", required = true, dataType = "User", paramType = "body"))
#BodyParser.Of(BodyParser.Json.class)
public static Result createUser() {
JsonNode json = request().body().asJson();
ObjectNode result = Json.newObject();
JsonNode body = json.findPath("body");
if(body.isMissingNode()) {
result.put("status", "KO");
result.put("message", "Missing parameter [body]");
return badRequest(result);
}
JsonNode name = body.get("name");
if(name == null) {
result.put("status", "KO");
result.put("message", "Missing parameter [body.name]");
return badRequest(result);
}
result.put("status", "OK");
result.put("message", "Hello " + name.getTextValue());
return ok(result);
}
}
I've tried to annotate model exactly as in an example
#XmlRootElement(name = "User")
public class User {
public String name;
#XmlElement(name = "name")
public String getName() {
return name;
}
}
The result is:
{
apiVersion: "beta",
swaggerVersion: "1.1",
basePath: "http://localhost:9000",
resourcePath: "/user",
apis: [
{
path: "/user",
description: "User registration and authorisation",
operations: [
{
httpMethod: "POST",
summary: "Create user",
notes: "Used to register new user.",
responseClass: "void",
nickname: "createUser",
parameters: [
{
name: "body",
description: "Created user object",
paramType: "body",
required: true,
allowMultiple: false,
dataType: "User"
}
]
}
]
}
]
}
Any ideas ?
I've found the answer myself.
It appears that swagger acknowledges a model when it is being used as a return value, ie responseClass:
#ApiOperation( value = "Find quiz by ID",
notes = "Returns a quiz with given ID",
responseClass = "models.Quiz" )
#ApiErrors( value = {
#ApiError(code = 400, reason = "Invalid ID supplied"),
#ApiError(code = 404, reason = "Quiz not found") })
public static Result getQuizById(
#ApiParam(value = "ID of question that needs to be fetched", required = true) #PathParam("quizId")
String quizId) {
ObjectNode result = Json.newObject();
return ok(result);
}
Simply adding method like this makes corresponding model appear in api-docs.json.

Categories

Resources