Rogala
Rogala

Reputation: 2773

Azure Functions - route template with file

I have created an Azure Function that receives an HTTP request and returns an HTTP request. The function:

  1. Accepts an HTTP request
  2. Creates a URI to a location in blob storage with a shared access signature that expires in n minutes/hours
  3. 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}"
        }
    }
}

Upvotes: 0

Views: 1870

Answers (1)

Fabio Cavalcante
Fabio Cavalcante

Reputation: 12538

Currently, there is a limitation with the HttpTrigger and it does not support request with extensions (see this for details).

As stated in the issue, you can use proxies to workaround this limitation, but you do need to remove the alpha constraint from your route.

Here's an example proxy configuration that will forward the id you have above as a query string:

{
    "$schema": "http://json.schemastore.org/proxies",
    "proxies": {
        "Test": {
            "matchCondition": {
                "route": "products/{category}/{id}"
            },
            "backendUri": "https://<functionapp>.azurewebsites.net/api/<function>?id={id}"
        }
    }
}

You can adjust the above to match your requirements, but this should give you the behavior you're looking for.

Upvotes: 2

Related Questions