Skip to main content
Version: 5.1

Azure Files

Azure Files file integrations poll a directory on an Azure file share and process files as they arrive. Use them for drop-folder processing, ETL pipelines, and batch integrations where applications exchange data as CSV, XML, JSON, or binary files through a share mounted over SMB or NFS.

The listener authenticates to the storage account with a shared key, a SAS token, a SAS URL, a connection string, or a Microsoft Entra ID identity. For creating the storage account, the file share, and the credentials, see the Azure Files setup guide.

Creating an Azure Files service​

One flow creates the listener and the service together; the authentication method is a selector on the creation form.

  1. Click + in the WSO2 Integrator side panel header to open the New Integration wizard (on an empty project, the + Add Integration or Library button in the project view opens the same wizard), and continue to the Type step.

  2. Scroll to the File Integration category, select the Azure Files card, and click Next.

    New Integration wizard with the Azure Files card selectedNew Integration wizard with the Azure Files card selected
  3. The Azure Files Integration page opens with the Listener Configurations form. Fill in:

    FieldDescription
    Listener NameIdentifier for this listener (e.g., shareListener).
    Share NameThe name of the file share to watch.
    Monitoring PathThe directory on the share to poll for files (e.g., /incoming). / watches the share root.
  4. Choose an authentication method. For Shared Key, fill in:

    FieldDescription
    Account NameThe storage account name.
    Account KeyA base64-encoded access key of the storage account.
    Azure Files listener configuration formAzure Files listener configuration form

    The selector's other options — SAS token, SAS URL, connection string, and Microsoft Entra ID — reveal the fields of the matching credential record shown on the Ballerina Code tab.

  5. Click Create. WSO2 Integrator generates the listener and the service, and a files:Service entry appears in the sidebar under Entry Points.

  6. Click + Add Handler in the service view to define how incoming files are processed.

File handlers​

A file handler is a remote function that WSO2 Integrator calls for each file the listener's polling cycle finds on the watched path. A service declares one handler per content format it processes, plus an optional error handler:

HandlerTrigger
onCreate (onFileText / onFileJson / onFileXml / onFileCsv / onFile)A file on the watched path matches the service's filters. The function name depends on the content type — one typed variant per file format, with onFile as the raw-bytes catch-all.
onErrorA poll failed, a listed file's content could not be read, or a file's content could not be bound to a typed handler's content parameter — for example, a JSON handler received malformed JSON. A binding failure arrives as a files:ContentBindingError naming the file.

At least one content handler is required — a service with only an onError handler is not valid.

There is no delete handler: the listener dispatches the files present on the share and keeps no per-file state.

Adding a file handler​

  1. Open the service view (select files:Service under Entry Points) and click + Add Handler. The handler picker offers On Create, which fires for files appearing on the monitoring path; select it.

    Handler picker with the On Create handlerHandler picker with the On Create handler
  2. The handler configuration panel opens:

    FieldDescription
    FormatThe format of incoming files. Determines the handler function name and the type of the content parameter. Options: JSON, XML, CSV, Text, Raw Bytes. See Content types.
    After File Processing — On SuccessAction to take when the handler completes without error: Move to a destination path or Delete the file. See Post-processing.
    After File Processing — On ErrorAction to take when the handler returns an error: Move to an error directory or Delete the file. It also covers a content-binding failure, unless the service declares an onError handler in code, in which case the binding failure's disposition follows onError's own actions instead. See Post-processing.
    On Create handler configuration with the format and post-processing actionsOn Create handler configuration with the format and post-processing actions
  3. Click Save to register the handler. The service view lists it:

    Service view with the registered handlerService view with the registered handler

An onError handler for poll, read, and content-binding failures is added in the code view — see the Ballerina Code tab. Declaring one changes how content-binding failures are post-processed; see Post-processing.

Content types​

The Format chosen on an On Create handler determines the function name and the type of the content parameter. Files are routed to handlers by file extension:

FormatHandler functionRouted extensionContent typeUse when
TextonFileText.txtstringFiles are plain text (logs, EDI, custom formats).
JSONonFileJson.jsonjson or a typed recordFiles are JSON documents.
XMLonFileXml.xmlxml or a typed recordFiles are XML documents.
CSVonFileCsv.csvstring[][], record {}[], or a stream of either row formFiles are comma-separated values. Record rows map through the header row into your record type; string rows keep every row of the file. Use a stream for large files.
Raw BytesonFileany other extensionbyte[] or stream<byte[], error?>Binary files or when you need raw byte access.

Routing rules:

  • A per-handler @files:FunctionConfig with a fileNamePattern overrides extension routing for that handler. When several patterns match one file name, the handlers are checked in the fixed order onFileText, onFileJson, onFileXml, onFileCsv, then onFile. At most one handler runs per file.
  • A file whose extension maps to a handler the service does not declare falls back to onFile; if onFile is also absent, the file is skipped and logged.
  • A file routed to a typed handler whose content is malformed raises a files:ContentBindingError — it never falls through to onFile. Its detail carries the file's path in filePath, and its raw bytes in content when the download had already completed. When the service declares an onError handler, the error is delivered there and the file's fate follows onError's own @files:FunctionConfig; the content handler's afterError is not applied. When the service declares no onError, the error is logged and the content handler's afterError applies.
  • A CSV stream handler is the exception for individual rows. A row that fails to bind while the handler reads the stream is returned to the handler as a files:Error from the stream, not raised as a files:ContentBindingError. It does not reach onError; if the handler returns it, the handler's afterError applies.

Post-processing: moving or deleting files​

Delivery is at-least-once: the listener keeps no per-file state, so a file that stays on the watched path fires again on every poll. Handlers consume files by deleting or moving them out of the watched path — either through the Caller or with the automatic actions configured here.

The handler configuration panel's After File Processing section has two independent actions:

EventAction pickerExtra input
On SuccessMove or DeleteMove To destination path (required when Move is chosen)
On ErrorMove or DeleteMove To destination path (required when Move is chosen)

Common combinations:

  • Delete on success, move on error — discard processed files, quarantine failures for review. Set an error destination like /failed.
  • Move on success, move on error — archive processed files and quarantine failures. Set separate destinations like /processed and /failed.
  • Leave the file alone for an outcome — skip the action for that side; the file stays on the watched path and fires again on the next poll.

These actions cover errors the handler returns. If the service also declares an onError handler in the code view, content-binding failures are disposed of by onError's own actions instead, so annotate onError to quarantine files that fail to bind.

The choices update the handler's @files:FunctionConfig annotation; switch to the code view to review the generated annotation.

Typed content and streaming​

JSON and XML handlers can receive their payload as a free-form value (json, xml) or as a typed record you define; CSV handlers receive rows as string arrays (string[][]) or as typed records. CSV and Raw Bytes handlers can additionally receive the content as a stream<T, error?>, so the handler never holds the whole file in memory. The Format picker on the handler form selects the base delivery type; to bind typed records or streams, edit the handler's content parameter type in the code view.

Typed CSV rows — the file's first row is always consumed as the header and maps each row's fields:

type Order record {|
string orderId;
string product;
int quantity;
|};

remote function onFileCsv(Order[] orders, files:FileInfo file) returns error? {
foreach Order 'order in orders {
// typed field access: 'order.orderId, 'order.quantity, ...
}
}

Typed JSON document:

type OrderBatch record {|
string batchId;
Order[] orders;
|};

remote function onFileJson(OrderBatch batch, files:FileInfo file) returns error? {
// batch.batchId and batch.orders are typed
}

Streaming CSV rows:

remote function onFileCsv(stream<Order, error?> orders, files:FileInfo file) returns error? {
check orders.forEach(function(Order 'order) {
// process each row as it arrives
});
}

Streaming raw bytes:

remote function onFile(stream<byte[], error?> content, files:FileInfo file) returns error? {
check content.forEach(function(byte[] chunk) {
// process each chunk
});
}

A content value that does not match the declared parameter type is a files:ContentBindingError, delivered to onError. The exception is a row of a CSV stream, which fails inside the handler instead; see Content types. To relax the record binding — treating a null value as an optional field and an absent field as a nilable field — set laxDataBinding: true on the listener configuration.

FileInfo​

Each handler can receive a files:FileInfo parameter with metadata about the dispatched file.

FieldTypeDescription
shareNamestringThe name of the share the file lives on
pathstringThe share-relative path of the file, for example /dir1/dir2/file.ext — use this for all caller-> operations
namestringThe file name only, without the directory component
sizeBytesintThe file size in bytes
eTagstringThe entity tag of the file
lastModifiedtime:UtcThe last-modified time (UTC)

FileInfo carries what a directory listing provides. For full properties (content type, metadata, headers), use the connector's getFileProperties operation — see the action reference.

Caller operations​

For most use cases, the typed handler parameters and the @files:FunctionConfig post-processing actions are sufficient. When you need additional control — reading a related file, writing output to a different path, or managing files manually — add the files:Caller parameter to your handler. It exposes a share-scoped subset of the connector's client operations on the same connection the listener polls with.

Reading and writing content:

OperationReturn typeDescription
caller->getFile(path, options)T|ErrorRetrieve a file's content in the form the assignment target selects — byte[], string, json, xml, a typed record or record array, or a lazy stream
caller->download(sourcePath, destinationPath, options)Error?Download a file to a local path
caller->uploadFromFile(sourcePath, destinationPath, options)Error?Upload a local file to the share
caller->upload(content, destinationPath, options)Error?Upload in-memory content — byte[], string, json, xml, a record, or a record array

File management:

OperationReturn typeDescription
caller->deleteFile(path)Error?Delete a file
caller->renameFile(sourcePath, destinationPath, options)Error?Rename or move a file within the share
caller->copyFile(sourcePath, destinationPath, options)files:CopyInfo|ErrorStart an asynchronous copy within the share
caller->checkCopyStatus(path)files:CopyStatusInfo?|ErrorCheck the state of the most recent copy targeting a file
caller->abortCopy(path, copyId)Error?Abort a pending copy

Directories:

OperationReturn typeDescription
caller->createDirectory(directoryPath, options)Error?Create a directory
caller->deleteDirectory(directoryPath)Error?Delete an empty directory
caller->list(directoryPath, options)stream<files:Entry, Error?>|ErrorList the entries under a directory

Handlers pass the event's path explicitly — for example, a handler that consumes its file manually:

remote function onFile(byte[] content, files:FileInfo file, files:Caller caller) returns error? {
check archive(content);
check caller->deleteFile(file.path);
}

Property reads and writes and share-level administrative operations are not on the Caller; construct a client through a connection for those. See the action reference for every operation's parameters.

Service and listener​

Every Azure Files integration in the project tree is built from two pieces:

ConstructRole
ListenerThe connection to one file share. Holds the credentials, the share name, and how often to poll.
ServiceThe processing logic for one directory on that share. Its attach point is the watched path, and it holds the file filters and the file handlers that run when a file arrives.

The pairing is one-to-one: each listener accepts exactly one service. To watch several paths — on the same share or on different shares — declare one listener and service pair per path:

import ballerinax/azure.storage.files;

configurable string accountName = ?;
configurable string accountKey = ?;
configurable string shareName = ?;

listener files:Listener ordersListener = new (shareName,
auth = {accountName, accountKey}
);

listener files:Listener invoicesListener = new (shareName,
auth = {accountName, accountKey}
);

type OrderRow record {|
string orderId;
int quantity;
|};

service /orders on ordersListener {
remote function onFileCsv(OrderRow[] content, files:FileInfo file) returns error? {
// Process order CSVs from /orders
}
}

service /invoices on invoicesListener {
remote function onFileXml(xml content, files:FileInfo file) returns error? {
// Process invoice XMLs from /invoices
}
}

Delivery is at-least-once. The listener keeps no per-file state, so a file that stays on the watched path fires again on every poll — consume processed files with the post-processing actions or through the Caller. One file is never dispatched twice at once: at most one invocation runs per path at a time, and a file overwritten while its handler is running is picked up on a later poll. For exactly-once effects, make handlers idempotent or claim each file by renaming it out of the watched path before processing. A file still being written when a poll runs can be picked up mid-write — set minFileAgeSeconds on the service configuration to guard against partial writes.

For the general concept, see Services and listeners.

Service configuration​

The optional @files:ServiceConfig annotation controls what the service watches — recursion into subdirectories, file-name filtering, and a minimum file age. It does not carry a path: the watched path is the service's attach point, so where the FTP/SFTP service sets a path field, the Azure Files service is declared as service /incoming on shareListener.

type OrderRow record {|
string orderId;
int quantity;
|};

@files:ServiceConfig {
recursive: false,
fileNamePattern: ".*\\.csv",
minFileAgeSeconds: 30
}
service /incoming/orders on shareListener {
remote function onFileCsv(OrderRow[] content, files:FileInfo file) returns error? {
// Process order CSVs
}
}

@files:ServiceConfig fields:

FieldTypeDefaultDescription
recursivebooleantrueWatch subdirectories under the watched path.
fileNamePatternstring?—Regular expression matched against the file name (not the path); non-matching files are never dispatched.
minFileAgeSecondsdecimal?—Skip files younger than this many seconds, guarding against files still being written.

Listener configuration​

The listener controls how to connect — the share, the credentials, and the polling cadence. Open the listener's configuration by clicking its name (for example, shareListener) under Listeners in the sidebar.

FieldDescriptionDefault
NameIdentifier for the listener. Required.—
Share NameThe name of the file share to watch. Required.—
AuthThe authentication record — one of the five credential kinds. See Creating an Azure Files service. Required.—
Polling IntervalSeconds between polls of the watched path. Must be greater than zero.60
Retry ConfigRetry behaviour for service requests.Service defaults
Transport ConfigHTTP transport settings — proxy, connection pool, and TLS.Defaults
Lax Data BindingRelaxed data binding for the typed content handlers: JSON, XML, and CSV record binding treat a null value as an optional field and an absent field as a nilable field.false

Each poll with recursive: true issues a full recursive listing and downloads every dispatched file. At scale, widen the polling interval, narrow the watched path, or add a fileNamePattern.

What's next​