Im having a very bad time triying to figure out this problem, I have a web API made in net core 6 with Entity Framework, in this web api I have to consume a third party API. If a try to make a POST request directly the Swagger UI it works perfectly: POST in Swagger HOWEVER, if i made a post request in javascript using fetch it return a 400 error, that to be honest doesn't say much: 400 error response I know there is no missing data in my post request, I checked a lot, in fact there is no field call "data".
Here is the code to make a fetch in the frontend:
return fetch(apiURL, {
method: 'POST',
headers: {
'Content-Type': 'text/plain',
},
body: JSON.stringify(data)
})
.then(response => response.json())
Here is the post method in net core
[HttpPost]
public async Task<string> PostProductAsync(string data)
{
HttpResponseMessage response = await _client.PostAsync(path, new StringContent(data, Encoding.UTF8, "application/json"));
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
return json;
}
I'm a bit confused. What could i be doing wrong.
UPDATE
I followed each instruction in the answers section, and I can say that it makes a lot of sense to put [FromBody] in the POST method since in the fetch method I am sending the data in the body. However this led me to a new parsing error: parsing error after POST request
I have been searching in other forums about this error, it seems that what is recommended in this case is to make a class Unexpected character encountered while parsing value: . Path '', line 1, position 1
Now, the problem that i have with this approach its that i have quite a big json to post, witch means that i will have to create a lot of classes to make this possible. Its there any way to this without creating a class?
So far i tried the following changes in the POST method:
Adding [FromBody]
[HttpPost]
public async Task<string> PostProductAsync([FromBody] string data)
{
HttpResponseMessage response = await _client.PostAsync(path, new StringContent(data, Encoding.UTF8, "application/json"));
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
return json;
}
This one leads to the parsing error mentioned before.
Adding [FromBody] and changing string to object
[HttpPost]
public async Task<string> PostProductAsync([FromBody] object data)
{
HttpResponseMessage response = await _client.PostAsync(path, new StringContent(data.ToString(), Encoding.UTF8, "application/json"));
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
return json;
}
This one leads to a non valid JSON is not a valid JSON error
CodePudding user response:
Your Swagger UI is sending your data as a Query
parameter, but you are trying to post it through body
in your fetch. They are two different methods of post. I recommend you use body
only.
Change your controller method to use the [FromBody]
parameter attribute:
PostProductAsync([FromBody] string data)
More information from https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api#using-frombody
Defaults for a string, in your case:
If the parameter is a "simple" type, Web API tries to get the value from the URI. Simple types include the .NET primitive types (int, bool, double, and so forth), plus TimeSpan, DateTime, Guid, decimal, and string, plus any type with a type converter that can convert from a string. (More about type converters later.)
So the default behavior is what Swagger is currently using.
CodePudding user response:
Since you want to pass json type data,you need to use 'Content-Type': 'application/json'
in fetch,and then use [FromBody]
in action.
fetch:
return fetch(apiURL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data)
})
.then(response => response.json())
action:
[HttpPost]
public async Task<string> PostProductAsync([FromBody]string data)
{
HttpResponseMessage response = await _client.PostAsync(path, new StringContent(data, Encoding.UTF8, "application/json"));
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
return json;
}
CodePudding user response:
In your case, you can bind model in two ways.
Simple type model binding approach
Since you are accepting simple type string value in controller, you can use 'Content-Type': 'application/x-www-form-urlencoded'
in fetch
and you can pass parameter data in the URL as following:
At fetch:
let apiURL = `https://localhos:8080/Test/data`;
return fetch(apiURL, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: null
}).then(response => response.json())
Complex type model binding approach
Let's assume you're now posting complex object type data. To post data from request body Content-Type
should be application/json
. And add [FromBody]
in the action to define the location to get data from request. Here's the example code snippet.
At fetch:
return fetch(apiURL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data)
}).then(response => response.json())
At controller:
[HttpPost]
public async Task<string> PostProductAsync([FromBody]string data)
{
HttpResponseMessage response = await _client.PostAsync(path, new StringContent(data, Encoding.UTF8, "application/json"));
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
return json;
}
On a side note, please avoid using text/plain
as Content-Type
to avoid security issues.
Hope this helps you and here's for your further reference for model binding in ASP.NET Core.