49

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?

2

8 Answers 8

29

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.

Sign up to request clarification or add additional context in comments.

Comments

27

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:

Comments

14

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;
    }

}

6 Comments

Is there any reason why this answer shouldn't be up-voted, assuming that all the functions in the original poster's example are all in the same function app? I know this solution isn't 'durable' in that if any of the steps fail, there won't be a retry. However, if that's not a requirement, isn't this a valid solution?
+1 as a valid answer. Downsides would depend on your trigger scenarios and the degree to which your function interfaces with the trigger binding inputs to perform its work. (Might be cumbersome to 'fake'.)
But for that matter, the degree to which your 'core' business logic is abstracted from your 'trigger' scenarios is also up to you; thus 'invoking' the trigger in this scenario would be a bit of a hammer, when instead you should be sharing a dependency and invoking it (the abstraction) directly, from both Trigger Scenarios. If your current state 'requires' you to invoke the trigger, then you might consider refactoring the logic into a common abstraction.
@PoorInRichfield, I have a scenario where function is triggered by TimerTrigger(daily) and sdk gets some documents with Cosmosdb bindings (or a queue for that matter). I want also to call this function after some other has finished. If I call it as static I need to provide Cosmosdb documents myself as a parameter.
Some issues with this - any monitoring you have like app insights will not see this as a second function call - you cannot do "fire and forget" as the second function is running synchronously inside the first - any scaling required is hidden from azure as the second trigger is never fired so scale up will be limited
|
8

You can do it directly by calling the 2nd function as a normal C# static method.

But in this case you lose benefits of Azure Functions scaling and distributing (for example, based on server load your 2nd function may be called from different part of the world).

  1. Send an HTTP request to another function's public URL
  2. Put a message into an Azure Queue and let the other Azure Function process it
  3. Use Durable Functions

As for the 1st option in C# you can do it like so:

    static HttpClient client = new HttpClient();

    [FunctionName("RequestImageProcessing")]
    public static async Task RequestImageProcessing([HttpTrigger(WebHookType = "genericJson")]
        HttpRequestMessage req)
    {
            string anotherFunctionSecret = ConfigurationManager.AppSettings
                ["AnotherFunction_secret"];
            // anotherFunctionUri is another Azure Function's 
            // public URL, which should provide the secret code stored in app settings 
            // with key 'AnotherFunction_secret'
            Uri anotherFunctionUri = new Uri(req.RequestUri.AbsoluteUri.Replace(
                req.RequestUri.PathAndQuery, 
                $"/api/AnotherFunction?code={anotherFunctionSecret}"));

            var responseFromAnotherFunction = await client.GetAsync(anotherFunctionUri);
            // process the response

    }

    [FunctionName("AnotherFunction")]
    public static async Task AnotherFunction([HttpTrigger(WebHookType = "genericJson")]
    HttpRequestMessage req)
    {
        await Worker.DoWorkAsync();
    }

Also sometimes you need your first Azure Function to return HTTP response first, and then do something in the background, so this solution won't work. In this case options 2 and 3 are suitable.

3 Comments

This code probably works, but as a general principle you should avoid creating and disposing the HttpClient object for each call, but instead have a static one for the whole application. Per learn.microsoft.com/en-us/dotnet/api/…
Does AzFx keep your assembly loaded when not running, or does it load the assembly for each execution? That would make a difference when deciding whether to use static fields.
I have a doubt: if Function1 HTTP Calls Function 2, would it not Azure charge you extra because of the execution time of the function being call?
3

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.

Comments

3

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.

Comments

0

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
    }

Comments

0

Maybe this will help someone with How to create Azure function Timer Trigger that calls API endpoint

It is pretty straightforward.

using System;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.Extensions.Logging;
using RestSharp;

namespace FunctionApp1
{
   public class Function1
   {
       public const string baseurl = "https://localhost:5101/api/v1";
       public const string ApiKey = "remoteAPiKey";

       [FunctionName("TestFunction")]
       public void Run([TimerTrigger("*/5 * * * *")]TimerInfo myTimer, ILogger log)
       {
           string url = $"{baseurl}/Values";
           var client = new RestClient(url);
           var request = new RestRequest();
           request.Method = Method.Get;
           request.AddHeader("ApiKey", ApiKey);
           RestResponse response = client.Execute(request);
           log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
       }
   }
}

You can also get more details here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.