Azure Functions Custom Handlers

What are Custom Handlers?

Azure Functions custom handlers enable you to use any programming language or framework that can run as an HTTP server for your serverless workloads. This provides maximum flexibility, allowing you to leverage existing codebases or choose your preferred development environment without being limited to the languages officially supported by Azure Functions.

When you use a custom handler, Azure Functions invokes your HTTP server directly. Your server is responsible for parsing the request, executing the function logic, and returning a response.

How it Works

Getting Started

To use a custom handler, you need to configure your function app to point to your custom handler executable and specify the port it should listen on.

Configuration

In your host.json file, you define the customHandlers property:


{
  "version": "2.0",
  "customHandlers": {
    "defaultExecutablePath": "your_executable_path",
    "arguments": [
      "--port",
      "8080"
    ],
    "supportedWorkers": [
      {
        "workerName": "node",
        "defaultExecutablePath": "node",
        "arguments": [
          "index.js"
        ]
      }
    ]
  }
}
            

Alternatively, you can specify the configuration within the function.json file of each individual function.

Example: Node.js Custom Handler

Let's say you have a simple Node.js HTTP server that handles incoming requests. You would configure it to listen on a specific port provided by the Functions runtime.

server.js


const http = require('http');

const port = process.env.FUNCTION_PORT || 8080;

const server = http.createServer((req, res) => {
  console.log(`Received request: ${req.method} ${req.url}`);

  let body = '';
  req.on('data', chunk => {
    body += chunk.toString();
  });
  req.on('end', () => {
    res.writeHead(200, { 'Content-Type': 'application/json' });
    res.end(JSON.stringify({
      message: 'Hello from custom handler!',
      method: req.method,
      url: req.url,
      body: body ? JSON.parse(body) : {}
    }));
  });
});

server.listen(port, () => {
  console.log(`Custom handler server listening on port ${port}`);
});
            

And your host.json might look like this:


{
  "version": "2.0",
  "customHandlers": {
    "defaultExecutablePath": "node",
    "arguments": [
      "server.js"
    ]
  }
}
            

Important: The Azure Functions runtime injects the port your custom handler should listen on via the FUNCTION_PORT environment variable. Always use this variable to ensure your handler communicates correctly with the runtime.

Request and Response Format

The Azure Functions runtime sends HTTP requests to your custom handler in a specific format. Your handler should respond with a JSON payload that includes the HTTP status code, headers, and body.

Request Payload Example


{
  "Data": {
    "Method": "POST",
    "Url": "/api/my-custom-function",
    "Headers": {
      "Content-Type": "application/json",
      "User-Agent": "Azure Functions"
    },
    "Body": "{\"name\": \"Azure\"}"
  },
  "Metadata": {
    "FunctionName": "my-custom-function"
  }
}
            

Response Payload Example


{
  "Outputs": {
    "response": {
      "StatusCode": 200,
      "Headers": {
        "Content-Type": "application/json"
      },
      "Body": "{\"greeting\": \"Hello, Azure!\"}"
    }
  }
}
            

Supported Languages and Frameworks

Custom handlers are highly versatile. You can use them with:

Best Practices

Custom handlers provide a powerful way to extend Azure Functions, enabling you to build sophisticated serverless applications using the tools and languages you know best.

^