Quick Start
This guide demonstrates the most common operations: creating a resource, marshaling it to JSON, and unmarshaling it back. All examples use the R4 package, but the API is identical for R4B and R5.
1. Create a Patient with a Struct Literal
The most direct way to create a FHIR resource is by initializing the struct fields. Optional FHIR fields are represented as Go pointers, so you need a helper function or the address-of operator to set them.
package main
import (
"fmt"
"github.com/gofhir/models/r4/v2"
)
// ptrTo is a generic helper that returns a pointer to the given value.
func ptrTo[T any](v T) *T {
return &v
}
func main() {
patient := r4.Patient{
Id: ptrTo("123"),
Active: ptrTo(true),
Name: []r4.HumanName{
{Family: ptrTo("Smith"), Given: r4.PtrSlice("John")},
},
}
data, _ := r4.Marshal(&patient)
fmt.Println(string(data))
}Output:
{"resourceType":"Patient","id":"123","active":true,"name":[{"family":"Smith","given":["John"]}]}2. Create a Patient with the Builder
The builder eliminates pointer boilerplate: Set* takes a plain value for single fields and Add* appends to repeating ones, wrapping pointers internally.
patient := r4.NewPatientBuilder().
SetId("patient-123").
SetActive(true).
SetGender(r4.AdministrativeGenderMale).
SetBirthDate("1990-01-15").
Build()You can also add complex nested fields like names and identifiers:
use := r4.NameUseOfficial
family := "Smith"
patient := r4.NewPatientBuilder().
SetId("patient-456").
AddName(r4.HumanName{
Use: &use,
Family: &family,
Given: r4.PtrSlice("John"),
}).
AddIdentifier(r4.Identifier{
System: ptrTo("http://hospital.example.org/mrn"),
Value: ptrTo("12345"),
}).
Build()3. Create a Patient with the Fluent Builder
The builder pattern provides a chainable API. Start with New<Resource>Builder(), set fields with Set and Add methods, and finish with .Build().
family := "Garcia"
use := r4.NameUseOfficial
patient := r4.NewPatientBuilder().
SetId("patient-789").
SetActive(true).
SetGender(r4.AdministrativeGenderFemale).
SetBirthDate("1985-06-20").
AddName(r4.HumanName{
Use: &use,
Family: &family,
Given: r4.PtrSlice("Maria"),
}).
Build()4. Marshal to JSON
Use r4.Marshal instead of json.Marshal. The library function disables HTML escaping so that FHIR narrative XHTML in text.div fields is preserved correctly. The resourceType field is always injected automatically.
data, err := r4.Marshal(patient)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(data))For pretty-printed output, use MarshalIndent:
data, err := r4.MarshalIndent(patient, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(data))Output:
{
"resourceType": "Patient",
"id": "patient-789",
"active": true,
"name": [
{
"use": "official",
"family": "Garcia",
"given": ["Maria"]
}
],
"gender": "female",
"birthDate": "1985-06-20"
}5. Unmarshal from JSON
Known Resource Type
If you know the resource type at compile time, unmarshal directly into the struct:
var patient r4.Patient
err := json.Unmarshal(data, &patient)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Patient ID: %s\n", *patient.Id)Unknown Resource Type
When the resource type is not known in advance (for example, when reading from a FHIR server response), use UnmarshalResource. It inspects the resourceType field and returns the correct Go struct behind the Resource interface:
resource, err := r4.UnmarshalResource(data)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Type: %s\n", resource.GetResourceType())
// Type-assert to access resource-specific fields
if patient, ok := resource.(*r4.Patient); ok {
fmt.Printf("Patient ID: %s\n", *patient.Id)
}You can also peek at the resource type without full deserialization:
resourceType, err := r4.GetResourceType(data)
if err != nil {
log.Fatal(err)
}
fmt.Println(resourceType) // "Patient"6. Create an Observation
Here is a more complete example showing an Observation with a code, value, and category:
codeSystem := "http://loinc.org"
codeCode := "8867-4"
codeDisplay := "Heart rate"
obs := r4.NewObservationBuilder().
SetId("obs-123").
SetStatus(r4.ObservationStatusFinal).
SetCode(r4.CodeableConcept{
Coding: []r4.Coding{
{System: &codeSystem, Code: &codeCode, Display: &codeDisplay},
},
}).
SetEffectiveDateTime("2024-01-15T10:30:00Z").
Build()
data, _ := r4.Marshal(obs)
fmt.Println(string(data))Next Steps
- Learn about FHIR Versions and how the three packages differ.
- Explore Resource Construction patterns in depth.