Introduction
A key benefit of creating Data Virtualization APIs is their flexibility, with all aspects of their inputs and outputs customizable. FME supports file-based inputs and outputs, allowing users to upload and receive data in any format, matching the existing versatility of traditional workspaces.
This tutorial will walk through creating an endpoint that accepts a JPG image as input and returns the same image rotated 180°. Being a demo, this endpoint is fairly rigid, but it could be made significantly more flexible by using parameters or by adopting a less simplistic file-processing approach.
Requirements
- FME Form and FME Flow 2026.1 or newer.
- Familiarity with Data Virtualization: Please review Create a Data Virtualization API
Optional
- A 3rd party client that can send POST requests. Many are available, including Postman and cURL. More detailed instructions will be provided for Postman.
Step-by-Step Instructions
This tutorial focuses on the file upload aspect of Data Virtualization. For detailed steps on creating a Data Virtualization API, see Create a Data Virtualization API.
1. Create a New Data Virtualization API
Log in to FME Flow 2026.1+. Navigate to Data Virtualization, click Create, and create a new API with the following settings:
API Details
- API Title: Working with Files Tutorial
- Namespace: files
- Summary: An API for processing image files.
- Description: A tutorial API that demonstrates how to handle file-based inputs and outputs in Data Virtualization. Contains an endpoint that accepts a JPG image and returns the same image rotated 180°.
Endpoint Security
- Access Level: Unauthenticated
See Secure Data Virtualization Endpoints with Authentication for guidance on endpoint access levels.
Leave all other settings as the default. Then click Create at the bottom of the parameters list.
2. Create a New Endpoint
In the newly created API, navigate to the Endpoints tab and click Create. In the Details tab, enter the following settings:
Endpoint Details
- Path: flip
- Operation: POST
- Summary: Rotates an image 180 degrees.
Endpoint Security
- Inherit API Security: Enabled
Click Create in the top right.
3. Set the Request Body
While still in the POST /flip endpoint, in the Request Body tab:
- Required: Yes
- Content Type: image/jpeg
Then click Save.
4. Set the Response
Switch to the Response tab:
- Response Type: Workspace
Click Add Status Code:
First Status Code
- HTTP Status Code: 200 - OK
- Description: Successful request
- Content Type: application/json
- Response Structure: Create Properties
Click Add Status Code again to create another code:
Second Status Code
- HTTP Status Code: 400 - Bad Request
- Description: Image missing or incorrect file format sent
- Content Type: application/json
-
Response Structure: Create Properties
-
Object Properties: Click Create
- NAME: error
- TYPE: String
- Required: Yes
-
Object Properties: Click Create
Click Save. If a Workspace Update Required warning appears, click Save to ignore it.
5. Generate a New Workspace and Open it in FME Workbench
In the Workspaces tab, select the POST /flip endpoint, then from the Endpoint Actions drop-down, click Generate Workspace.
In the dialog, change the following:
- Workspace Name: flip_endpoint
Click Generate.
Open FME Workbench, on the start page, click Data Virtualization, select flip_endpoint.fmw, and click Download.
6. Create Samples
Download a JPG (example) and a PNG (example), and rename them to boats.jpg and vancouver.png.
Navigate to the Samples directory, located at Documents/FME/Data Virtualization APIs/<hostname>/<API Name>/<endpoint>/Samples.
Place both files in the Samples directory.
In FME Workbench, click Run. In the Translation Parameter Values dialog, enter the following:
{
"body": [
{
"content": "boats.jpg",
"contentType": "image/jpeg"
}
],
"method": "POST",
"path": "/flip"
}Click Save As Sample and name the sample 200 Response. Click Run with data caching enabled, and check everything is read in as expected:
7. Expose the Source Path
Double-click the Reader, navigate to the Format Attributes tab, check source_path, and hit OK. This attribute contains the file's directory, which can be combined with request.body_file_path to get its full path.
Rerun using the saved sample, and check that the source_path attribute appears in the data preview.
If source_path is missing or ".", you are likely encountering a known issue. For a workaround, see Known Issue: source_path set incorrectly in FME Form.
8. Add a FeatureReader
Add a FeatureReader transformer, and connect it to the /flip Reader. Set its parameters as follows:
- Format: JPEG (Joint Photographic Experts Group)
-
Dataset:
@Value(source_path)/@Value(request.body_file_path)
Click OK.
After clicking OK, a Generating Output Ports dialog will appear. Select the JPG you downloaded, and press OK.
Run the workspace again using the previously saved sample template. Verify that your image was read in correctly by clicking the FeatureReader and checking whether your image appears.
9. Flip the Image
Add a Rotator and connect its Input port to the FeatureReader’s JPEG port. In its parameters, set:
- Rotation Angle (degrees): 180
Add a RasterRotationApplier transformer and connect its Input port to the Rotator’s Rotated port. Leave its parameters as default.
Rerun the workspace and click RasterRotationApplier to verify the image was flipped. Depending on your FME Workbench configuration, the preview may be low resolution.
10. Add a FeatureWriter
Add a FeatureWriter transformer and connect its Output port to the RasterRotationApplier. Set its parameters as follows:
Writer
- Format: JPEG (Joint Photographic Experts Group)
- Dataset: $(FME_SHAREDRESOURCE_TEMP)
- Raster File Name: flipped
Click OK.
Run the workspace. In the Translation Parameter Values dialog, set FME Flow Temporary Resource Directory to a new folder you can easily access.
Click Run, navigate to the directory you just set, and verify that flipped.jpg is there.
11. Construct a 200 Response
Add an AttributeCreator. Connect its Input port to the Summary port of the FeatureWriter, and its Output port to the http_response writer feature type. In its parameters, add the following attributes:
-
Output Attribute:
response.status_code- Value: 200
- Type: uint8
-
Output Attribute:
response.body.content_type- Value: image/jpeg
- Type: varchar(10)
-
Output Attribute:
response.body.content_file_path-
Value:
$(FME_SHAREDRESOURCE_TEMP)/flipped.jpg - Type: varchar(200)
-
Value:
Click OK, and verify the relevant ports in the writer have turned from red to green. If not, you have likely made a typo in one of the Output Attribute fields.
Click Run, and ensure the translation was successful. Check your flip_endpoint\Output folder to verify that it contains the flipped image. Your workspace should look like this:
12. Publish to FME Flow and Test
Publish the workspace with all default settings to FME Flow.
Make a POST request to your endpoint with your image in the request body. If using Postman, for example, use form-data in the body to include the file. If using cURL, your request should be of this format:
curl -X POST <Flow Host>/api/files/flip -F file=@"<path to JPG>" --output="path/to/output/file.jpg"13. Instructions for Testing in Swagger UI
To open Swagger UI, in FME Flow, click on API Details, then View Documentation. Expand the menu for POST /flip, and click Try It Out. When choosing a file, choose boats.jpg, then click execute.
You should see this response.
14. Instructions for Using Postman (Optional)
Postman is a standalone API client that lets you save, organize, and reuse requests beyond what Swagger UI offers. If you'd like to test the API in Postman instead, follow the steps below.
Assuming you have already installed and opened Postman, click the plus button in the top-left corner, then select HTTP.
In the dropdown on the left, change the method from GET to POST. Put your endpoint address in the URL bar. It should follow this pattern:
http://<your-FME-Flow-host>/api/files/flipTo attach your image, click the Body tab and select form-data. In the table, change the drop-down value from Text to File. Type the file as the key name. In the value column, click Select File and choose boats.jpg. Then send the request.
The result should show a preview of the flipped image and the 200 - OK message.
15. Deal with Incorrect Content Types
Currently, if you call this endpoint with the wrong file format, a generic 500 Internal Server Error will be returned. This is poor API design, since the problem is on the user’s end, and not the server’s. As such, the API should inform the user that they uploaded the wrong file type and respond with an appropriate 400 status code.
Create the following template, referencing the PNG you downloaded in step 5.
{
"body": [
{
"content": "vancouver.png",
"contentType": "image/png"
}
],
"method": "POST",
"path": "/flip"
}Save this as a sample named “400 (png uploaded)”, and run the workspace.
The workspace fails at the FeatureReader and outputs a rejected feature. To make sure this doesn’t happen, add a Tester before the FeatureReader and give it the following parameters:
-
Left Value:
request.content_type - Operator: =
- Right Value: image/jpeg
Add another AttributeCreator and connect its Input port to the Tester’s Failed port, and its Output port to the writer. In its parameters, add the following attributes:
-
Output Attribute:
response.status_code- Value: 400
- Type: uint16
-
Output Attribute:
response.body.content_type- Value: application/json
- Type: varchar(16)
-
Output Attribute:
response.body.content-
Value:
{"error":"Only .jpg files can be submitted."} - Type: varchar(45)
-
Value:
The format of response.body.content matches the properties we set in FME Flow in step 3, in the Response Structure of the second status code:
Label the new AttributeCreator 400, and the old one 200. Your workspace should now look like this:
16. Republish to FME Flow
Republish to FME Flow and test the responses again.