SDCClient Configuration

Configuration reference for the SDCClient, which handles all FHIR R5 SDC (Structured Data Capture) operations for the Web SDK.

Overview

SDCClient is the underlying client used by FormFiller and other components to:

  • Fetch Questionnaire resources from FHIR servers
  • Submit QuestionnaireResponse resources
  • Execute SDC operations ($populate, $extract)
  • Handle authentication and network requests
  • Manage CORS and connectivity

Note: SDCClient is configured automatically through component configuration. Direct instantiation is typically not needed.


Configuration

SDCClient is configured through the sdcEndpoint parameter when creating FormFiller:

const filler = new FormFiller({
  questionnaire: 'phq-9',
  sdcEndpoint: {
    resourceType: 'Endpoint',
    address: 'https://sdc-backend.example.com/fhir'
  }
})

Endpoint Configuration Structure

interface EndpointConfig {
  resourceType: 'Endpoint'
  address: string
}

Properties:

PropertyTypeRequiredDescription
resourceType'Endpoint'YesMust be the literal string 'Endpoint'
addressstringYesBase URL of the FHIR R5 SDC endpoint

Endpoint Setup

SDC Backend Requirements

Your SDC endpoint must be a FHIR R5-compliant server that supports:

Required Operations:

  • GET /Questionnaire/{id} - Retrieve questionnaires
  • POST /QuestionnaireResponse - Submit responses

Optional Operations:

  • GET /Questionnaire?_id={id} - Search questionnaires
  • POST /Questionnaire/$populate - Pre-populate questionnaires
  • POST /QuestionnaireResponse/$extract - Extract structured data

Endpoint URL Format

The address should be the base FHIR URL without trailing operations:

// ✅ Good - base FHIR URL
address: 'https://sdc.example.com/fhir'

// ✅ Good - with API version path
address: 'https://api.example.com/v1/fhir'

// ❌ Bad - includes resource type
address: 'https://sdc.example.com/fhir/Questionnaire'

// ❌ Bad - trailing slash (may cause issues)
address: 'https://sdc.example.com/fhir/'

CORS Configuration

For web applications, ensure your FHIR server has proper CORS headers:

Access-Control-Allow-Origin: https://your-app.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true

For development:

Access-Control-Allow-Origin: *

Advanced Options

Environment-Specific Configuration

Use environment variables for different deployment environments:

const sdcEndpoint = {
  resourceType: 'Endpoint',
  address: import.meta.env.VITE_SDC_ENDPOINT || 'https://default-sdc.example.com/fhir'
}

const filler = new FormFiller({
  questionnaire: 'phq-9',
  sdcEndpoint: sdcEndpoint
})

Environment files:

.env.development:

VITE_SDC_ENDPOINT=https://dev-sdc.example.com/fhir

.env.production:

VITE_SDC_ENDPOINT=https://prod-sdc.example.com/fhir

Multiple Endpoints

If you need different SDC endpoints for different questionnaires:

const endpoints = {
  clinical: {
    resourceType: 'Endpoint',
    address: 'https://clinical-sdc.example.com/fhir'
  },
  research: {
    resourceType: 'Endpoint',
    address: 'https://research-sdc.example.com/fhir'
  }
}

// Use appropriate endpoint
const filler = new FormFiller({
  questionnaire: 'clinical-assessment',
  sdcEndpoint: endpoints.clinical
})

Timeout Configuration

Currently, timeout is managed internally. For custom timeout requirements, contact support.

Retry Logic

The SDCClient includes automatic retry logic for:

  • Network failures
  • Temporary server errors (5xx)
  • Timeout errors

Default behavior:

  • 3 retry attempts
  • Exponential backoff
  • Configurable in future versions

Examples

Basic Configuration

import { FormFiller } from '@tiro-health/web-sdk'

const filler = new FormFiller({
  questionnaire: 'patient-intake',
  sdcEndpoint: {
    resourceType: 'Endpoint',
    address: 'https://sdc.example.com/fhir'
  }
})

With Environment Variables

// Configuration module
export const config = {
  sdcEndpoint: {
    resourceType: 'Endpoint',
    address: import.meta.env.VITE_SDC_ENDPOINT
  },
  dataEndpoint: {
    resourceType: 'Endpoint',
    address: import.meta.env.VITE_DATA_ENDPOINT
  }
}

// Use in components
import { config } from './config'

const filler = new FormFiller({
  questionnaire: 'my-form',
  sdcEndpoint: config.sdcEndpoint
})

Development vs Production

const isDevelopment = import.meta.env.DEV

const sdcEndpoint = {
  resourceType: 'Endpoint',
  address: isDevelopment
    ? 'https://dev-sdc.example.com/fhir'
    : 'https://prod-sdc.example.com/fhir'
}

const filler = new FormFiller({
  questionnaire: 'patient-form',
  sdcEndpoint: sdcEndpoint
})

With Data Endpoint

import { FormFiller, LaunchContextProvider } from '@tiro-health/web-sdk'

// SDC endpoint for questionnaires
const sdcEndpoint = {
  resourceType: 'Endpoint',
  address: 'https://sdc.example.com/fhir'
}

// Data endpoint for patient data
const dataEndpoint = {
  resourceType: 'Endpoint',
  address: 'https://fhir-server.example.com/fhir'
}

const filler = new FormFiller({
  questionnaire: 'patient-intake',
  sdcEndpoint: sdcEndpoint
})

const contextProvider = new LaunchContextProvider({
  dataEndpoint: dataEndpoint,
  filler: filler,
  patientId: 'patient-123'
})

Angular Configuration Service

import { Injectable } from '@angular/core'
import { environment } from '../environments/environment'

interface EndpointConfig {
  resourceType: 'Endpoint'
  address: string
}

@Injectable({
  providedIn: 'root'
})
export class EndpointConfigService {
  getSDCEndpoint(): EndpointConfig {
    return {
      resourceType: 'Endpoint',
      address: environment.sdcEndpoint
    }
  }

  getDataEndpoint(): EndpointConfig {
    return {
      resourceType: 'Endpoint',
      address: environment.dataEndpoint
    }
  }

  validateEndpoint(endpoint: EndpointConfig): boolean {
    return (
      endpoint.resourceType === 'Endpoint' &&
      typeof endpoint.address === 'string' &&
      endpoint.address.startsWith('https://')
    )
  }
}

// Usage in component
constructor(private endpointConfig: EndpointConfigService) {}

ngAfterViewInit(): void {
  const filler = new FormFiller({
    questionnaire: 'my-form',
    sdcEndpoint: this.endpointConfig.getSDCEndpoint()
  })

  filler.mount(this.formContainer.nativeElement)
}

React Configuration Hook

import { useMemo } from 'react'

interface EndpointConfig {
  resourceType: 'Endpoint'
  address: string
}

export function useEndpointConfig() {
  const sdcEndpoint = useMemo<EndpointConfig>(() => ({
    resourceType: 'Endpoint',
    address: import.meta.env.VITE_SDC_ENDPOINT
  }), [])

  const dataEndpoint = useMemo<EndpointConfig>(() => ({
    resourceType: 'Endpoint',
    address: import.meta.env.VITE_DATA_ENDPOINT
  }), [])

  return {
    sdcEndpoint,
    dataEndpoint
  }
}

// Usage in component
function MyForm() {
  const { sdcEndpoint } = useEndpointConfig()

  useEffect(() => {
    const filler = new FormFiller({
      questionnaire: 'my-form',
      sdcEndpoint: sdcEndpoint
    })

    filler.mount(containerRef.current)

    return () => filler.unmount()
  }, [sdcEndpoint])

  return <div ref={containerRef} />
}

Next Steps

For questions or support, please contact the Tiro.health team.

Was this page helpful?