Introducing the new Azure Event Grid Client Libraries with CloudEvents v1.0 Support

Kerri Lee

Kerri

For those looking to build applications with event-based architectures, Azure Event Grid is a cloud-based service that provides reliable event delivery at a massive scale, insulating users from infrastructure concerns. The service fully manages all routing of events from any source, to any destination, for any application. Azure service events and custom events can be published directly to the service, where the events can then be filtered and sent to various recipients, such as built-in handlers or custom webhooks. These features help vastly improve serverless, ops automation, and integration work (for more information, read What can I do with Event Grid?). Included below is an image that demonstrates how Event Grid connects to various event sources and handlers.

Event Grid Functional Model

We are excited to announce the release of the new Azure Event Grid client library’s first beta for .NET, Java, JavaScript, and Python! Check out the links to learn more about how to install the package for each language.

The new client libraries simplify the process of authenticating and publishing messages. You can use the new Azure Event Grid client library to publish events to the Event Grid service in various event schemas (EventGrid, CloudEvents v1.0, or a custom schema) and to consume events that have been delivered to event handlers. This post will explore both event publishing and event consuming in more detail. Another notable difference from the previous Event Grid client library is the ability to specify a custom ObjectSerializer to use when serializing event data to/from JSON (by default, using JsonObjectSerializer).

Read on to learn more about the CloudEvents v1.0 schema, and how you can now use Event Grid to work with CloudEvents!

What is CloudEvents?

CloudEvents is a collaborative effort between numerous companies and individuals in the industry (Microsoft included) to produce a vendor-neutral specification for “describing event data in a common way”. Simply stated, the CloudEvents spec defines a set of common metadata attributes that describe the event being transferred (such as a unique identifier or the time of the event occurrence). The self-described goal of CloudEvents is “to define interoperability of event systems that allow services to produce or consume events, where the producer and consumer can be developed and deployed independently”. The common event format thus allows for easy integration of work across platforms and services and can help standardize how events are consumed.

The new Event Grid client libraries support the JSON format for CloudEvents, meaning that JSON-serialized events of the CloudEvents schema that are sent and received by the service must adhere to the given specification.

Below is an example of an Azure Blob Storage event in CloudEvents format:

{
    "specversion": "1.0",
    "type": "Microsoft.Storage.BlobCreated",  
    "source": "/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Storage/storageAccounts/{storage-account}",
    "id": "9aeb0fdf-c01e-0131-0922-9eb54906e209",
    "time": "2019-11-18T15:13:39.4589254Z",
    "subject": "blobServices/default/containers/{storage-container}/blobs/{new-file}",
    "dataschema": "#",
    "data": {
        "api": "PutBlockList",
        "clientRequestId": "4c5dd7fb-2c48-4a27-bb30-5361b5de920a",
        "requestId": "9aeb0fdf-c01e-0131-0922-9eb549000000",
        "eTag": "0x8D76C39E4407333",
        "contentType": "image/png",
        "contentLength": 30699,
        "blobType": "BlockBlob",
        "url": "https://gridtesting.blob.core.windows.net/testcontainer/{new-file}",
        "sequencer": "000000000000000000000000000099240000000000c41c18",
        "storageDiagnostics": {
            "batchId": "681fe319-3006-00a8-0022-9e7cde000000"
        }
    }
}

Now, let’s use the Azure Event Grid client library to send and receive some CloudEvents!

Prerequisites

You must have an Azure subscription and an Azure resource group with a custom Event Grid topic or domain. Follow this step-by-step tutorial to register the Event Grid resource provider and create Event Grid topics using the Azure portal. Importantly, when creating your Event Grid topic, you must set the input schema to “CloudEvents v1.0” in the “Advanced” tab. After creating your custom topic, navigate to your newly-created topic page to retrieve the topic endpoint and access key, both of which are required in order for the client library to interact with that topic.

Creating and Authenticating the Client

Once you have your access key and topic endpoint, you can create the publisher client as follows:

.NET

EventGridPublisherClient client = new EventGridPublisherClient(
    "<endpoint>",
    new AzureKeyCredential("<access-key>"));

Java

EventGridPublisherClient egClient = new EventGridPublisherClientBuilder()
    .endpoint("<endpoint>")
    .keyCredential(new AzureKeyCredential("<access-key>"))
    .buildClient();

JavaScript

const { EventGridPublisherClient, AzureKeyCredential } = require("@azure/eventgrid");

const client = new EventGridPublisherClient("<endpoint>", new AzureKeyCredential("<Access Key>"));

Python

from azure.core.credentials import AzureKeyCredential
from azure.eventgrid import EventGridPublisherClient

credential = AzureKeyCredential("<access-key>")
eg_publisher_client = EventGridPublisherClient("<endpoint>", credential)

We will be using the .NET SDK for the remainder of the article, but similar functionality is available for all libraries. Check out the samples for all languages in the Next Steps section.

Publishing CloudEvents to your Topic

The publisher sends events to the Event Grid service. Regardless of what schema your topic or domain is configured to use, EventGridPublisherClient will be used to publish events to the service. After creating the EventGridPublisherClient such that the custom topic is configured to accept events of the CloudEvents v1.0 schema, we can now create some events of the CloudEvent type to publish to the topic.

The CloudEvent type represents the event format as described by the specification. Each CloudEvent has a set of required, non-nullable properties. Notably for CloudEvents, you can include any number of extension attributes such that additional metadata can be added to the event envelope as needed.

// Add CloudEvents to a list to publish to the topic
List<CloudEvent> eventsList = new List<CloudEvent>
{
    new CloudEvent(
        "/cloudevents/example/source",    // source - identifies the context in which an event happened
        "Example.EventType",              // type - describing the type of event
        "This is the event data")         // data - the event payload
};

Following that, invoke SendEvents or SendEventsAsync to publish the events to Azure Event Grid.

await client.SendEventsAsync(eventsList);

To see the events that you’ve sent, the quickstart tutorial also includes instructions on how to subscribe to your new topic with a pre-built web app, which will display the events you sent as JSON:

Events Sent to Topic

Deserializing CloudEvents Delivered to an Event Handler

The Azure Event Grid client library can also be used to parse events from JSON to access event data. There are several different Azure services that act as event handlers. Regardless of the event handler, events are always sent as UTF-8 encoded JSON.

Once events are delivered to the event handler, you can parse the JSON payload into list of events.

CloudEvent[] cloudEvents = CloudEvent.Parse(jsonPayload);

From here, you can access the event data by deserializing to a specific type using GetData<T>() and passing in a custom serializer if necessary. Calling GetData() will either return a deserialized system event (an event generated by an Azure service), or the event data wrapped in BinaryData, which represents the serialized JSON event data as bytes.

Below is an example calling GetData<T>() for CloudEvents. The Type property for CloudEvents describes the event type related to the occurrence, which may help differentiate between events during deserialization. Custom event data should be deserialized using the generic method GetData<T>(). There is also an overload for GetData<T>() that accepts a custom ObjectSerializer to deserialize the event data.

foreach (CloudEvent cloudEvent in cloudEvents)
{
    switch (cloudEvent.Type)
    {
        case "Contoso.Items.ItemReceived":
            // By default, GetData uses JsonObjectSerializer to deserialize the payload
            ContosoItemReceivedEventData itemReceived = cloudEvent.GetData<ContosoItemReceivedEventData>();
            Console.WriteLine(itemReceived.ItemSku);
            break;
        case "MyApp.Models.CustomEventType":
            // You can also specify a custom ObjectSerializer as needed to deserialize the payload correctly
            TestPayload testPayload = await cloudEvent.GetDataAsync<TestPayload>(myCustomSerializer);
            Console.WriteLine(testPayload.Name);
            break;
        case "Microsoft.Storage.BlobDeleted":
            // Example for deserializing system events using GetData<T>
            StorageBlobDeletedEventData blobDeleted = cloudEvent.GetData<StorageBlobDeletedEventData>();
            Console.WriteLine(blobDeleted.BlobType);
            break;
    }
}

Summary

The new Azure Event Grid client library follows the Azure SDK Design guidelines, bringing about SDKs that are approachable, consistent, and idiomatic for their target languages. As a result, the process of publishing and consuming events should be straightforward for both new and experienced users. Finally, the new support for CloudEvents v1.0 relies less on service specifics, allowing for greater interoperability.

A big shout out to the other 2020 summer interns Soren Dahl and Swathi Pillalamarri who worked on getting these libraries shipped for Java and Python! You guys are amazing!!

Next Steps

Azure SDK Blog Contributions

Thank you for reading this Azure SDK blog post! We hope that you learned something new and welcome you to share this post. We are open to Azure SDK blog contributions. Please contact us at azsdkblog@microsoft.com with your topic and we’ll get you setup as a guest blogger.

0 comments

Leave a comment