Azure Event Grid output binding for Azure Functions
Use the Event Grid output binding to write events to a custom topic. You must have a valid access key for the custom topic. The Event Grid output binding doesn't support shared access signature (SAS) tokens.
For information on setup and configuration details, see How to work with Event Grid triggers and bindings in Azure Functions.
Important
This article uses tabs to support multiple versions of the Node.js programming model. The v4 model is currently in preview and is designed to have a more flexible and intuitive experience for JavaScript and TypeScript developers. Learn more about the differences between v3 and v4 in the upgrade guide.
Azure Functions supports two programming models for Python. The way that you define your bindings depends on your chosen programming model.
The Python v2 programming model lets you define bindings using decorators directly in your Python function code. For more information, see the Python developer guide.
This article supports both programming models.
Important
The Event Grid output binding is only available for Functions 2.x and higher.
Example
The type of the output parameter used with an Event Grid output binding depends on the Functions runtime version, the binding extension version, and the modality of the C# function. The C# function can be created using one of the following C# modes:
- In-process class library: compiled C# function that runs in the same process as the Functions runtime.
- Isolated worker process class library: compiled C# function that runs in a worker process isolated from the runtime.
The following example shows how the custom type is used in both the trigger and an Event Grid output binding:
using System;
using System.Collections.Generic;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
namespace SampleApp
{
public static class EventGridFunction
{
[Function(nameof(EventGridFunction))]
[EventGridOutput(TopicEndpointUri = "MyEventGridTopicUriSetting", TopicKeySetting = "MyEventGridTopicKeySetting")]
public static MyEventType Run([EventGridTrigger] MyEventType input, FunctionContext context)
{
var logger = context.GetLogger(nameof(EventGridFunction));
logger.LogInformation(input.Data.ToString());
var outputEvent = new MyEventType()
{
Id = "unique-id",
Subject = "abc-subject",
Data = new Dictionary<string, object>
{
{ "myKey", "myValue" }
}
};
return outputEvent;
}
}
public class MyEventType
{
public string Id { get; set; }
public string Topic { get; set; }
public string Subject { get; set; }
public string EventType { get; set; }
public DateTime EventTime { get; set; }
public IDictionary<string, object> Data { get; set; }
}
}
The following example shows a Java function that writes a message to an Event Grid custom topic. The function uses the binding's setValue
method to output a string.
public class Function {
@FunctionName("EventGridTriggerTest")
public void run(@EventGridTrigger(name = "event") String content,
@EventGridOutput(name = "outputEvent", topicEndpointUri = "MyEventGridTopicUriSetting", topicKeySetting = "MyEventGridTopicKeySetting") OutputBinding<String> outputEvent,
final ExecutionContext context) {
context.getLogger().info("Java EventGrid trigger processed a request." + content);
final String eventGridOutputDocument = "{\"id\": \"1807\", \"eventType\": \"recordInserted\", \"subject\": \"myapp/cars/java\", \"eventTime\":\"2017-08-10T21:03:07+00:00\", \"data\": {\"make\": \"Ducati\",\"model\": \"Monster\"}, \"dataVersion\": \"1.0\"}";
outputEvent.setValue(eventGridOutputDocument);
}
}
You can also use a POJO class to send Event Grid messages.
public class Function {
@FunctionName("EventGridTriggerTest")
public void run(@EventGridTrigger(name = "event") String content,
@EventGridOutput(name = "outputEvent", topicEndpointUri = "MyEventGridTopicUriSetting", topicKeySetting = "MyEventGridTopicKeySetting") OutputBinding<EventGridEvent> outputEvent,
final ExecutionContext context) {
context.getLogger().info("Java EventGrid trigger processed a request." + content);
final EventGridEvent eventGridOutputDocument = new EventGridEvent();
eventGridOutputDocument.setId("1807");
eventGridOutputDocument.setEventType("recordInserted");
eventGridOutputDocument.setEventTime("2017-08-10T21:03:07+00:00");
eventGridOutputDocument.setDataVersion("1.0");
eventGridOutputDocument.setSubject("myapp/cars/java");
eventGridOutputDocument.setData("{\"make\": \"Ducati\",\"model\":\"monster\"");
outputEvent.setValue(eventGridOutputDocument);
}
}
class EventGridEvent {
private String id;
private String eventType;
private String subject;
private String eventTime;
private String dataVersion;
private String data;
public String getId() {
return id;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public String getDataVersion() {
return dataVersion;
}
public void setDataVersion(String dataVersion) {
this.dataVersion = dataVersion;
}
public String getEventTime() {
return eventTime;
}
public void setEventTime(String eventTime) {
this.eventTime = eventTime;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getEventType() {
return eventType;
}
public void setEventType(String eventType) {
this.eventType = eventType;
}
public void setId(String id) {
this.id = id;
}
}
The following example shows a timer triggered TypeScript function that outputs a single event:
import { app, EventGridPartialEvent, InvocationContext, output, Timer } from '@azure/functions';
export async function timerTrigger1(myTimer: Timer, context: InvocationContext): Promise<EventGridPartialEvent> {
const timeStamp = new Date().toISOString();
return {
id: 'message-id',
subject: 'subject-name',
dataVersion: '1.0',
eventType: 'event-type',
data: {
name: 'John Henry',
},
eventTime: timeStamp,
};
}
app.timer('timerTrigger1', {
schedule: '0 */5 * * * *',
return: output.eventGrid({
topicEndpointUri: 'MyEventGridTopicUriSetting',
topicKeySetting: 'MyEventGridTopicKeySetting',
}),
handler: timerTrigger1,
});
To output multiple events, return an array instead of a single object. For example:
import { app, EventGridPartialEvent, InvocationContext, output, Timer } from '@azure/functions';
export async function timerTrigger1(myTimer: Timer, context: InvocationContext): Promise<EventGridPartialEvent[]> {
// <displayInDocs>
const timeStamp = new Date().toISOString();
return [
{
id: 'message-id',
subject: 'subject-name',
dataVersion: '1.0',
eventType: 'event-type',
data: {
name: 'John Henry',
},
eventTime: timeStamp,
},
{
id: 'message-id-2',
subject: 'subject-name',
dataVersion: '1.0',
eventType: 'event-type',
data: {
name: 'John Doe',
},
eventTime: timeStamp,
},
];
// </displayInDocs>
}
app.timer('timerTrigger1', {
schedule: '0 */5 * * * *',
return: output.eventGrid({
topicEndpointUri: 'MyEventGridTopicUriSetting',
topicKeySetting: 'MyEventGridTopicKeySetting',
}),
handler: timerTrigger1,
});
The following example shows a timer triggered JavaScript function that outputs a single event:
const { app, output } = require('@azure/functions');
const eventGridOutput = output.eventGrid({
topicEndpointUri: 'MyEventGridTopicUriSetting',
topicKeySetting: 'MyEventGridTopicKeySetting',
});
app.timer('timerTrigger1', {
schedule: '0 */5 * * * *',
return: eventGridOutput,
handler: (myTimer, context) => {
const timeStamp = new Date().toISOString();
return {
id: 'message-id',
subject: 'subject-name',
dataVersion: '1.0',
eventType: 'event-type',
data: {
name: 'John Henry',
},
eventTime: timeStamp,
};
},
});
To output multiple events, return an array instead of a single object. For example:
const { app, output } = require('@azure/functions');
const eventGridOutput = output.eventGrid({
topicEndpointUri: 'MyEventGridTopicUriSetting',
topicKeySetting: 'MyEventGridTopicKeySetting',
});
app.timer('timerTrigger1', {
schedule: '0 */5 * * * *',
return: eventGridOutput,
handler: (myTimer, context) => {
// <displayInDocs>
const timeStamp = new Date().toISOString();
return [
{
id: 'message-id',
subject: 'subject-name',
dataVersion: '1.0',
eventType: 'event-type',
data: {
name: 'John Henry',
},
eventTime: timeStamp,
},
{
id: 'message-id-2',
subject: 'subject-name',
dataVersion: '1.0',
eventType: 'event-type',
data: {
name: 'John Doe',
},
eventTime: timeStamp,
},
];
// </displayInDocs>
},
});
The following example demonstrates how to configure a function to output an Event Grid event message. The section where type
is set to eventGrid
configures the values needed to establish an Event Grid output binding.
{
"bindings": [
{
"type": "eventGrid",
"name": "outputEvent",
"topicEndpointUri": "MyEventGridTopicUriSetting",
"topicKeySetting": "MyEventGridTopicKeySetting",
"direction": "out"
},
{
"authLevel": "anonymous",
"type": "httpTrigger",
"direction": "in",
"name": "Request",
"methods": [
"get",
"post"
]
},
{
"type": "http",
"direction": "out",
"name": "Response"
}
]
}
In your function, use the Push-OutputBinding
to send an event to a custom topic through the Event Grid output binding.
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.
$message = $Request.Query.Message
Push-OutputBinding -Name outputEvent -Value @{
id = "1"
eventType = "testEvent"
subject = "testapp/testPublish"
eventTime = "2020-08-27T21:03:07+00:00"
data = @{
Message = $message
}
dataVersion = "1.0"
}
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = 200
Body = "OK"
})
The following example shows a trigger binding and a Python function that uses the binding. It then sends in an event to the custom topic, as specified by the topicEndpointUri
. The example depends on whether you use the v1 or v2 Python programming model.
Here's the function in the function_app.py file:
import logging
import azure.functions as func
import datetime
app = func.FunctionApp()
@app.function_name(name="eventgrid_output")
@app.event_grid_trigger(arg_name="eventGridEvent")
@app.event_grid_output(
arg_name="outputEvent",
topic_endpoint_uri="MyEventGridTopicUriSetting",
topic_key_setting="MyEventGridTopicKeySetting")
def eventgrid_output(eventGridEvent: func.EventGridEvent,
outputEvent: func.Out[func.EventGridOutputEvent]) -> None:
logging.log("eventGridEvent: ", eventGridEvent)
outputEvent.set(
func.EventGridOutputEvent(
id="test-id",
data={"tag1": "value1", "tag2": "value2"},
subject="test-subject",
event_type="test-event-1",
event_time=datetime.datetime.utcnow(),
data_version="1.0"))
Attributes
Both in-process and isolated worker process C# libraries use attribute to configure the binding. C# script instead uses a function.json configuration file as described in the C# scripting guide.
The attribute's constructor takes the name of an application setting that contains the name of the custom topic, and the name of an application setting that contains the topic key.
The following table explains the parameters for the EventGridOutputAttribute
.
Parameter | Description |
---|---|
TopicEndpointUri | The name of an app setting that contains the URI for the custom topic, such as MyTopicEndpointUri . |
TopicKeySetting | The name of an app setting that contains an access key for the custom topic. |
connection* | The value of the common prefix for the setting that contains the topic endpoint URI. For more information about the naming format of this application setting, see Identity-based authentication. |
Annotations
For Java classes, use the EventGridAttribute attribute.
The attribute's constructor takes the name of an app setting that contains the name of the custom topic, and the name of an app setting that contains the topic key. For more information about these settings, see Output - configuration. Here's an EventGridOutput
attribute example:
public class Function {
@FunctionName("EventGridTriggerTest")
public void run(@EventGridTrigger(name = "event") String content,
@EventGridOutput(name = "outputEvent", topicEndpointUri = "MyEventGridTopicUriSetting", topicKeySetting = "MyEventGridTopicKeySetting") OutputBinding<String> outputEvent, final ExecutionContext context) {
...
}
}
Configuration
The following table explains the properties that you can set on the options
object passed to the output.eventGrid()
method.
Property | Description |
---|---|
topicEndpointUri | The name of an app setting that contains the URI for the custom topic, such as MyTopicEndpointUri . |
topicKeySetting | The name of an app setting that contains an access key for the custom topic. |
connection* | The value of the common prefix for the setting that contains the topic endpoint URI. When setting the connection property, the topicEndpointUri and topicKeySetting properties shouldn't be set. For more information about the naming format of this application setting, see Identity-based authentication. |
Configuration
The following table explains the binding configuration properties that you set in the function.json file.
function.json property | Description |
---|---|
type | Must be set to eventGrid . |
direction | Must be set to out . This parameter is set automatically when you create the binding in the Azure portal. |
name | The variable name used in function code that represents the event. |
topicEndpointUri | The name of an app setting that contains the URI for the custom topic, such as MyTopicEndpointUri . |
topicKeySetting | The name of an app setting that contains an access key for the custom topic. |
connection* | The value of the common prefix for the setting that contains the topic endpoint URI. For more information about the naming format of this application setting, see Identity-based authentication. |
*Support for identity-based connections requires version 3.3.x or higher of the extension.
When you're developing locally, add your application settings in the local.settings.json file in the Values
collection.
Important
Make sure that you set the value of TopicEndpointUri
to the name of an app setting that contains the URI of the custom topic. Don't specify the URI of the custom topic directly in this property. The same applies when using Connection
.
See the Example section for complete examples.
Usage
The parameter type supported by the Event Grid output binding depends on the Functions runtime version, the extension package version, and the C# modality used.
When you want the function to write a single event, the Event Grid output binding can bind to the following types:
Type | Description |
---|---|
string |
The event as a string. |
byte[] |
The bytes of the event message. |
JSON serializable types | An object representing a JSON event. Functions tries to serialize a plain-old CLR object (POCO) type into JSON data. |
When you want the function to write multiple events, the Event Grid output binding can bind to the following types:
Type | Description |
---|---|
T[] where T is one of the single event types |
An array containing multiple events. Each entry represents one event. |
For other output scenarios, create and use types from Azure.Messaging.EventGrid directly.
Send individual messages by calling a method parameter such as out EventGridOutput paramName
, and write multiple messages with ICollector<EventGridOutput>
.
Access the output event by using the Push-OutputBinding
cmdlet to send an event to the Event Grid output binding.
There are two options for outputting an Event Grid message from a function:
- Return value: Set the
name
property in function.json to$return
. With this configuration, the function's return value is persisted as an Event Grid message. - Imperative: Pass a value to the set method of the parameter declared as an Out type. The value passed to
set
is persisted as an Event Grid message.
Connections
There are two ways of authenticating to an Event Grid topic when using the Event Grid output binding:
Authentication method | Description |
---|---|
Using a topic key | Set the TopicEndpointUri and TopicKeySetting properties, as described in Use a topic key. |
Using an identity | Set the Connection property to the name of a shared prefix for multiple application settings, together defining identity-based authentication. This method is supported when using version 3.3.x or higher of the extension. |
Use a topic key
Use the following steps to configure a topic key:
Follow the steps in Get access keys to obtain the topic key for your Event Grid topic.
In your application settings, create a setting that defines the topic key value. Use the name of this setting for the
TopicKeySetting
property of the binding.In your application settings, create a setting that defines the topic endpoint. Use the name of this setting for the
TopicEndpointUri
property of the binding.
Identity-based authentication
When using version 3.3.x or higher of the extension, you can connect to an Event Grid topic using an Microsoft Entra identity to avoid having to obtain and work with topic keys.
You need to create an application setting that returns the topic endpoint URI. The name of the setting should combine a unique common prefix (for example, myawesometopic
) with the value __topicEndpointUri
. Then, you must use that common prefix (in this case, myawesometopic
) when you define the Connection
property in the binding.
In this mode, the extension requires the following properties:
Property | Environment variable template | Description | Example value |
---|---|---|---|
Topic Endpoint URI | <CONNECTION_NAME_PREFIX>__topicEndpointUri |
The topic endpoint. | https://<topic-name>.centralus-1.eventgrid.chinacloudapi.cn/api/events |
More properties can be used to customize the connection. See Common properties for identity-based connections.
Note
When using Azure App Configuration or Key Vault to provide settings for managed identity-based connections, setting names should use a valid key separator such as :
or /
in place of the __
to ensure names are resolved correctly.
For example, <CONNECTION_NAME_PREFIX>:topicEndpointUri
.
When hosted in the Azure Functions service, identity-based connections use a managed identity. The system-assigned identity is used by default, although a user-assigned identity can be specified with the credential
and clientID
properties. Note that configuring a user-assigned identity with a resource ID is not supported. When run in other contexts, such as local development, your developer identity is used instead, although this can be customized. See Local development with identity-based connections.
Grant permission to the identity
Whatever identity is being used must have permissions to perform the intended actions. For most Azure services, this means you need to assign a role in Azure RBAC, using either built-in or custom roles which provide those permissions.
Important
Some permissions might be exposed by the target service that are not necessary for all contexts. Where possible, adhere to the principle of least privilege, granting the identity only required privileges. For example, if the app only needs to be able to read from a data source, use a role that only has permission to read. It would be inappropriate to assign a role that also allows writing to that service, as this would be excessive permission for a read operation. Similarly, you would want to ensure the role assignment is scoped only over the resources that need to be read.
You must create a role assignment that provides access to your Event Grid topic at runtime. Management roles like Owner are not sufficient. The following table shows built-in roles that are recommended when using the Event Hubs extension in normal operation. Your application may require additional permissions based on the code you write.
Binding type | Example built-in roles |
---|---|
Output binding | EventGrid Contributor, EventGrid Data Sender |