Writing data to Fabric
Append new rows, replace small tables whole, load files that are already in the lakehouse and write files to it.
This page will show you how to write data from Python into Microsoft Fabric:
- Appending the day's new rows to a table that grows
- Replacing a small table whole with the current list
- Turning a file that is already in the lakehouse into a table
- Writing a file to the lakehouse
Under the hood, the Zato services will automatically call OneLake and trigger load-to-table Fabric APIs
Connection and IDs
The app registration, the Fabric connection in the Zato Dashboard, and the workspace and lakehouse IDs are the same as in the tutorial, so set them up as described there first.
Writing to tables needs the app registration to have the Contributor role in the workspace - in Fabric, open the workspace, click "Manage access" and check the role next to the app registration's name.
Two kinds of tables
As a recap, a lakehouse is where Fabric keeps tables and files together, and the tables in it can be generally of two kinds:
- Some will record what happened, e.g. orders, calls or transactions, and they only ever grow, so new rows are appended to them
- Others will describe things, e.g. sites, products or customers, and they are small, so the whole table can be replaced with the current list whenever it changes
Appending the day's rows
Say you have a source system that records admissions and, once a night, a scheduled service should copy the day's new ones to the admissions table in Fabric. The service below does that:
- It keeps in the cache the time it stopped at the last time
- It takes everything recorded since then
- It appends the rows with
conn.write_table - It moves the marker in the cache forward for the next night
# -*- coding: utf-8 -*-
# Zato
from zato.server.service import Service
class AppendAdmissions(Service):
name = 'fabric.append-admissions'
def handle(self):
# The two IDs from the tutorial ..
workspace_id = '262ddd3d-3d0d-4495-b80f-6dddda1e23a1'
lakehouse_id = '73811955-064d-481a-a7e9-f9c563124f9e'
# .. where the previous run stopped ..
since = self.cache.get('admissions.loaded_until')
# .. the rows recorded since then, from the source system ..
rows = [
{
'admission_id': 'ADM-1041',
'location': 'Riverside',
'admitted_at': '2026-09-01 07:15:00',
'discharged_at': '',
'status': 'admitted',
},
{
'admission_id': 'ADM-1042',
'location': 'Riverside',
'admitted_at': '2026-09-01 09:40:00',
'discharged_at': '',
'status': 'admitted',
},
]
# .. get a Fabric connection ..
conn = self.microsoft.fabric['Zato Fabric']
# .. add the rows to what the table already holds ..
# .. note the "Append" mode ..
conn.write_table(workspace_id, lakehouse_id,
'admissions', rows, mode='Append',
)
# .. store the last timestamp for the next run ..
last_row = rows[-1]
self.cache.set('admissions.loaded_until', last_row['admitted_at'])
# .. and tell our caller what was done.
self.response.payload = {'appended': len(rows), 'since': since}
After invoking it, it will append new rows, and you'll see a response as below
Method conn.write_table takes any number of rows:
- It writes them as CSV files to the lakehouse's
Filessection, 100,000 rows per file - It tells the lakehouse to load all of the files into the table in one operation
- It returns when that operation is done so
conn.querycan read the rows
Replacing a small table
In this example, the list of locations has its source in another system and the locations table in Fabric is a copy of it. The service below will:
- Read the list, which comes with the source system's own field names
- Map each field sto the Fabric table's columns
- Replace the whole table in Fabric - note that no
modeis needed for this, because replacing is the default
# -*- coding: utf-8 -*-
# Zato
from zato.server.service import Service
class ReplaceLocations(Service):
name = 'fabric.replace-locations'
def handle(self):
# The two IDs from the tutorial ..
workspace_id = '262ddd3d-3d0d-4495-b80f-6dddda1e23a1'
lakehouse_id = '73811955-064d-481a-a7e9-f9c563124f9e'
# .. in a real service, this list would be obtained ..
# .. via a REST API call or a similar call to the source system ..
items = [
{
'id': 'LOC-1',
'label': 'Riverside',
'town': 'Portland',
'region': 'OR',
'bed_count': 120,
},
{
'id': 'LOC-2',
'label': 'Oak Hill',
'town': 'Salem',
'region': 'OR',
'bed_count': 80,
},
{
'id': 'LOC-3',
'label': 'Maple Grove',
'town': 'Eugene',
'region': 'OR',
'bed_count': 60,
},
]
# .. rename the fields to the table's columns ..
rows = []
for item in items:
row = {
'location_id': item['id'],
'name': item['label'],
'city': item['town'],
'state': item['region'],
'beds': item['bed_count'],
}
rows.append(row)
# .. get a Fabric connection ..
conn = self.microsoft.fabric['Zato Fabric']
# .. replace the table with the current list ..
conn.write_table(workspace_id, lakehouse_id, 'locations', rows)
# .. and tell our caller how many rows the table has now.
self.response.payload = {'locations': len(rows)}
After invoking the service you'll see:
Turning a file into a table
In this case, picture a partner uploads a CSV file to the lakehouse's Files/incoming folder each month and you need a service to turn that file into rows of the invoices table.
You'd create a scheduled job to trigger a service like below, which will then use two calls:
conn.load_tablestarts the load and returns the address where its progress can be checkedconn.wait_for_operationwaits there until the load is done
# -*- coding: utf-8 -*-
# Zato
from zato.server.service import Service
class LoadInvoicesFile(Service):
name = 'fabric.load-invoices-file'
def handle(self):
# The two IDs from the tutorial ..
workspace_id = '262ddd3d-3d0d-4495-b80f-6dddda1e23a1'
lakehouse_id = '73811955-064d-481a-a7e9-f9c563124f9e'
# .. get a Fabric connection ..
conn = self.microsoft.fabric['Zato Fabric']
# .. start loading the file into the table ..
location = conn.load_table(
workspace_id,
lakehouse_id,
'invoices',
'Files/incoming/invoices-2026-08.csv',
mode='Append',
)
# .. wait until Fabric reports that it is done ..
operation = conn.wait_for_operation(location)
# .. and return the outcome to our caller.
self.response.payload = {'status': operation['status']}
After invoking the service you'll see:
Writing a file to Fabric
In this example, the billing system has the month's invoiced totals per location and a CSV file with them needs to land in the lakehouse's Files/exports folder, where other people pick it up.
The service below will:
- Read the totals from the billing system
- Write them to a file under
Files/exportswithconn.onelake_write, which turns a list of dicts into CSV and creates the file, or replaces it if it exists
# -*- coding: utf-8 -*-
# Zato
from zato.server.service import Service
class WriteInvoiceExport(Service):
name = 'fabric.write-invoice-export'
def handle(self):
# The two IDs from the tutorial ..
workspace_id = '262ddd3d-3d0d-4495-b80f-6dddda1e23a1'
lakehouse_id = '73811955-064d-481a-a7e9-f9c563124f9e'
# .. which month this export is for ..
month = '2026-08'
# .. in a real service, these totals would be obtained ..
# .. from a database or a REST API call to the billing system ..
rows = [
{'location': 'Riverside', 'invoiced': 14050.00},
{'location': 'Oak Hill', 'invoiced': 13450.00},
{'location': 'Maple Grove', 'invoiced': 13750.00},
]
# .. get a Fabric connection ..
conn = self.microsoft.fabric['Zato Fabric']
# .. write the rows as a CSV file to the exports folder ..
file_path = f'{lakehouse_id}/Files/exports/invoices-{month}.csv'
conn.onelake_write(workspace_id, file_path, rows)
# .. and tell our caller where the file is.
self.response.payload = {'file': file_path, 'rows': len(rows)}
After invoking the service you'll see:
See also
| Page | What it covers |
|---|---|
| Your first Fabric integration | The app registration, the connection and where the IDs come from |
| Fabric API - Tables | conn.write_table, conn.load_table, conn.list_tables and conn.wait_for_operation, with every parameter |
| Fabric API - Files | conn.onelake_write, conn.onelake_read, conn.onelake_list and conn.onelake_delete, with every parameter |