Event Service¶
This guide provides step-by-step instructions for creating a new APIM API to publish events to Azure Service Bus Topics using the SAIF platform templates.
Aspire Publish Alternative
Starting in Forge 3.3, if your project uses an Aspire AppHost, you can register event services with builder.AddEventService("events") from the SAIF.Platform.Aspire.Hosting package and generate pipeline YAML automatically. See Aspire Publish for details.
๐ Useful Resources¶
- SAIF CLI Documentation
- TypeSpec Documentation
- TypeSpec Official Documentation
- Azure API Management Documentation
- Azure Service Bus Documentation
๐ Prerequisites¶
- โ SAIF CLI and TypeSpec installed and updated
- โ Visual Studio Code with TypeSpec extension
- โ Access to SAIF Azure DevOps organization
- โ Permissions for creating pipelines and Azure resources
โก Step 1: Create Your Project¶
To create a new event service project, run the following command in your project root directory:
๐ง Command Options¶
You can provide all parameters upfront to skip the interactive prompts:
Parameters:
--name: Your application name (will be used in project naming)--owner: The team or individual responsible for the service
๐ก Example¶
This creates an event service with:
- Project ID:
events-myapp(automatically generated from "events" + name) - Application Name:
myapp - Owner:
Platform
โ Success Indicators¶
After running the command, you should see:
- โ New project folder created with your app name
- โ Files generated successfully message
- โ No error messages in the terminal
๐ฏ What Happens Next?¶
- Navigate into your new project directory:
cd <your-project-name> - Verify the project structure matches the layout below
- Proceed to Step 2 to configure security keys
๐ Click to see detailed project structure
your-project/
โโโ .azdo/ # Azure Pipelines configuration
โ โโโ azure-pipelines-event.yml # Main deployment pipeline
โ โโโ azure-pipelines-event-pr.yml # Pull request validation pipeline
โ โโโ vars/ # Pipeline variables
โโโ infra/ # Infrastructure as Code
โ โโโ bootstrap/ # Environment bootstrapping
โ โโโ event/ # Event service infrastructure
โ โโโ openapi/ # Generated OpenAPI specifications
โโโ src/ # Source code
โ โโโ SAIF.[AppName].TypeSpec/ # TypeSpec project for API definitions
โโโ .gitignore
๐๏ธ Step 2: Configure Security Keys¶
๐ What You Need to Provide¶
Your event service API requires subscription key authentication to protect your Service Bus topics. You need to bring a primary key for each environment (TEST, QA, UAT, PROD) that will serve as the authentication token for consuming applications.
โ ๏ธ Required: You must provide primary keys for each environment before deployment, or the infrastructure deployment will fail.
๐ Generate and Configure Primary Key (Recommended)¶
If you need to generate secure primary keys, use Keeper's password generator. Be sure it only contains alphanumerics (hyphens and underscores are allowed, but the pipeline is sensitive to symbols). It is recommended to use a key length of at least 32 characters, maximum 256.
- Configure Azure DevOps Variable Group:
- Navigate to Azure DevOps โ Pipelines โ Library
- There should already be a group created by the SAIF CLI named after your project ID (e.g.,
events-myapp), with the environment-specific variables pre-defined. - Add a different primary key for each environment.
โ ๏ธ Critical: If you rename or use a different variable group, its name must match the secretsVariableGroupName value in your .azdo/vars/event-service.yml file.
โ Success Indicators¶
After configuring security keys, you should have:
- โ Variable group created in Azure DevOps Library
- โ Primary keys added for TEST, QA, UAT, and PROD environments (marked as secret)
๐ฏ What Happens Next?¶
- Your keys are stored securely in Azure DevOps for the deployment pipeline to use
- Proceed to Step 3 to define your event structure with TypeSpec
๐ Note: All SAIF event service APIs use mandatory subscription key authentication. Every API call must include a valid subscription key in the
Ocp-Apim-Subscription-Keyheader.
๐ป Step 3: Define Your Events with TypeSpec¶
๐ฏ What is TypeSpec?¶
TypeSpec is a language for defining APIs and data models. It will automatically generate the OpenAPI specifications that configure your event service. Think of it as describing what your events look like so the system can create the right APIs.
๐ Open Your TypeSpec Project¶
๐๏ธ Understanding the TypeSpec Template¶
Here's what a complete TypeSpec service looks like with explanations:
import "@typespec/http";
import "@typespec/rest";
import "@typespec/openapi";
import "@typespec/openapi3";
import "@typespec/versioning";
import "@saif/platform-typespec";
using TypeSpec.Http;
using TypeSpec.Rest;
using SAIF.Platform;
@service({
title: "Your Event Service", // ๐ This appears in your API documentation
version: "1.0" // ๐ Version your API for consumers
})
@useAuth(ApiKeyAuth<ApiKeyLocation.header, "Ocp-Apim-Subscription-Key">) // ๐ Requires subscription key
namespace YourEventService;
// ๐ Automatically creates REST endpoints
@autoRoute
interface UserCreatedTopic extends Topic<UserCreatedEvent> {}
// ๐ Define your event structure - customize this for your use case
model UserCreatedEvent is Event<"UserCreated"> {
userId: string; // Required field
email: string; // Required field
firstName?: string; // Optional field (note the ?)
lastName?: string; // Optional field
}
Key Concepts:
- ๐ฏ Each event type maps to one Service Bus topic (e.g.
UserCreatedTopicโUserCreatedtopic) - ๐ The
@useAuthdecorator makes subscription keys mandatory for all operations - โก The
@autoRoutedecorator creates REST endpoints from your interface
๐ Build and Validate¶
โ Success Indicators¶
After building your TypeSpec definitions, you should see:
- โ No compilation errors in the terminal
- โ
OpenAPI files generated in the
openapi/folder - โ TypeSpec validation passes without warnings
๐ฏ What Happens Next?¶
- Your TypeSpec is compiled into OpenAPI specifications
- These specs define your API structure for the deployment pipeline
- Proceed to Step 4 to deploy your event service
๐ Step 4: Deploy Your Event Service¶
๐ฏ What This Step Does¶
The deployment pipeline will take your TypeSpec definitions and security keys to create a fully functional event service in Azure, including the API endpoints and Service Bus topics.
- Navigate to Azure DevOps Pipelines
- Run the
events-<project-name>pipeline (e.g.,events-myapp)
The pipeline will:
- โ Compile TypeSpec and generate OpenAPI specifications
- โ Deploy OpenAPI specifications to a dedicated OpenAPI storage account
- โ Deploy APIM API with auto-generated operations
- โ Create Service Bus Topics for event publishing
- โ Configure security policies and activate subscription keys
โ Success Indicators¶
A successful deployment should show:
- โ All pipeline stages completed without errors
- โ Green checkmarks for each deployment environment
- โ No failed tasks in the pipeline logs
๐ Access Your OpenAPI Specifications¶
After deployment, specifications are available at:
๐งช Test Your API¶
curl -X POST "https://app-int-<environment>.saif.com/api/event/<api-name>/<topic-name>" \
-H "Ocp-Apim-Subscription-Key: your-primary-key" \
-H "Content-Type: application/json" \
-H "X-Event-Type: UserCreated" \
-d '{<your-request-body>}'
๐ก Example¶
curl -X POST "https://app-int-test.saif.com/api/event/events-myapp/UserCreated" \
-H "Ocp-Apim-Subscription-Key: 1234-45678" \
-H "Content-Type: application/json" \
-H "X-Event-Type: UserCreated" \
-d '{"userId": "123", "email": "user@example.com"}'
๐ฏ What Happens Next?¶
- Your event service is live and ready to receive requests from the API
- Share your OpenAPI specs with teams that need to consume your events
- Monitor your Service Bus topics for incoming events
- Distribute subscription keys securely to authorized consuming teams
๐ Visual Flow¶
TypeSpec Definition โ OpenAPI Specs โ APIM API โ Service Bus Topics โ Event Consumers
(Step 3) (Pipeline) (Azure) (Azure) (Your Teams)
๐ง Troubleshooting¶
โ Deployment fails with "primary_key not found"¶
- Solution: Add
primary_keysecret to Azure DevOps variable group - Check: Variable group name exactly matches
secretsVariableGroupNamein.azdo/vars/event-service.yml - Verify: Use environment-specific naming:
[TEST]primary_key, ...,[PROD]primary_key
โ API calls return 401 Unauthorized¶
- Solution: Include
Ocp-Apim-Subscription-Keyheader with correct subscription key value
โ API calls return 403 Forbidden¶
- Solution: Verify Service Bus topic exists and is not disabled
- Check: Ensure topic has not been disabled due to quota limits or administrative action
โ TypeSpec compilation errors¶
- Solution: Run
npm installand verify TypeSpec syntax follows SAIF platform conventions