Self-hosted Web API - Post Param null - asp.net-web-api

I'm trying to set up a simple test to make a POST request to my self-hosted Web-API server.
var config = new HttpSelfHostConfiguration(new Uri(baseAddress));
// add a route
config.Routes.MapHttpRoute(name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();
I added a Controller:
public class PayloadController : ApiController
{
public string Get()
{
return "Hello from GET";
}
public HttpResponseMessage PostItem(Payload payload)
{
// payload
//...
}
}
And I do have the corresponding model (making sure it contains properties):
public class Payload
{
public string Date { get; set; }
public string Command { get; set; }
}
I'm using Rest Console on Chrome to test the server, getting correct results for the GET in my controller.
Issueing the following request as POST:
Request Url: http://localhost:8080/api/payload
Request Method: POST
Params: {
"Date": "2012.09.26",
"Command": "Hello"
}
EDIT: Content-Type is set to application/json and encoding to UTF-8
Setting a break-point at the controller shows that the POST params are not correctly deserialized into an Paylod object, the param is null.
What am I possibly missing?

You need to specify the request Content-Type as application/json
Edit
Complete response with info from the comments below:
If you are using REST console's "request parameters" instead of "request payload raw body" it will not generate JSON out of them even when you specify application/json.
You need to paste raw JSON into the raw body field like this: http://screencast.com/t/iRWZqv91
{
"Date": "2012.09.26",
"Command": "Hello"
}

If you are receiving a null post parameter to your controller you need to create a constructor with 0 parameters in your model.
Greetings

Related

How to use #PostMapping and Postman to send post request and JSON Object as a request parameter

**I am trying to make a POST controller in springboot having request parameter as JSON object and hiting the controller from the postman .The problem I am facing is that I want to pass a JSONObject in the parameter itself from the postman. I am sending JSON from POSTMAN in body, basically pasted JSON object in the raw body **
#RestController
public class PostController {
#PostMapping(value="/status")
public JSONObject status (#RequestBody JSONObject jsonObject){
System.out.println(jsonObject.toString());
return jsonObject;
}
}
`
I am hitting from the postman with POST request at the url : localhost:8080/status ,,
I am not getting the appropriate response. Main problem is that the JSON object is not getting passed to the request . PLease explain.
Intellij terminal response :
{}
AT line 19
and POSTMAN response is :
{
"empty": true,
"mapType": "java.util.HashMap"
}
enter image description here

Spring Boot Content Type Error even when specified in Kotlin

I have an issue in Spring Boot with Kotlin
I have a function that accepts all major Content Types as defined below:
#PostMapping(
value = ["/users/new"],
consumes = [
MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE,
MediaType.MULTIPART_FORM_DATA_VALUE,
MediaType.APPLICATION_FORM_URLENCODED_VALUE]
)
fun registerNewUser(
#RequestHeader("X-Forward-For") ipAddress: String?,
newUser: NewUser,
request: HttpServletRequest
): ResponseEntity<ObjectNode> {
var realIPAddress = ipAddress
if (realIPAddress == null) {
realIPAddress = request.remoteAddr
}
return userService.registerUser(realIPAddress!!, newUser)
}
Here is how my NewUser class is defined in kotlin
data class NewUser(val email: String?, val password: String?)
Here is how I am doing the check in the registration function
if (!StringUtils.hasText(newUser.email)) {
return responseHandler.errorResponse(
HttpStatus.BAD_REQUEST,
"Please provide an email address"
)
}
Now when I sent a post request with postman and even axios I keep getting the error as shown in the screenshot below
That error message should only be displayed if email address is not provided. But as you can see clearly, the email address is provided in the JSON Payload.
What could be wrong?
Note: This works when the Content-Type is application/x-www-form-urlencoded but doesn't work when the Content-Type is application/json
put #RequestBody before newUser parameter to specify that input should be inside http body part. by default function parameters in spring are considered to be url parameters which can be further clarified with #RequestParam.
there are 2 ways to insert request parameters into http request. one is to attach request parameters to end of the url and the other is to put in http body with application/x-www-form-urlencoded as the content-type.

Spring post method "Required request body is missing"

#PostMapping(path="/login")
public ResponseEntity<User> loginUser(#RequestBody Map<String, String> userData) throws Exception {
return ResponseEntity.ok(userService.login(userData));
}
I have this method for the login in the UserController. The problem is when i try to make the post request for the login i get this error:
{
"timestamp": "2018-10-24T16:47:04.691+0000",
"status": 400,
"error": "Bad Request",
"message": "Required request body is missing: public org.springframework.http.ResponseEntity<org.scd.model.User> org.scd.controller.UserController.loginUser(java.util.Map<java.lang.String, java.lang.String>) throws java.lang.Exception",
"path": "/users/login"
}
You have to pass that as JSON in your body, if it's a POST request.
I had a similar issue, was getting this error in my Spring Boot service
HttpMessageNotReadableException: Required request body is missing:...
My issue was that, when I was making requests from Postman, the "Content-Length" header was unchecked, so service was not considering the request body.
This is happening because you are not passing a body to you server.
As can I see in your screenshot you are passing email and password as a ResquestParam.
To handle this values, you can do the following:
#PostMapping(path="/login")
public ResponseEntity<User> loginUser(#RequestParam("email") String email, #RequestParam("password") String password) {
//your imp
}
In order to accept an empty body you can use the required param in the RequestBody annotation:
#RequestBody(required = false)
But this will not solve your problem. Receiving as RequestParam will.
If you want to use RequestBody you should pass the email and password in the body.
You need to send data in Body as JSON
{ "email":"email#email.com", "password":"tuffCookie"}
If it's still not working, try adding additional information UTF-8 in Headers.
key : Content-Type
value : application/json; charset=utf-8
For my case, I must adding UTF-8 in Headers.
In my case it was poorly defined JSON that I sent to my REST service.
Attribute that was suppose to be an object, was in my case just string:
Changed from:
"client" = "",
to:
"client" = { ... },
In my case String did not add additional information about value in different format.

WebAPI OData v4 custom action without parameters can't be routed with error "No routing convention was found..."

I have very simple OData controller that successfully process standard actions (at least GET, POST, PUT and DELETE methods are working). I have followed this tutorial and added simple bound action. The method has parameters argument, but actually it does not required the parameters:
[HttpPost]
public IHttpActionResult Close([FromODataUri] int key, ODataActionParameters parameters) {
return Ok();
}
I have defined this action in OData EDM configuration as following:
builder.EntitySet<Ticket>("tickets");
builder.EntityType<Ticket>().Action("Close");
I am trying to call action from Postman:
POST /odata/tickets(2)/Default.Close HTTP/1.1
Host: localhost:50477
Accept: application/json
Content-Type: application/json
Cache-Control: no-cache
Postman-Token: eef4c1f6-8c7f-f5eb-c22d-4397f3bda170
But receives the error message:
{
"error": {
"code": "",
"message": "No HTTP resource was found that matches the request URI 'http://localhost:50477/odata/tickets(2)/default.close'.",
"innererror": {
"message": "No routing convention was found to select an action for the OData path with template '~/entityset/key/unresolved'.",
"type": "",
"stacktrace": ""
}
}
}
I have read the whole internet and all related articles on SO but can't fix this issue. Please help me because I have no any fresh idea how to fight this.
My controller:
public class TicketsController : ODataController
{
[HttpPost]
public IHttpActionResult Close([FromODataUri] int key, ODataActionParameters parameters)
{
return Ok();
}
}
My request:
string requestUri = "http://localhost/odata/tickets(2)/Default.Close";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUri);
request.Content = new StringContent("",
Encoding.UTF8,
"application/json");
HttpResponseMessage response = _client.SendAsync(request).Result;
Or remove the ODataActionParameters parameters in the close method and call with:
string requestUri = "http://localhost/odata/tickets(2)/Default.Close";
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, requestUri);
HttpResponseMessage response = _client.SendAsync(request).Result;
My EdmModel is use your model.

Asp.Net WebApi OData with DataJs throws an error

I just created a really simple ASP.Net WebApi project. I used NuGet to download the latest OData in WebAPI – RC release. I also download DataJs and Knockout via NuGet. All my dependencies are up to date. I created a simple "Books" class and wired everything together using HttpConfiguration.EnableOData(IEdmModel). I also added the [Queryable] attribute to my Get action in the controller. There is not database involved, I hard-coded the data I want returned. Basically, I did the minimum amount of changes to run my project with WebApi and OData.
When I try to query the OData service using DataJs, I get a 500 Internal Server Error in the response, but if I browse to the URL directly I can see the XML data. I've included the request, response, my C# class, the Javascript code, and the Global.asax code. What am I missing to get this to work?
REQUEST
Response Headers
Cache-Control private
Content-Length 966
Content-Type application/json; odata=fullmetadata; charset=utf-8
DataServiceVersion 3.0;
Date Fri, 21 Dec 2012 22:13:27 GMT
Server Microsoft-IIS/8.0
X-AspNet-Version 4.0.30319
X-Powered-By ASP.NET
X-SourceFiles =?UTF-8?B?YzpcdXNlcnNcanVzdGluXGRvY3VtZW50c1x2aXN1YWwgc3R1ZGlvIDIwMTJcUHJvamVjdHNcRGF0YUpzU3Bpa2VcRGF0YUpzU3Bpa2VcYXBpXEJvb2tz?=
Request Headers
Accept application/atomsvc+xml;q=0.8, application/json;odata=fullmetadata;q=0.7, application/json;q=0.5, */*;q=0.1
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Connection keep-alive
Cookie glimpseState=null; glimpseLatestVersion=0.87; glimpseOptions=null; glimpseClientName=null
Host localhost:31652
MaxDataServiceVersion 3.0
Referer http://{localhost}/
User-Agent Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0
RESPONSE
{
"odata.error":{
"code":"","message":{
"lang":"en-US","value":"An error has occurred."
},"innererror":{
"message":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; odata=fullmetadata; charset=utf-8'.","type":"System.InvalidOperationException","stacktrace":"","internalexception":{
"message":"The related entity set could not be found. The related entity set is required to serialize the payload.","type":"System.Runtime.Serialization.SerializationException","stacktrace":" at System.Web.Http.OData.Formatter.Serialization.ODataFeedSerializer.WriteObject(Object graph, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)\r\n at System.Web.Http.OData.Formatter.ODataMediaTypeFormatter.<>c__DisplayClass8.<WriteToStreamAsync>b__7()\r\n at System.Threading.Tasks.TaskHelpers.RunSynchronously(Action action, CancellationToken token)"
}
}
}
}
C# Class
namespace DataJsSpike.Models
{
public class Book
{
public string ISBN { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public string Publisher { get; set; }
}
}
Javascript Code
// the URL of the first page to retrieve
var startPage = "api/Books";
var viewModel = new Object();
viewModel.books = ko.observable();
// On initialization, make a request for the first page
$(document).ready(function () {
LoadDataJs();
function LoadDataJs() {
OData.read(startPage, function (data) {
viewModel.books(data.results);
ko.applyBindings(viewModel);
});
}
});
Global.asax
public class WebApiApplication : HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
var modelBuilder = new ODataConventionModelBuilder();
EntityTypeConfiguration<Book> bookConfiguration = modelBuilder.Entity<Book>();
bookConfiguration.HasKey(x => x.ISBN);
modelBuilder.EntitySet<Book>("Books");
IEdmModel model = modelBuilder.GetEdmModel();
GlobalConfiguration.Configuration.EnableOData(model, "api");
}
}
EnableOData actually registers a route for you, but since you registered routes before it ran, those routes take precedence. If you remove this line:
RouteConfig.RegisterRoutes(RouteTable.Routes);
I think it should work out. The request needs to come in on an OData route for the OData formatting to work because the route parses the OData path and gives the formatter information about things like the Entity Set that's being accessed.

Resources