I have created an Azure Function that receives an HTTP request and returns an HTTP request. The function:
- Accepts an HTTP request
- Creates a URI to a location in blob storage with a shared access signature that expires in n minutes/hours
- Returns a 302 status code with the location header set to the URI that will expire in n minutes/hours
I was able to get this to work when I placed the path to the blob in a query parameter, but it fails when that variable is in the route template.
I tried to make the route template: storage/{containerName:alpha}/{path:alpha} but it always returns a 404. Below is an example cURL of how the request is constructed.
GET /api/storage/example-container-name/example.jpg?code=SSBhbSBhIHRlYXBvdCwgZG8geW91IHRoaW5rIEkgd291bGQgcHV0IGEgcGFzc3dvcmQgaGVyZT8= HTTP/1.1
Host: hostdoesnotexist.azurewebsites.net
Cache-Control: no-cache
**Note:The host is not real, path and code are not real.*
I did find this question that was related to the Azure Functions Proxy doing the same thing, but this question is not applicable to the Functions.
Azure Functions Proxy - route to storage account
Using this Azure Functions HTTP and webhook bindings example, and scrolling to the Customizing the HTTP endpoint section, I created another function with the following code:
Function.json - id changed from int? to alpha
{
"bindings": [
{
"name": "req",
"type": "httpTrigger",
"direction": "in",
"methods": [
"get"
],
"route": "products/{category:alpha}/{id:alpha}",
"authLevel": "function"
},
{
"name": "$return",
"type": "http",
"direction": "out"
}
],
"disabled": false
}
run.csx
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req,
string category,
string id,
TraceWriter log)
{
if (id == null)
return req.CreateResponse(HttpStatusCode.OK, $"All {category} items were requested.");
else
return req.CreateResponse(HttpStatusCode.OK, $"{category} item with id = {id} has been requested.");
}
So if the route is products/test/abcd then it responds with:
200 - "test item with id = abc has been requested."
But, if you change this to products/test/abcd.jpg then it responds with:
404 - The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
This is the same behavior I am seeing with the other function I created.
Does anyone know if this is a bug like the proxies example, or should my route look different? Again, I have this working using query parameters, but it fails when I move the variables into the route template.
Edited - Added files based on feedback function.json
{
"bindings": [
{
"name": "req",
"type": "httpTrigger",
"direction": "in",
"methods": [
"get"
],
"route": "products/{category:alpha}",
"authLevel": "function"
},
{
"name": "$return",
"type": "http",
"direction": "out"
}
],
"disabled": false
}
run.csx
using System.Net;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req,
string category,
TraceWriter log)
{
string id = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "id", true) == 0)
.Value;
if (id == null)
return req.CreateResponse(HttpStatusCode.OK, $"All {category} items were requested.");
else
return req.CreateResponse(HttpStatusCode.OK, $"{category} item with id = {id} has been requested.");
}
proxies.json
{
"$schema": "http://json.schemastore.org/proxies",
"proxies": {
"GetJustArtinAroundStorageLinkProxy": {
"matchCondition": {
"route": "/products/{category:alpha}/{id}",
"methods": [
"GET"
]
},
"backendUri": "https://<company-name>.azurewebsites.net/api/products/{category:alpha}?id={id}"
}
}
}