Reputation: 187
I'm just starting out with .NET Web API programming, and I have a question for seasoned .NET developers - what is the "correct" way to pass an object reference into a Create endpoint?
I have the following models:
public class Task
{
public int ID { get; set; }
public string Title { get; set; }
public virtual User User { get; set; }
}
public class User
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
And my Controller - endpoint to create a Task
:
[HttpPost]
public async Task<IActionResult> PostTask([FromBody] Models.Task task)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_context.Task.Add(task);
await _context.SaveChangesAsync();
return CreatedAtAction("GetTask", new { id = task.ID }, task);
}
By default, this has some interesting behavior. It expects an entire User
model to be passed into the POST request (see below), and will actually create the user when passed:
{
"id": 0,
"title": "string",
"user": {
"id": 0,
"firstName": "string",
"lastName": "string"
}
}
I understand technically why it would do this, but this is definitely not acceptable behavior in a real app - so my question is - what is the "correct/appropriate" way to pass a UserID
and do validation on the model in .NET? Should I forego the use of "ModelState.IsValid
" and do manual validation?
As a secondary question - I am using NSwag to generate Swagger docs from my API, and it's showing "id
" as a parameter that needs to be passed into the POST method. Obviously, ID
cannot be passed as it's generated in code, but is there a way to get Swagger to not show ID
as being a passable property?
Upvotes: 1
Views: 1829
Reputation: 1
The attribute [Required]
is mandatory and then you can check parameter.
Upvotes: 0
Reputation: 247451
Then create a data transfer model that exposes only the data you want sent over the wire.
public class NewTaskDto {
[Required]
public string Title { get; set; }
[Required]
public int UserId { get; set; }
}
and map the data to your models on the server, along with what ever validation is required. For example checking that the UserId
exists and is valid.
[HttpPost]
public async Task<IActionResult> PostTask([FromBody] NewTaskDto data) {
if(data != null) {
validateUserId(data.UserId, ModelState);
}
if (!ModelState.IsValid) {
return BadRequest(ModelState);
}
Models.Task task = MapDataToTask(data); //create Task and copy members
await saveTask(task);
return CreatedAtAction("GetTask", new { id = task.ID }, task);
}
That way the doc will only see the and report on the exposed members.
Upvotes: 1