Implementation guidance for developers - focusing on general API implementation guidance

Purpose

This site is intended for use by software developers looking to build a conformant GP Connect API interface using the FHIR® standard with a focus on general API implementation guidance.

Notational conventions

The keywords ‘MUST’, ‘MUST NOT’, ‘REQUIRED’, ‘SHALL’, ‘SHALL NOT’, ‘SHOULD’, ‘SHOULD NOT’, ‘RECOMMENDED’, ‘MAY’, and ‘OPTIONAL’ on this site are to be interpreted as described in RFC 2119.

General standards

Information on the technical standards that SHALL be conformed to can be found in the sections below and throughout the GP Connect specification.

Internet standards

Clients and servers SHALL be conformant to the following Internet Engineering Task Force (IETF) request for comments (RFCs), which are the principal technical standards that underpin the design and development of the internet and thus FHIR’s APIs.

  • transport level integration SHALL be via HTTP as defined in the following RFCs: RFC 7230, RFC 7231, RFC 7232, RFC 7233, RFC 7234 and RFC 7235
  • transport level security SHALL be via TLS/HTTPS as defined in RFC 5246 and RFC 6176
  • HTTP Strict Transport Security (HSTS) as defined in RFC 6797 SHALL be employed to protect against protocol downgrade attacks and cookie hijacking

RESTful API

The RESTful API described in the FHIR® standard is built on top of the Hypertext Transfer Protocol (HTTP) with the same HTTP verbs (GET, POST, PUT, DELETE, etc.) commonly used by web browsers. Furthermore, FHIR exposes resources (and operations) as Uniform Resource Identifiers (URIs). For example, a Patient resource /fhir/Patient/1, can be operated upon using standard HTTP verbs such as DELETE /fhir/Patient/1 to remove the patient record.

The FHIR RESTful API style guide defines the following URL conventions which are used throughout the remainder of this document:

  • URL pattern content surrounded by [ ] are mandatory.
  • URL pattern content surrounded by { } are optional.

Service Root URL

The Service Root URL is the address root address of where the resources defined by a capability are found.

The Service Root URL is the [base] portion of FHIR URLs.

It is important to note that the Service Root URL will be different for each GP Connect capability (excluding Appointments and Foundations as mentioned below), as each capability is defined as its own FHIR server:

  • Appointment Management (including Foundations, which will always have the same Service Root URL as Appointment Management)
  • Access Record Structured
  • Access Document

Each capability’s Service Root URL may have a different URL path, or point to a different server, or a completely different supplier system.

Service Root URL versioning

Service Root URLs SHALL be aligned with the GP Connect specification they were built against, specifically the major version number SHALL be present in the server’s Service Root URL to provide a clear distinction between API versions that are incompatible (i.e. contain breaking changes) vs. backwards-compatible (i.e. contain no breaking changes).

Provider systems SHALL publish Service Root URLs for major versions of FHIR APIs in the Spine Directory Service in the following format:

https://[FQDN of FHIR Server]/[ODS_CODE]/[FHIR_VERSION_NAME]/[GPC_MAJOR_VERSION]/[PROVIDER_ROUTING_SEGMENT]
  • [FQDN_OF_FHIR_SERVER] is the fully qualified domain name where traffic will be routed to the logical FHIR server for the organisation in question

  • [ODS_CODE] is the Organisation Data Service code which uniquely identifies the GP Practice organisation

  • [FHIR_VERSION_NAME] refers to the textual name identifying the major FHIR version, examples being DSTU2 and STU3. The FHIR Version name SHALL be specified in UPPERCASE characters.

  • [GPC_MAJOR_VERSION] identifies the major version number of the GP Connect specification that the API is built to.

  • [PROVIDER_ROUTING_SEGMENT] enables providers to differentiate between logical FHIR servers defined by GP Connect capabilities, or other FHIR based APIs. For example, the [PROVIDER_ROUTING_SEGMENT] could be:
    • gpconnect for the Appointment Management and Foundations capabilities
    • gpconnect/structured for the Access Record Structured capability
    • and gpconnect/documents for the Access Documents capability

    Please note: The Appointment Management and Foundations capabilities SHALL have the same [PROVIDER_ROUTING_SEGMENT] value. Other capabilies SHALL have different values.

  • The Service Root URL SHALL NOT contain a trailing /

Example Service Root URL

The provider SHALL publish the Service Root URL for each capability to Spine Directory Services, for example:

https://provider.nhs.uk/GP0001/STU3/1/gpconnect/structured

Please see Registering GP Connect systems in SDS for more details.

Consumer systems are required to construct a Service Root URL containing the SSP URL followed by the FHIR Server Root URL of the practice’s capability FHIR server that is suitable for interacting with the SSP service. API provider systems will be unaware of the SSP URL prefix as this will be removed prior to calling the provider API endpoint.

The consumer system would therefore issue a request to the new version of the provider FHIR API to the following URL:

https://[ssp_fqdn]/https://provider.nhs.uk/GP0001/STU3/1/gpconnect/structured/[FHIR request]

Resource URL

The Resource URL will be in the following format:

VERB [base]/[type]/[id] {?_format=[mime-type]}

Clients and servers constructing URLs SHALL conform to RFC 3986 Section 6 Appendix A which requires percent-encoding for a number of characters that occasionally appear in the URLs (mainly in search parameters).

HTTP verbs

The following HTTP verbs SHALL be supported to allow RESTful API interactions with the various FHIR resources:

  • GET
  • POST
  • PUT
  • DELETE

Resource types

GP Connect provider systems SHALL support FHIR resource types as detailed within the FHIR Resource Guidance.

Resource ID

This is the logical Id of the resource which is assigned by the server responsible for storing it. The logical identity is unique within the space of all resources of the same type on the same server, is case sensitive and can be up to 64 characters long.

Once assigned, the identity SHALL never change. logical Ids are always opaque, and external systems need not and should not attempt to determine their internal structure.

For further background, refer to principles of resource identity as described in the FHIR standard

External resource resolution

In line with work being undertaken in other jurisdictions (see the Argonaut Implementation Guide for details) GP Connect provider systems are not expected to resolve full URLs that are external to their environment.

Content types

  • Servers should support both formal MIME-types for FHIR resources:
    • Servers SHALL support JSON: application/fhir+json
    • Servers SHOULD support XML: application/fhir+xml
  • Servers SHALL support the optional _format parameter in order to allow the client to specify the response format by its MIME-type. If both are present, the _format parameter overrides the Accept header value in the request.

  • Where no Accept header or _format parameter is sent with a request but there is a Content-Type header, such as in a POST request, the server SHALL return the response using the format type within the Content-Type header.

  • Where no Accept header, _format parameter and no Content-Type header is present, as is possible within a GET request, the server SHALL default to JSON.

Wire format representations

Servers should support two wire formats as ways to represent resources when they are exchanged:

  • Servers SHALL support JSON
  • Servers SHOULD support XML

Consumers SHALL ignore unknown extensions and elements in order to foster forwards compatibility and declare this by setting CapabilityStatement.acceptUnknown to ‘both’ in their capability statement.

Systems SHALL declare which format(s) they support in their CapabilityStatement. If a server receives a request for a format that it does not support, it SHALL return an HTTP status code of 415 indicating an Unsupported Media Type.

Transfer encoding

Clients and servers SHALL support the HTTP Transfer-Encoding header with a value of chunked. This indicates that the body of a HTTP response will be returned as an unspecified number of data chunks (without an explicit Content-Length header).

Character encoding

Clients and servers SHALL support the UTF-8 character encoding as outlined in the FHIR standard.

FHIR uses UTF-8 for all request and response bodies. Since the HTTP specification (section 3.7.1) defines a default character encoding of ISO-8859-1, requests and responses SHALL explicitly set the character encoding to UTF-8 using the charset parameter of the MIME-type in the Content-Type header. Requests MAY also specify this charset parameter in the Accept header and/or use the Accept-Charset header.

Where the character encoding is included with the “Content-Type” or “Accept” header there should not be a space between the MIME-type and the character encoding, as per the standard for these headers (rfc2616).

Content compression

To improve system performances clients/servers SHALL support GZIP compression.

Compression is requested by setting the Accept-Encoding header to gzip.

Inter-version compatibility

Unrecognized search criteria SHALL always be ignored. As search criteria supported in a query are echoed back as part of the search response there is no risk in ignoring unexpected search criteria.

HTTP headers

Proxying headers

Additional HTTP headers SHALL be added into the HTTP request/response for allowing the proxy system to disclose information lost in the proxying process (for example, the originating IP address of a request). Typically, this information is added to proxy forwarding headers as defined in RFC 7239.

Cross-organisation provenance and audit headers

To meet auditing and provenance requirements (which are expected to be closely aligned with the IM1 requirements), clients SHALL provide an oAuth 2.0 Bearer token in the HTTP Authorization header (as outlined in RFC 6749) in the form of a JSON Web Token (JWT) as defined in RFC 7519.

Refer to Integration - cross-organisation audit and provenance for full details of the JWT claims that SHALL be used for passing audit and provenance details between systems.

Clients SHALL add the following Spine proxy headers for audit and security purposes:

  • Ssp-TraceID - TraceID (generated per request) which identifies the sender’s message/interaction (for example, a GUID/UUID).
  • Ssp-From - ASID which identifies the sender’s FHIR endpoint.
  • Ssp-To - ASID which identifies the recipient’s FHIR endpoint.
  • Ssp-InteractionID - identifies the FHIR interaction that is being performed 1

1 please refer to the Development - FHIR API guidance - operation guidance for full details.

The SSP SHALL perform the following checks to authenticate client request:

  • get the common name (CN) from the TLS session and compare the host name to the declared endpoint
  • check that the client/sending endpoint has been registered (and accredited) to initiate the given interaction
  • check that the server/receiving endpoint has been registered (and accredited) to receive/process the given interaction

Caching headers

Providers SHALL use the following HTTP header to ensure that no intermediaries cache responses: Cache-Control: no-store

Managing Return Content

Provider SHALL maintain resource state in line with the underlying system, including the state of any associated resources.

For example:

If the practitioner associated with a schedule is changed on the provider’s system, such as when a locum is standing in for a regular doctor, this should be reflected in all associated resources to that schedule. The diagram below shows the expected change to the appointment resources for this scenario.

When the appointment is booked, the appointment resource is associated with a slot resource and references the practitioner resource associated with the schedule in which the slot resides. If the schedule is then updated within the provider system to reflect the change of practitioner from the original doctor to a locum doctor, then the practitioner reference with the schedule will be updated. If a consumer then performs a read of the appointment the returned appointment resource should reflect the updated practitioner on the schedule.

Diagram of reflection of state

Servers SHALL default to the return=representation behaviour (that is, returning the entire resource) for interactions that create or update resources.

Servers SHOULD honour a return=minimal or return=representation preference indicated in the Prefer request header, if present.

Demographic cross-checking

Consumer systems SHALL compare the returned structured patient demographic data (supplied by the provider system as structured data) against the demographic data held in the consumer system.

The following data SHALL be cross-checked between consumer and returned provider data. Any differences between these fields SHALL be brought to the attention of the user.

Item Resource field
Family name patient.name.family
Given name patient.name.given
Gender patient.gender
Birth date patient.birthDate

Additionally, the following data MAY be displayed if returned from the provider to assist a visual cross-check and for safe identification, but should not be part of the automatic comparison:

  • Address and postcode
  • Contact (telephone, mobile, email)

All above may be redacted if patient is flagged on Spine as sensitive demographics.

Managing resource contention

To facilitate the management of resource contention, servers SHALL always return an ETag header with each resource including the resource’s versionId:

HTTP 200 OK
Date: Sat, 09 Feb 2013 16:09:50 GMT
Last-Modified: Sat, 02 Feb 2013 12:02:47 GMT
ETag: W/"23"
Content-type: application/json+fhir

ETag headers which denote resource version Ids SHALL be prefixed with W/ and enclosed in quotes, for example:

ETag: W/"3141"

Clients SHALL submit update requests with an If-Match header that quotes the ETag from the server.

PUT /Patient/347 HTTP/1.1
If-Match: W/"23"

If the version Id given in the If-Match header does not match, the server returns a 409 Conflict status code instead of updating the resource.

For servers that don’t persist historical versions of a resource (that is, any resource other than the currently available/latest version) then they SHALL operate in line with the guidance provided in the following Hay on FHIR - FHIR versioning with a non-version capable back-end blog post. This is to ensure that GP Connect servers will be compatible with version-aware clients, even though the server itself doesn’t support the retrieval of historical versions.

Managing return errors

To manage return errors, FHIR defines an OperationOutcome resource that can be used to convey specific detailed processable error information. An OperationOutcome may be returned with any HTTP 4xx or 5xx response, but is not always required.