How to call another function with in an Azure function

Viewed 61255

I have written 3 functions as follows

  1. create users in db
  2. fetch users from db
  3. process users

In [3] function, I will call [2] function to get users using Azure function url as below:-

https://hdidownload.azurewebsites.net/api/getusers

Is there any other way to call Azure function with in another Azure function without full path as above?

7 Answers

There's nothing built-in in Function Apps to call one HTTP function from other functions without actually making the HTTP call.

For simple use cases I would just stick to calling by full URL.

For more advanced workflows, have a look at Durable Functions, paticularly Function Chaining.

All the previous answers are valid but, as was also mentioned in the comments, earlier this year (Q1/Q2 2018) the concept of Durable Functions has been introduced. In short, Durable Functions:

... lets you write stateful functions in a serverless environment. The extension manages state, checkpoints, and restarts for you.

This effectively means that you can also now chain several Functions together. It manages state when it flows from Function A => B => C, if you would require this.

It works by installing the Durable Functions Extension to your Function App. With that, you have some new context bindings available where, for example in C#, you can do something like (pseudo code):

[FunctionName("ExpensiveDurableSequence")]
public static async Task<List<string>> Run(
    [OrchestrationTrigger] DurableOrchestrationTrigger context)
{
    var response = new List<Order>();

    // Call external function 1 
    var token = await context.CallActivityAsync<string>("GetDbToken", "i-am-root");

    // Call external function 2
    response.Add(await context.CallActivityAsync<IEnumerable<Order>>("GetOrdersFromDb", token));

    return response;
}

[FunctionName("GetDbToken")]
public static string GetDbToken([ActivityTrigger] string username)
{
    // do expensive remote api magic here
    return token;
}

[FunctionaName("GetOrdersFromDb")]
public static IEnumerable<Order> GetOrdersFromDb([ActivityTrigger] string apikey)
{
    // do expensive db magic here
    return orders;
}

Some nice aspects here are:

  • The main sequence chains up two additional functions that are run after one another
  • When an external function is executed, the main sequence is put to sleep; this means that you won't be billed twice once an external function is busy processing

This allows you to both run multiple functions in sequence of each other (e.g. function chaining), or execute multiple functions in parallel and wait for them all to finish (fan-out/fan-in).

Some additional background reference on this:

I know we have Durable Functions but I call my functions like a normal static method and it works, here an example :

public static class HelloWorld
{
    [FunctionName("HelloWorld")]
    public static string Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, ILogger log)
    {
        return "Hello World";
    }

}

public static class HelloWorldCall
{
    [FunctionName("HelloWorldCall")]
    public static string Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, ILogger log)
    {
        var caller = HelloWorld.Run(req, log);
        return caller;
    }

}

I din't find any good sources, I did the below, it worked fine.

To call other function with its url, of below format:

https://my-functn-app-1.azurewebsites.net/some-path-here1?code=123412somecodehereemiii888ii88k123m123l123k1l23k1l3==

In Node.js, I called as below:

let request_options = {
        method: 'GET',
        host: 'my-functn-app-1.azurewebsites.net',
        path: '/path1/path2?&q1=v1&q2=v2&code=123412somecodehereemiii888ii88k123m123l123k1l23k1l3',
        headers: {
            'Content-Type': 'application/json'
        }
};
require('https')
    .request(
         request_options,
         function (res) {
               // do something here
         });

Worked with no issues.
It should work similar way for other programming languages.
Hope this helps.

Durable functions support this, however, they are currently supported only when using C#, F# or JavaScript.

Another options would be

  1. Create HTTP request for new Azure function, however, you would have to do it in a way where your function doesn't wait for response, otherwise first function in a chain would have to wait until the very last one finishes. Using Python, that would be something like:

    try:
            requests.get("http://secondAzureFunction.com/api/",timeout=0.0000000001)
    except requests.exceptions.ReadTimeout: 
            pass
    

That seems bit hacky to me though.

  1. Use Azure Storage Queues. First function passes message to a queue, which will trigger another Azure function. That seems more elegant solution. As Fabio writes here:

This keeps your functions small, fast and decoupled, while taking advantage of all the logic in place for provisioning, scaling and fault handling.

You can't call one function app to another function app (i.e Http trigger to another http trigger without full URL)

the same we can achieve in different way of coding

[FunctionName("CreateUser")]
    public Task<IActionResult> CreateUser([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", "put", Route = "{apiName}")] HttpRequest req, ILogger log, string apiName)
    {
        log.LogInformation("Requested API => " + apiName);
        CreateUser();
        // Based on condition you can call the internal methods 
        return Task.FromResult(" CreateUser-response");
    }
    [FunctionName("FetchUser")]
    public Task<IActionResult> FetchUser([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", "put", Route = "{apiName}")] HttpRequest req, ILogger log, string apiName)
    {
        log.LogInformation("Requested API => " + apiName);
        FetchUser();
        // Based on condition you can call the internal methods 
        return Task.FromResult("FetchUser-response");
    }
    [FunctionName("ProcessUser")]
    public Task<IActionResult> ProcessUser([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", "put", Route = "{apiName}")] HttpRequest req, ILogger log, string apiName)
    {
        log.LogInformation("Requested API => " + apiName);
        ProcessUser();
        // Based on condition you can call the internal methods 
        return Task.FromResult("FetchUser-response");
    }
    private void CreateUser()
    {
        // Create User Logic
    }
    private void FetchUser()
    {
        // Fetch User Logic
    }
    private void ProcessUser()
    {
        // Process User Logic
    }
Related