TypeScript SDK
Complete reference for the Medict TypeScript SDK.
Installation
npm install @medplum/core @medplum/react
MedictClient
The main client class for interacting with the Medict API.
Constructor
import { MedictClient } from '@medplum/core';
const client = new MedictClient({
baseUrl?: string;
clientId?: string;
clientSecret?: string;
redirectUri?: string;
cache?: CacheConfig;
storage?: Storage;
onUnauthenticated?: () => void;
});
Configuration Options
| Option | Type | Description |
|--------|------|-------------|
| baseUrl | string | Medict API base URL (default: 'https://api.medplum.com') |
| clientId | string | OAuth client ID |
| clientSecret | string | OAuth client secret (for server-side apps) |
| redirectUri | string | OAuth redirect URI |
| cache | CacheConfig | Cache configuration |
| storage | Storage | Custom storage implementation |
| onUnauthenticated | () => void | Callback for authentication errors |
Authentication
OAuth 2.0 Flow
// Sign in with redirect
await client.signInWithRedirect({
clientId: 'your-client-id',
redirectUri: 'https://your-app.com/callback',
scope: 'openid profile email'
});
// Handle OAuth callback
const profile = await client.handleCodeExchange();
// Sign out
await client.signOut();
Client Credentials
// Server-to-server authentication
await client.authenticateWithClientCredentials();
Token Management
// Get current access token
const token = client.getAccessToken();
// Refresh token
const newToken = await client.refreshToken();
// Check if token is valid
const isValid = client.isTokenValid();
Resource Operations
Create Resource
const patient = await client.createResource({
resourceType: 'Patient',
name: [{
use: 'official',
family: 'Smith',
given: ['John']
}],
gender: 'male',
birthDate: '1990-01-01'
});
Read Resource
// Read single resource
const patient = await client.readResource('Patient', 'patient-id');
// Read multiple resources
const patients = await client.readResources([
'Patient/patient-1',
'Patient/patient-2'
]);
Update Resource
const updatedPatient = await client.updateResource({
...patient,
name: [{
use: 'official',
family: 'Smith',
given: ['John', 'Michael']
}]
});
Delete Resource
// Delete single resource
await client.deleteResource('Patient', 'patient-id');
// Delete multiple resources
await client.deleteResources([
'Patient/patient-1',
'Patient/patient-2'
]);
Search Operations
Basic Search
// Search for patients by name
const patients = await client.searchResources('Patient', {
name: 'Smith'
});
// Search with multiple parameters
const encounters = await client.searchResources('Encounter', {
patient: 'Patient/patient-id',
status: 'finished',
date: 'ge2023-01-01'
});
Advanced Search
// Search with complex queries
const observations = await client.searchResources('Observation', {
patient: 'Patient/patient-id',
category: 'vital-signs',
'value-quantity': 'gt100',
'value-quantity': 'lt200',
_sort: 'date',
_count: 10
});
// Search with includes
const encountersWithPatient = await client.searchResources('Encounter', {
status: 'finished'
}, {
_include: ['Encounter:patient']
});
Search Iterator
// Iterate through search results
for await (const patient of client.searchResourceIterator('Patient', {
name: 'Smith'
})) {
console.log(patient);
}
Batch Operations
Execute Batch
const batchResponse = await client.executeBatch({
resourceType: 'Bundle',
type: 'batch',
entry: [
{
request: {
method: 'POST',
url: 'Patient'
},
resource: {
resourceType: 'Patient',
name: [{ family: 'Smith', given: ['John'] }]
}
}
]
});
Execute Transaction
const transaction = await client.executeTransaction({
resourceType: 'Bundle',
type: 'transaction',
entry: [
{
request: {
method: 'POST',
url: 'Patient'
},
resource: {
resourceType: 'Patient',
name: [{ family: 'Smith', given: ['John'] }]
}
}
]
});
History and Versioning
Resource History
// Get history for a specific resource
const history = await client.readHistory('Patient', 'patient-id');
// Get history for a resource type
const patientHistory = await client.readHistory('Patient');
// Get history with parameters
const recentHistory = await client.readHistory('Patient', 'patient-id', {
_count: 10,
_since: '2023-01-01T00:00:00Z'
});
Version Management
// Read a specific version
const version = await client.readVersion('Patient', 'patient-id', 'version-1');
// Compare versions
const differences = await client.compareVersions(
'Patient',
'patient-id',
'version-1',
'version-2'
);
Custom Requests
HTTP Requests
// GET request
const response = await client.request('GET', '/fhir/Patient');
// POST request
const response = await client.request('POST', '/fhir/Patient', {
name: [{ family: 'Smith', given: ['John'] }]
});
// PUT request
const response = await client.request('PUT', '/fhir/Patient/patient-id', {
id: 'patient-id',
name: [{ family: 'Smith', given: ['John'] }]
});
// DELETE request
const response = await client.request('DELETE', '/fhir/Patient/patient-id');
Request Options
const response = await client.request('GET', '/fhir/Patient', undefined, {
headers: {
'Custom-Header': 'value'
},
timeout: 5000
});
Error Handling
Error Types
try {
const patient = await client.readResource('Patient', 'invalid-id');
} catch (error) {
if (error instanceof MedictError) {
switch (error.code) {
case 'not-found':
console.log('Resource not found');
break;
case 'unauthorized':
console.log('Authentication required');
break;
case 'forbidden':
console.log('Access denied');
break;
default:
console.log('Error:', error.message);
}
}
}
Retry Logic
async function withRetry<T>(operation: () => Promise<T>, maxRetries = 3): Promise<T> {
for (let i = 0; i < maxRetries; i++) {
try {
return await operation();
} catch (error) {
if (i === maxRetries - 1) throw error;
if (error.code === 'rate-limit') {
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
} else {
throw error;
}
}
}
}
Caching
Cache Configuration
const client = new MedictClient({
baseUrl: 'https://api.medplum.com',
clientId: 'your-client-id',
cache: {
enabled: true,
ttl: 300000, // 5 minutes
maxSize: 1000
}
});
Cache Operations
// Cache a resource
await client.cacheResource('Patient', 'patient-id');
// Clear cache
await client.clearCache();
// Get cached resource
const cached = client.getCachedResource('Patient', 'patient-id');
Events
Event Listeners
// Listen for authentication events
client.on('authenticate', (profile) => {
console.log('User authenticated:', profile);
});
client.on('logout', () => {
console.log('User logged out');
});
// Listen for token refresh
client.on('tokenRefresh', (token) => {
console.log('Token refreshed:', token);
});
React Integration
MedictProvider
import { MedictProvider } from '@medplum/react';
function App() {
return (
<MedictProvider medplum={client}>
<YourApp />
</MedictProvider>
);
}
React Hooks
import { useMedict, useResource, useSearchResources } from '@medplum/react';
function PatientComponent({ patientId }: { patientId: string }) {
const medplum = useMedict();
const patient = useResource('Patient', patientId);
const encounters = useSearchResources('Encounter', {
patient: `Patient/${patientId}`
});
if (!patient) {
return <div>Loading...</div>;
}
return (
<div>
<h1>{patient.name?.[0]?.given?.[0]} {patient.name?.[0]?.family}</h1>
<p>DOB: {patient.birthDate}</p>
</div>
);
}
Type Definitions
Common Types
// Resource types
type ResourceType = 'Patient' | 'Encounter' | 'Observation' | 'MedicationRequest';
// Search parameters
interface SearchParams {
[key: string]: string | number | boolean;
}
// Search options
interface SearchOptions {
_count?: number;
_offset?: number;
_sort?: string;
_include?: string[];
_revinclude?: string[];
}
// Cache configuration
interface CacheConfig {
enabled: boolean;
ttl: number;
maxSize: number;
}
// Storage interface
interface Storage {
getItem(key: string): string | null;
setItem(key: string, value: string): void;
removeItem(key: string): void;
}
Best Practices
1. Error Handling
Always handle errors gracefully and provide meaningful feedback to users.
2. Resource Validation
Validate resources before creating or updating them.
3. Use Search Efficiently
- Use specific search parameters
- Implement pagination for large result sets
- Cache frequently accessed data
4. Authentication
- Implement proper token refresh logic
- Handle authentication errors
- Use secure storage for tokens
5. Performance
- Use batch operations when possible
- Implement caching for frequently accessed data
- Monitor API usage and response times
Next Steps
- Learn about React Components
- Explore FHIR Reference
- Understand OAuth2 Reference
- Review Project Admin