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
- Triggering: An incoming request triggers your function.
- Invocation: Azure Functions runtime sends an HTTP request to your custom handler's server endpoint.
- Execution: Your handler receives the request, processes it, and executes your function's logic.
- Response: Your handler returns an HTTP response to the Azure Functions runtime.
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:
- Node.js: Express, Koa, Fastify, or a plain Node.js HTTP server.
- Python: Flask, Django, FastAPI, or a simple WSGI/ASGI server.
- Java: Spring Boot, Spark, or any Java web framework.
- Go: Standard library `net/http` or frameworks like Gin or Echo.
- Rust: Actix-web, Rocket, or others.
- Any language that can host an HTTP server.
Best Practices
- Keep your handler lightweight: Focus on the core function logic.
- Handle errors gracefully: Return appropriate HTTP status codes and error messages.
- Secure your endpoints: Implement necessary authentication and authorization.
- Monitor your handler: Use logging and tracing to identify issues.
- Optimize for performance: Minimize startup time and processing latency.
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.