# Python Microsoft Fabric - Sending events as they happen

Send each event to a Fabric eventstream as soon as it happens, over Kafka or over REST.

A service that passes records from one system to another can also send each record to Fabric, so it reaches Fabric within a second, not at the nightly load. Fabric receives events in an eventstream, and from there a dashboard can show them and an eventhouse can store them. This page sends one event per record to an eventstream.

> **What you need from your Fabric admin**
>
> From the eventstream's custom endpoint source, the Keys tab - the bootstrap server, the topic name and, for the connection-string variant, the connection string. For the OAuth 2.0 variant, the app registration of your Fabric connection must be allowed to send to the eventstream. For the REST variant, the same endpoint's REST address.

## Kafka or REST {#kafka-or-rest}

An eventstream's custom endpoint accepts events over Kafka and over REST. With Kafka one connection stays open and each event is one send, with REST each event is one HTTPS call.

**Kafka**

## The Kafka connection {#the-kafka-connection}

The bootstrap server from the Keys tab is the address, the topic name is the topic, TLS is on. Authentication is a security definition plus a mechanism, the same way every [Kafka connection](https://zato.io/docs/dev/examples/kafka.html) in Zato is set up.

With OAuth 2.0, the connection signs in as the same app registration your Fabric connection uses. Create a Bearer token definition first, under `Security → Bearer tokens`:

| Field | Value |
| --- | --- |
| Name | `Fabric Events Token` |
| Username | The application (client) ID of your app registration |
| Password | Its client secret |
| Auth endpoint | `https://login.microsoftonline.com/<tenant ID>/oauth2/v2.0/token` |
| Scopes | `https://<namespace>.servicebus.windows.net/.default` |

The namespace is the first part of the bootstrap server, up to `.servicebus.windows.net`. Then, under `Connections → Message queues → Kafka → Outgoing connections`, create the connection:

| Field | Value |
| --- | --- |
| Name | `Fabric Events` |
| Address | The bootstrap server, e.g. `<namespace>.servicebus.windows.net:9093` |
| Topic | The topic name from the Keys tab |
| SSL | On |
| Security | `Fabric Events Token` |
| SASL mechanism | `OAUTHBEARER` |

When the admin gives you a connection string instead of allowing the app to sign in, the definition is a Basic Auth one with the username `$$ConnectionString` - the doubled `$` is how a literal `$` is entered, a single one would name an environment variable - and the connection string as the password, and the mechanism is `PLAIN`. The rest of the connection stays the same.

The same two connections in enmasse YAML, the OAuth 2.0 one first:

```yaml
security:
  - name: Fabric Events Token
    type: bearer_token
    username: <application (client) ID>
    password: Zato_Enmasse_Env.FabricEventsSecret
    auth_endpoint: https://login.microsoftonline.com/<tenant ID>/oauth2/v2.0/token
    scopes: https://<namespace>.servicebus.windows.net/.default

outgoing_kafka:
  - name: Fabric Events
    address: <namespace>.servicebus.windows.net:9093
    topic: <topic name>
    security: Fabric Events Token
    sasl_mechanism: OAUTHBEARER
    ssl: true
```

```yaml
security:
  - name: Fabric Events Key
    type: basic_auth
    username: $$ConnectionString
    password: Zato_Enmasse_Env.FabricEventsConnectionString
    realm: zato

outgoing_kafka:
  - name: Fabric Events
    address: <namespace>.servicebus.windows.net:9093
    topic: <topic name>
    security: Fabric Events Key
    sasl_mechanism: PLAIN
    ssl: true
```

## The service {#the-service}

The event is a dict, `send` turns it into JSON and hands it to the eventstream:

```python
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class PassAdmission(Service):

    input = 'admission_id', 'location', 'admitted_at'

    def handle(self):

        admission = self.request.input

        # The event the eventstream receives ..
        event = {
            'event_type': 'admission',
            'location': admission.location,
            'occurred_at': admission.admitted_at,
            'admission_id': admission.admission_id,
        }

        # .. sent to it.
        self.out.kafka['Fabric Events'].send(event)
```

**REST**

## The REST connection {#the-rest-connection}

The eventstream's endpoint accepts events posted over HTTPS too, to `https://<namespace>.servicebus.windows.net/<topic name>/messages`. Create a Bearer token definition under `Security → Bearer tokens`:

| Field | Value |
| --- | --- |
| Name | `Fabric Events REST Token` |
| Username | The application (client) ID of your app registration |
| Password | Its client secret |
| Auth endpoint | `https://login.microsoftonline.com/<tenant ID>/oauth2/v2.0/token` |
| Scopes | `https://eventhubs.azure.net/.default` |

Then, under `Connections → REST → Outgoing connections`:

| Field | Value |
| --- | --- |
| Name | `Fabric Events REST` |
| Host | `https://<namespace>.servicebus.windows.net` |
| URL path | `/<topic name>/messages` |
| Data format | JSON |
| Security | `Fabric Events REST Token` |

In enmasse YAML:

```yaml
security:
  - name: Fabric Events REST Token
    type: bearer_token
    username: <application (client) ID>
    password: Zato_Enmasse_Env.FabricEventsSecret
    auth_endpoint: https://login.microsoftonline.com/<tenant ID>/oauth2/v2.0/token
    scopes: https://eventhubs.azure.net/.default

outgoing_rest:
  - name: Fabric Events REST
    host: https://<namespace>.servicebus.windows.net
    url_path: /<topic name>/messages
    data_format: json
    security: Fabric Events REST Token
```

## The service {#the-service_1}

The endpoint takes a list of events, each wrapped in a `Body` field, with a content type of its own:

```python
# -*- coding: utf-8 -*-

# stdlib
import json

# Zato
from zato.server.service import Service

class PassAdmission(Service):

    input = 'admission_id', 'location', 'admitted_at'

    def handle(self):

        admission = self.request.input

        # The event the eventstream receives ..
        event = {
            'event_type': 'admission',
            'location': admission.location,
            'occurred_at': admission.admitted_at,
            'admission_id': admission.admission_id,
        }

        body = json.dumps(event)
        payload = [{'Body': body}]
        headers = {'Content-Type': 'application/vnd.microsoft.servicebus.json'}

        # .. sent to it.
        conn = self.rest['Fabric Events REST']
        conn.post(self.cid, payload, headers=headers)
```

## What Fabric shows {#what-fabric-shows}

A second after the service runs, the eventstream's data preview has the event:

A Real-Time Dashboard that reads from the eventhouse the eventstream writes to shows the new count:

## See also {#see-also}

- [Receiving events as they happen](https://zato.io/docs/dev/examples/cloud/fabric/receiving-events.html) - The other direction, Fabric sending events to a service
- [Reading recent events](https://zato.io/docs/dev/examples/cloud/fabric/reading-events.html) - Querying the last few minutes of events on a schedule
- [Events](https://zato.io/docs/dev/examples/cloud/fabric/api/events.html) - Every field of the Kafka and REST connections for an eventstream

## Learn more {#learn-more}

- [Development documentation](https://zato.io/docs/dev/) - Everything about writing services, in one place
- [Requests and responses](https://zato.io/docs/dev/request-response/) - What a service receives, what it returns and how to shape both
- [Integration examples](https://zato.io/docs/dev/examples/) - Ready-made code for the systems you are likely to connect to
- [IDE and debugging](https://zato.io/docs/dev/ide/) - Write services in the Dashboard or in your own editor
- [Data models](https://zato.io/docs/dev/model/) - Declare inputs and outputs and have them validated for you
- [In-depth API tutorial](https://zato.io/tutorials/main/01.html) - The full platform tutorial, from installation to production patterns
