user2549803
user2549803

Reputation: 333

Post nested resource and return new location Uri

I created an apicontroller that offers a Post method to create a new nested resource (in this example: customer > mediaFile):

[Route("api/Customer/{customerId}/MediaFile", Name = "CreateMediaFileForCustomer")]
[HttpPost]
[ResponseType(typeof(MediaFile))]
public IHttpActionResult Post(long customerId, [FromBody]MediaFile mediaFile)
{
    ...

    return CreatedAtRoute("CreateMediaFileForCustomer", new { id = mediaFile.Id }, mediaFile);
}

I expected the CreatedAtRoute method to return a location header that looks like this:

http://localhost:51656/api/Customer/1/MediaFile/37

But instead I got this:

http://localhost:51656/api/Customer/1/MediaFile?id=37

After struggling quite a bit I came up with a "solution" that somehow feels like a cheesy approach:

[Route("api/Customer/{customerId}/MediaFile/{generatedMediaFileId:long?}", Name = "CreateMediaFileForCustomer")]
[HttpPost]
[ResponseType(typeof(MediaFile))]
public IHttpActionResult Post(long customerId, [FromBody]MediaFile mediaFile)
{
    ...

    return CreatedAtRoute("CreateMediaFileForCustomer", new { generatedMediaFileId = mediaFile.Id }, mediaFile);
}

So like this I have an optional resource id that I only need to then set the location header correctly. Is this the way it is meant to work? Or is there a more elegant solution?

Thanks!

Upvotes: 0

Views: 171

Answers (1)

Craig H
Craig H

Reputation: 2071

The "CreatedAtRoute" location header should return a URL to where you can see the newly created resource. You are using the same route name as your POST method. So I would expect to see something like this:

[HttpGet()]
[Route("api/Customer/{customerId}/MediaFile/{id}", Name="GetMediaFileForCustomer")]
public IHttpActionResult Get(long customerId, long id)
{
    ....
}

And your CreatedAtRoute would be:

return CreatedAtRoute("GetMediaFileForCustomer", new { customerId = customerId, id = mediaFile.Id }, mediaFile);

Upvotes: 1

Related Questions