Reputation: 520
I'm new to Azure Functions and have a simple question about how to generate a Location header for a newly created resource. I have created a simple function that is used to create a Person (original eh?).
In my example I'm using DocumentDB for storage. I want to return a Location header to the client that they can then de-reference should they wish to, but to do that I need to know about routing.
My code is as follows...
public static class PersonProcessing
{
[FunctionName("person")]
public static async Task<HttpResponseMessage> Create(
[HttpTrigger(AuthorizationLevel.Anonymous, "post")]HttpRequestMessage req,
[DocumentDB("Test", "People", CreateIfNotExists = true)]ICollector<Person> outTable,
TraceWriter log)
{
var tx = await req.Content.ReadAsAsync<Person>();
tx.Id = Guid.NewGuid();
outTable.Add(tx);
var response = req.CreateResponse(HttpStatusCode.Created, tx);
response.Headers.Location = new Uri($"{req.RequestUri}/{tx.Id}");
return response;
}
public class Person
{
[JsonProperty("id")]
public Guid Id { get; set; }
public string Name { get; set; }
}
}
I have created the Location header based on the incoming RequestUri, but is there a better (or more standard) way to do this with Azure Functions?
Is what I have done here accepted wisdom - I can't find any useful resources on the web hence my question?
Thanks in advance for your responses.
Upvotes: 1
Views: 2098
Reputation: 3438
Another way to accomplish this is by having your function return an IActionResult
and then returning a CreatedResult
For example:
[FunctionName("TwoOhWhan")]
public async Task<IActionResult> ReturnATwoOhWhanEvenIfCORSIsInThePicture(
[HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "v1/test/twoohwhan")]
HttpRequest req,
ILogger logger)
{
// ... logic here
var @return = new CreatedResult(location, new
{
id = resourceIdentifier
});
//This trumped me for a while. In ASPNET Core you get this done by using
//the extension method: .WithExposedHeaders("Location")
req.HttpContext.Response.Headers.Add("Access-Control-Expose-Headers", "Location");
return @return;
}
I like this approach because its easier to gather what is going on here by returning a result that signifies the 201 itself.
I snuck in a little icing on top of this answer. Check out the line right about the return @return
statement. If you are making cross origin requests to an HTTP triggered function you are in for a bad time. The location header will be visible in fiddler or your network chrome tab but you won't have access to it in your JS code.
Typically this is handled in your startup.cs
file in an aspnetcore setting but azure functions don't have a way to do this. The azure portal dashboard also does not give you an option to do this in the CORS
settings page found under the Platform Settings
section.
Its not very intuitive and information on the internet regarding this little caveat is hard to come by. Hopefully this helps someone else in a similar situation.
Upvotes: 1
Reputation: 8336
I'm using azure functions v2 and the above doesn't seem to work. However I tried
var headers = req.HttpContext.Response.Headers;
var when = DateTime.UtcNow;
var v = new StringValues(when.ToString("yyyy-MM-dd HH:mm:ss.ffffff"));
headers.Add("now", v);
and it seems to work just fine.
Upvotes: 2
Reputation: 43183
I don't know of a different way, and there is nothing wrong with what you have. It's using the standard HttpResponseMessage
pattern rather than inventing a different way to do this. Generally, http triggered Functions just use the standard paradigms when it comes to dealing with the request.response.
Upvotes: 2