title | description | author | ms.topic | ms.date | ms.author | ms.custom |
---|---|---|---|---|---|---|
Azure Functions HTTP trigger |
Learn how to call an Azure Function via HTTP. |
craigshoemaker |
reference |
02/21/2020 |
cshoe |
devx-track-csharp, devx-track-python |
The HTTP trigger lets you invoke a function with an HTTP request. You can use an HTTP trigger to build serverless APIs and respond to webhooks.
The default return value for an HTTP-triggered function is:
HTTP 204 No Content
with an empty body in Functions 2.x and higherHTTP 200 OK
with an empty body in Functions 1.x
To modify the HTTP response, configure an output binding.
For more information about HTTP bindings, see the overview and output binding reference.
[!INCLUDE HTTP client best practices]
The following example shows a C# function that looks for a name
parameter either in the query string or the body of the HTTP request. Notice that the return value is used for the output binding, but a return value attribute isn't required.
[FunctionName("HttpTriggerCSharp")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]
HttpRequest req, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
The following example shows a trigger binding in a function.json file and a C# script function that uses the binding. The function looks for a name
parameter either in the query string or the body of the HTTP request.
Here's the function.json file:
{
"disabled": false,
"bindings": [
{
"authLevel": "function",
"name": "req",
"type": "httpTrigger",
"direction": "in",
"methods": [
"get",
"post"
]
},
{
"name": "$return",
"type": "http",
"direction": "out"
}
]
}
The configuration section explains these properties.
Here's C# script code that binds to HttpRequest
:
#r "Newtonsoft.Json"
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
You can bind to a custom object instead of HttpRequest
. This object is created from the body of the request and parsed as JSON. Similarly, a type can be passed to the HTTP response output binding and returned as the response body, along with a 200
status code.
using System.Net;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
public static string Run(Person person, ILogger log)
{
return person.Name != null
? (ActionResult)new OkObjectResult($"Hello, {person.Name}")
: new BadRequestObjectResult("Please pass an instance of Person.");
}
public class Person {
public string Name {get; set;}
}
- Read parameter from the query string
- Read body from a POST request
- Read parameter from a route
- Read POJO body from a POST request
The following examples show the HTTP trigger binding.
This example reads a parameter, named id
, from the query string, and uses it to build a JSON document returned to the client, with content type application/json
.
@FunctionName("TriggerStringGet")
public HttpResponseMessage run(
@HttpTrigger(name = "req",
methods = {HttpMethod.GET},
authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<Optional<String>> request,
final ExecutionContext context) {
// Item list
context.getLogger().info("GET parameters are: " + request.getQueryParameters());
// Get named parameter
String id = request.getQueryParameters().getOrDefault("id", "");
// Convert and display
if (id.isEmpty()) {
return request.createResponseBuilder(HttpStatus.BAD_REQUEST)
.body("Document not found.")
.build();
}
else {
// return JSON from to the client
// Generate document
final String name = "fake_name";
final String jsonDocument = "{\"id\":\"" + id + "\", " +
"\"description\": \"" + name + "\"}";
return request.createResponseBuilder(HttpStatus.OK)
.header("Content-Type", "application/json")
.body(jsonDocument)
.build();
}
}
This example reads the body of a POST request, as a String
, and uses it to build a JSON document returned to the client, with content type application/json
.
@FunctionName("TriggerStringPost")
public HttpResponseMessage run(
@HttpTrigger(name = "req",
methods = {HttpMethod.POST},
authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<Optional<String>> request,
final ExecutionContext context) {
// Item list
context.getLogger().info("Request body is: " + request.getBody().orElse(""));
// Check request body
if (!request.getBody().isPresent()) {
return request.createResponseBuilder(HttpStatus.BAD_REQUEST)
.body("Document not found.")
.build();
}
else {
// return JSON from to the client
// Generate document
final String body = request.getBody().get();
final String jsonDocument = "{\"id\":\"123456\", " +
"\"description\": \"" + body + "\"}";
return request.createResponseBuilder(HttpStatus.OK)
.header("Content-Type", "application/json")
.body(jsonDocument)
.build();
}
}
This example reads a mandatory parameter, named id
, and an optional parameter name
from the route path, and uses them to build a JSON document returned to the client, with content type application/json
. T
@FunctionName("TriggerStringRoute")
public HttpResponseMessage run(
@HttpTrigger(name = "req",
methods = {HttpMethod.GET},
authLevel = AuthorizationLevel.ANONYMOUS,
route = "trigger/{id}/{name=EMPTY}") // name is optional and defaults to EMPTY
HttpRequestMessage<Optional<String>> request,
@BindingName("id") String id,
@BindingName("name") String name,
final ExecutionContext context) {
// Item list
context.getLogger().info("Route parameters are: " + id);
// Convert and display
if (id == null) {
return request.createResponseBuilder(HttpStatus.BAD_REQUEST)
.body("Document not found.")
.build();
}
else {
// return JSON from to the client
// Generate document
final String jsonDocument = "{\"id\":\"" + id + "\", " +
"\"description\": \"" + name + "\"}";
return request.createResponseBuilder(HttpStatus.OK)
.header("Content-Type", "application/json")
.body(jsonDocument)
.build();
}
}
Here is the code for the ToDoItem
class, referenced in this example:
public class ToDoItem {
private String id;
private String description;
public ToDoItem(String id, String description) {
this.id = id;
this.description = description;
}
public String getId() {
return id;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return "ToDoItem={id=" + id + ",description=" + description + "}";
}
}
This example reads the body of a POST request. The request body gets automatically de-serialized into a ToDoItem
object, and is returned to the client, with content type application/json
. The ToDoItem
parameter is serialized by the Functions runtime as it is assigned to the body
property of the HttpMessageResponse.Builder
class.
@FunctionName("TriggerPojoPost")
public HttpResponseMessage run(
@HttpTrigger(name = "req",
methods = {HttpMethod.POST},
authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<Optional<ToDoItem>> request,
final ExecutionContext context) {
// Item list
context.getLogger().info("Request body is: " + request.getBody().orElse(null));
// Check request body
if (!request.getBody().isPresent()) {
return request.createResponseBuilder(HttpStatus.BAD_REQUEST)
.body("Document not found.")
.build();
}
else {
// return JSON from to the client
// Generate document
final ToDoItem body = request.getBody().get();
return request.createResponseBuilder(HttpStatus.OK)
.header("Content-Type", "application/json")
.body(body)
.build();
}
}
The following example shows a trigger binding in a function.json file and a JavaScript function that uses the binding. The function looks for a name
parameter either in the query string or the body of the HTTP request.
Here's the function.json file:
{
"disabled": false,
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req"
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
The configuration section explains these properties.
Here's the JavaScript code:
module.exports = function(context, req) {
context.log('Node.js HTTP trigger function processed a request. RequestUri=%s', req.originalUrl);
if (req.query.name || (req.body && req.body.name)) {
context.res = {
// status defaults to 200 */
body: "Hello " + (req.query.name || req.body.name)
};
}
else {
context.res = {
status: 400,
body: "Please pass a name on the query string or in the request body"
};
}
context.done();
};
The following example shows a trigger binding in a function.json file and a PowerShell function. The function looks for a name
parameter either in the query string or the body of the HTTP request.
{
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "Request",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "Response"
}
]
}
using namespace System.Net
# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)
# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."
# Interact with query parameters or the body of the request.
$name = $Request.Query.Name
if (-not $name) {
$name = $Request.Body.Name
}
$body = "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response."
if ($name) {
$body = "Hello, $name. This HTTP triggered function executed successfully."
}
# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
Body = $body
})
The following example shows a trigger binding in a function.json file and a Python function that uses the binding. The function looks for a name
parameter either in the query string or the body of the HTTP request.
Here's the function.json file:
{
"scriptFile": "__init__.py",
"disabled": false,
"bindings": [
{
"authLevel": "function",
"type": "httpTrigger",
"direction": "in",
"name": "req"
},
{
"type": "http",
"direction": "out",
"name": "res"
}
]
}
The configuration section explains these properties.
Here's the Python code:
import logging
import azure.functions as func
def main(req: func.HttpRequest) -> func.HttpResponse:
logging.info('Python HTTP trigger function processed a request.')
name = req.params.get('name')
if not name:
try:
req_body = req.get_json()
except ValueError:
pass
else:
name = req_body.get('name')
if name:
return func.HttpResponse(f"Hello {name}!")
else:
return func.HttpResponse(
"Please pass a name on the query string or in the request body",
status_code=400
)
In C# class libraries and Java, the HttpTrigger
attribute is available to configure the function.
You can set the authorization level and allowable HTTP methods in attribute constructor parameters, webhook type, and a route template. For more information about these settings, see configuration.
This example demonstrates how to use the HttpTrigger attribute.
[FunctionName("HttpTriggerCSharp")]
public static Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest req)
{
...
}
For a complete example, see the trigger example.
Attributes are not supported by C# Script.
This example demonstrates how to use the HttpTrigger attribute.
@FunctionName("HttpTriggerJava")
public HttpResponseMessage<String> HttpTrigger(
@HttpTrigger(name = "req",
methods = {"get"},
authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<String> request,
final ExecutionContext context) {
...
}
For a complete example, see the trigger example.
Attributes are not supported by JavaScript.
Attributes are not supported by PowerShell.
Attributes are not supported by Python.
The following table explains the binding configuration properties that you set in the function.json file and the HttpTrigger
attribute.
function.json property | Attribute property | Description |
---|---|---|
type | n/a | Required - must be set to httpTrigger . |
direction | n/a | Required - must be set to in . |
name | n/a | Required - the variable name used in function code for the request or request body. |
authLevel | AuthLevel | Determines what keys, if any, need to be present on the request in order to invoke the function. The authorization level can be one of the following values:
|
methods | Methods | An array of the HTTP methods to which the function responds. If not specified, the function responds to all HTTP methods. See customize the HTTP endpoint. |
route | Route | Defines the route template, controlling to which request URLs your function responds. The default value if none is provided is <functionname> . For more information, see customize the HTTP endpoint. |
webHookType | WebHookType | Supported only for the version 1.x runtime. Configures the HTTP trigger to act as a webhook receiver for the specified provider. Don't set the methods property if you set this property. The webhook type can be one of the following values:
|
The trigger input type is declared as either HttpRequest
or a custom type. If you choose HttpRequest
, you get full access to the request object. For a custom type, the runtime tries to parse the JSON request body to set the object properties.
By default when you create a function for an HTTP trigger, the function is addressable with a route of the form:
http://<APP_NAME>.azurewebsites.net/api/<FUNCTION_NAME>
You can customize this route using the optional route
property on the HTTP trigger's input binding. As an example, the following function.json file defines a route
property for an HTTP trigger:
{
"bindings": [
{
"type": "httpTrigger",
"name": "req",
"direction": "in",
"methods": [ "get" ],
"route": "products/{category:alpha}/{id:int?}"
},
{
"type": "http",
"name": "res",
"direction": "out"
}
]
}
Using this configuration, the function is now addressable with the following route instead of the original route.
http://<APP_NAME>.azurewebsites.net/api/products/electronics/357
This configuration allows the function code to support two parameters in the address, category and id.
You can use any Web API Route Constraint with your parameters. The following C# function code makes use of both parameters.
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
public static IActionResult Run(HttpRequest req, string category, int? id, ILogger log)
{
var message = String.Format($"Category: {category}, ID: {id}");
return (ActionResult)new OkObjectResult(message);
}
You can use any Web API Route Constraint with your parameters. The following C# function code makes use of both parameters.
#r "Newtonsoft.Json"
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
public static IActionResult Run(HttpRequest req, string category, int? id, ILogger log)
{
var message = String.Format($"Category: {category}, ID: {id}");
return (ActionResult)new OkObjectResult(message);
}
The function execution context is properties as declared in the HttpTrigger
attribute. The attribute allows you to define route parameters, authorization levels, HTTP verbs and the incoming request instance.
Route parameters are defined via the HttpTrigger
attribute.
package com.function;
import java.util.*;
import com.microsoft.azure.functions.annotation.*;
import com.microsoft.azure.functions.*;
public class HttpTriggerJava {
public HttpResponseMessage<String> HttpTrigger(
@HttpTrigger(name = "req",
methods = {"get"},
authLevel = AuthorizationLevel.FUNCTION,
route = "products/{category:alpha}/{id:int}") HttpRequestMessage<String> request,
@BindingName("category") String category,
@BindingName("id") int id,
final ExecutionContext context) {
String message = String.format("Category %s, ID: %d", category, id);
return request.createResponseBuilder(HttpStatus.OK).body(message).build();
}
}
In Node, the Functions runtime provides the request body from the context
object. For more information, see the JavaScript trigger example.
The following example shows how to read route parameters from context.bindingData
.
module.exports = function (context, req) {
var category = context.bindingData.category;
var id = context.bindingData.id;
var message = `Category: ${category}, ID: ${id}`;
context.res = {
body: message;
}
context.done();
}
Route parameters declared in the function.json file are accessible as a property of the $Request.Params
object.
$Category = $Request.Params.category
$Id = $Request.Params.id
$Message = "Category:" + $Category + ", ID: " + $Id
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
Body = $Message
})
The function execution context is exposed via a parameter declared as func.HttpRequest
. This instance allows a function to access data route parameters, query string values and methods that allow you to return HTTP responses.
Once defined, the route parameters are available to the function by calling the route_params
method.
import logging
import azure.functions as func
def main(req: func.HttpRequest) -> func.HttpResponse:
category = req.route_params.get('category')
id = req.route_params.get('id')
message = f"Category: {category}, ID: {id}"
return func.HttpResponse(message)
By default, all function routes are prefixed with api. You can also customize or remove the prefix using the extensions.http.routePrefix
property in your host.json file. The following example removes the api route prefix by using an empty string for the prefix in the host.json file.
{
"extensions": {
"http": {
"routePrefix": ""
}
}
}
Route parameters that defined a function's route
pattern are available to each binding. For example, if you have a route defined as "route": "products/{id}"
then a table storage binding can use the value of the {id}
parameter in the binding configuration.
The following configuration shows how the {id}
parameter is passed to the binding's rowKey
.
{
"type": "table",
"direction": "in",
"name": "product",
"partitionKey": "products",
"tableName": "products",
"rowKey": "{id}"
}
If your function app is using App Service Authentication / Authorization, you can view information about authenticated clients from your code. This information is available as request headers injected by the platform.
You can also read this information from binding data. This capability is only available to the Functions runtime in 2.x and higher. It is also currently only available for .NET languages.
Information regarding authenticated clients is available as a ClaimsPrincipal. The ClaimsPrincipal is available as part of the request context as shown in the following example:
using System.Net;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
public static IActionResult Run(HttpRequest req, ILogger log)
{
ClaimsPrincipal identities = req.HttpContext.User;
// ...
return new OkObjectResult();
}
Alternatively, the ClaimsPrincipal can simply be included as an additional parameter in the function signature:
using System.Net;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
using Newtonsoft.Json.Linq;
public static void Run(JObject input, ClaimsPrincipal principal, ILogger log)
{
// ...
return;
}
Information regarding authenticated clients is available as a ClaimsPrincipal. The ClaimsPrincipal is available as part of the request context as shown in the following example:
using System.Net;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
public static IActionResult Run(HttpRequest req, ILogger log)
{
ClaimsPrincipal identities = req.HttpContext.User;
// ...
return new OkObjectResult();
}
Alternatively, the ClaimsPrincipal can simply be included as an additional parameter in the function signature:
#r "Newtonsoft.Json"
using System.Net;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;
using Newtonsoft.Json.Linq;
public static void Run(JObject input, ClaimsPrincipal principal, ILogger log)
{
// ...
return;
}
The authenticated user is available via HTTP Headers.
The authenticated user is available via HTTP Headers.
The authenticated user is available via HTTP Headers.
The authenticated user is available via HTTP Headers.
[!INCLUDE functions-authorization-keys]
Keys are stored as part of your function app in Azure and are encrypted at rest. To view your keys, create new ones, or roll keys to new values, navigate to one of your HTTP-triggered functions in the Azure portal and select Manage.
You may obtain function keys programmatically by using Key management APIs.
Most HTTP trigger templates require an API key in the request. So your HTTP request normally looks like the following URL:
https://<APP_NAME>.azurewebsites.net/api/<FUNCTION_NAME>?code=<API_KEY>
The key can be included in a query string variable named code
, as above. It can also be included in an x-functions-key
HTTP header. The value of the key can be any function key defined for the function, or any host key.
You can allow anonymous requests, which do not require keys. You can also require that the master key is used. You change the default authorization level by using the authLevel
property in the binding JSON. For more information, see Trigger - configuration.
Note
When running functions locally, authorization is disabled regardless of the specified authorization level setting. After publishing to Azure, the authLevel
setting in your trigger is enforced. Keys are still required when running locally in a container.
To fully secure your function endpoints in production, you should consider implementing one of the following function app-level security options. When using one of these function app-level security methods, you should set the HTTP-triggered function authorization level to anonymous
.
[!INCLUDE functions-enable-auth]
[!INCLUDE functions-deploy-isolation]
Note
Webhook mode is only available for version 1.x of the Functions runtime. This change was made to improve the performance of HTTP triggers in version 2.x and higher.
In version 1.x, webhook templates provide additional validation for webhook payloads. In version 2.x and higher, the base HTTP trigger still works and is the recommended approach for webhooks.
To respond to GitHub webhooks, first create your function with an HTTP Trigger, and set the webHookType property to github
. Then copy its URL and API key into the Add webhook page of your GitHub repository.
The Slack webhook generates a token for you instead of letting you specify it, so you must configure a function-specific key with the token from Slack. See Authorization keys.
Webhook authorization is handled by the webhook receiver component, part of the HTTP trigger, and the mechanism varies based on the webhook type. Each mechanism does rely on a key. By default, the function key named "default" is used. To use a different key, configure the webhook provider to send the key name with the request in one of the following ways:
- Query string: The provider passes the key name in the
clientid
query string parameter, such ashttps://<APP_NAME>.azurewebsites.net/api/<FUNCTION_NAME>?clientid=<KEY_NAME>
. - Request header: The provider passes the key name in the
x-functions-clientid
header.
Passing binary and form data to a non-C# function requires that you use the appropriate content-type header. Supported content types include octet-stream
for binary data and multipart types.
In non-C# functions, requests sent with the content-type image/jpeg
results in a string
value passed to the function. In cases like these, you can manually convert the string
value to a byte array to access the raw binary data.
The HTTP request length is limited to 100 MB (104,857,600 bytes), and the URL length is limited to 4 KB (4,096 bytes). These limits are specified by the httpRuntime
element of the runtime's Web.config file.
If a function that uses the HTTP trigger doesn't complete within 230 seconds, the Azure Load Balancer will time out and return an HTTP 502 error. The function will continue running but will be unable to return an HTTP response. For long-running functions, we recommend that you follow async patterns and return a location where you can ping the status of the request. For information about how long a function can run, see Scale and hosting - Consumption plan.