Custom FHIR Operations
Custom FHIR Operations is a powerful feature that allows you to extend the Medplum FHIR server with your own custom operations using the Medplum Bots framework. This feature enables you to create sophisticated business logic that integrates seamlessly with the FHIR API while leveraging the full power of JavaScript execution.
What are Custom FHIR Operations?
Custom FHIR Operations combine two key Medplum features:
- FHIR Operations - Standard FHIR operations (like
$validate,$expand, etc.) that can be invoked via HTTP requests - Medplum Bots - JavaScript functions that can be executed server-side with access to the Medplum SDK
This integration allows you to:
- Define custom business logic using JavaScript
- Expose that logic as standard FHIR operations
- Maintain full FHIR compliance while extending functionality
- Process and transform FHIR resources programmatically
- Integrate with external systems and APIs
How It Works
Custom operations are implemented through three main components:
- Bot - Contains the JavaScript code that implements your custom logic
- OperationDefinition - Defines the operation interface and links to your Bot
- Extension - Links the
OperationDefinitionto theBotimplementation
When a client calls your custom operation (e.g., POST /fhir/R4/Patient/$my-custom-operation), Medplum:
- Looks up the corresponding
OperationDefinition - Finds the linked Bot via the extension
- Executes the
Botwith the operation input - Returns the
Bot's output as the operation result
How to Use Custom FHIR Operations
Step 1: Create a Bot
First, create a Bot that contains your custom logic:
exports.handler = async function (medplum, event) {
const patient = event.input;
// Your custom logic here
patient.identifier = patient.identifier || [];
patient.identifier.push({
system: 'https://example.com/patient-id',
value: '12345',
});
return patient;
};
See Bot Basics for more details on creating Bots.
Important Requirements:
- Your Medplum project must have the
botsfeature enabled - The handler function receives
medplum(SDK instance) andevent(operation context) event.inputcontains the operation input (request body for POST, query params for GET)- Return value becomes the operation output
Step 2: Deploy the Bot
Deploy your Bot code using the $deploy operation:
curl -X POST "https://api.medplum.com/fhir/R4/Bot/{bot-id}/\$deploy" \
-H "Content-Type: application/fhir+json" \
-H "Authorization: Bearer {access-token}" \
-d '{
"code": "exports.handler = async function (medplum, event) { ... }"
}'
Step 3: Create an OperationDefinition
Create an OperationDefinition that describes your operation and links to your Bot:
{
"resourceType": "OperationDefinition",
"extension": [
{
"url": "https://medplum.com/fhir/StructureDefinition/operationDefinition-implementation",
"valueReference": {
"reference": "Bot/{bot-id}"
}
}
],
"name": "my-custom-operation",
"status": "active",
"kind": "operation",
"code": "my-custom-operation",
"system": true,
"type": false,
"instance": false,
"parameter": [
{
"use": "in",
"name": "input",
"type": "Patient",
"min": 1,
"max": "1"
},
{
"use": "out",
"name": "return",
"type": "Patient",
"min": 1,
"max": "1"
}
]
}
Key Requirements:
- Must include the
operationDefinition-implementationextension - Extension must reference a Bot resource
- Define appropriate input/output parameters
Step 4: Invoke Your Custom Operation
Once deployed, you can invoke your custom operation like any standard FHIR operation:
curl -X POST "https://api.medplum.com/fhir/R4/Patient/\$my-custom-operation" \
-H "Content-Type: application/fhir+json" \
-H "Authorization: Bearer {access-token}" \
-d '{
"resourceType": "Patient",
"name": [
{
"family": "Smith",
"given": ["John"]
}
]
}'
Operation Types
Custom operations support all standard FHIR operation types:
- System-level operations:
/fhir/R4/$my-operation - Type-level operations:
/fhir/R4/Patient/$my-operation - Instance-level operations:
/fhir/R4/Patient/123/$my-operation
Configure the operation type using the system, type, and instance properties in your OperationDefinition.
Input and Output Handling
Input Processing
- POST requests: Request body is passed as
event.input - GET requests: Query parameters are passed as
event.input - Access to full request context via
event.headers, etc.
Output Processing
The Bot's return value is automatically formatted according to the OperationDefinition's output parameters. You can return:
- FHIR resources directly
- Primitive values (strings, numbers, booleans)
- Complex objects that match the defined output structure
Security and Permissions
Custom operations inherit the security model of both Bots and FHIR operations:
- Users must have permission to read the Bot resource
- Bot execution follows the Bot's
runAsUserconfiguration - Standard FHIR access controls apply to the operation endpoint
- Operations can be system-level, type-level, or instance-level with appropriate permissions
Error Handling
If your Bot encounters an error:
- Return an
OperationOutcomeresource for controlled error responses - Thrown exceptions will be caught and converted to appropriate HTTP error responses
- Use standard FHIR error patterns for consistent client handling
Example Use Cases
- Data validation: Custom validation rules beyond standard FHIR constraints
- Data transformation: Convert between different FHIR profiles or external formats
- Integration: Connect to external systems, APIs, or databases
- Workflow automation: Implement complex business processes
- Reporting: Generate custom reports or analytics
- Decision support: Implement clinical decision support algorithms