RESTful API Example: SDP-V

The SDP Vocabulary Service (SDP-V) API illustrates many points from the RESTful API Guidance, this page describes the design of this API with reference to the applicable guidance.

Resources

SDP-V is an online tool for the management and harmonization of public health data collection instruments. SDP-V manages a pool of questions that are used for data collection along with an associated pool of answer sets for those questions (a set of answers is called a value set). Questions are associated with a specific value sets when they are added to a section of a survey and sections are hierarchically organized into a top level survey. Surveys are owned by a program and surveillance system.

From the above description we can identify six potential resources that could be included in the SDP-V API: surveys, sections, questions, value sets, programs and systems. These potential resources relate to each other in the following ways:

  • A question can be used with multiple different value sets, e.g. a question about age can have different value sets depending on how the survey breaks down age groups
  • A value set can be used for multiple different questions, e.g. a value set with values Yes, No and Unknown culd be used for many different questions
  • A question is tied to a value set by inclusion in a section; questions and value sets can be used in multiple sections
  • A section can include other sections and questions and their associated value sets
  • A section can be included in multiple surveys
  • A survey can include multiple sections
  • A program can own multiple surveys; a survey belongs to one program
  • A surveillance system can own multiple surveys; a survey belongs to one surveillance system

Given this set of relationships it is clear that all six of the potential resources identified earlier have a separate existence from the others and are therefore good candidates for resources in our API.

In the database that backs SDP-V there are additional entities for capturing the relationships between, e.g. sections and questions. One might consider exposing these as resources too but that would unnecessarily couple the API to the database structure, causing difficulties later when the database is refactored. Instead the relationship between sections and questions is captured via the representation of a section as will be shown later.

Resource Identifiers

Each resource is identified by a uniform resource identifier (URI) that is also a uniform resource locator (URL) that can be dereferenced to obtain a representation of that resource. Each of the identified resources have a separate existence and their identifiers are not scoped to any other resource so each is assigned a top level URL as follows:

  • https://sdp-v.services.cdc.gov/api/questions/{id} where {id} represents the unique component of the URI for a particular question
  • https://sdp-v.services.cdc.gov/api/valueSets/{id}
  • https://sdp-v.services.cdc.gov/api/sections/{id}
  • https://sdp-v.services.cdc.gov/api/surveys/{id}
  • https://sdp-v.services.cdc.gov/api/programs/{id}
  • https://sdp-v.services.cdc.gov/api/systems/{id}

If sections were not re-usable by multiple surveys it might be tempting to identify them using a hierarchical URI such as https://sdp-v.services.cdc.gov/api/surveys/{survey_id}/sections/{section_id}.

In addition to identifying resources that refer to specific instances, it is often useful to identify similar or related sets of resources. SDP-V also supports the following identifiers:

  • https://sdp-v.services.cdc.gov/api/questions
  • https://sdp-v.services.cdc.gov/api/valueSets
  • https://sdp-v.services.cdc.gov/api/sections
  • https://sdp-v.services.cdc.gov/api/surveys
  • https://sdp-v.services.cdc.gov/api/programs
  • https://sdp-v.services.cdc.gov/api/systems

Each of these URIs identifies a set of the same type of resources and can be used to obtain a representation of a list of resources of that type. The Request section describes additional URI components that can be used to filter the set of resource representations included in the list.

Representations

SDP-V uses JSON as the basis for its resource representations. Contrary to the API guidance it does not currently define a specific media type such as application/vnd.gov.cdc.sdpv+json but instead uses the generic application/json media type. This is unfortunate but could be rectified in a future release of the service that supports both application/json for current clients and a new, more specific, media type for future clients or new versions of existing clients.

Below is the abreviated representation of a section identified by the URI https://sdp-v.services.cdc.gov/api/sections/S-101 (omissions are indicated by ...):

Example representation of a section
{
  ...
  "sectionId": "S-101",
  "sectionName": "Complications Repeating Group",
  "sectionUri": "/api/sections/S-101?version=1",
  "version": 1,
  "published_by": {
    "id": 11,
    "email": "ikk1@cdc.gov",
    "created_at": "2017-12-18T17:16:14.159Z",
    "updated_at": "2018-08-30T18:13:03.465Z",
    ...
  },
  "tags": [
    {
      "code": "Pilot-test Mumps v1.0",
      "codeSystem": "",
      "displayName": "MMG Name"
    },
    ...
  ],
  "nested_items": [
    {
      "question": {
        "questionId": "Q-1167",
        "questionText": "Type of Complication",
        "questionUri": "/api/questions/Q-1167?version=1",
        "version": 1,
        "published_by": {
          "id": 11,
          "email": "ikk1@cdc.gov",
          "created_at": "2017-12-18T17:16:14.159Z",
          "updated_at": "2018-08-30T18:13:03.465Z",
          ...
        },
        ...
        "responseType": "Choice",
        "tags": [
          {
            "code": "67187-5",
            "codeSystem": "LN",
            "displayName": "Data Element Identifier"
          }
        ]
      },
      "response": {
        "url": "/api/valueSets/RS-2753?version=2",
        "id": "RS-2753",
        "identifier": [
          {
            "system": "urn:ietf:rfc:3986",
            "value": "urn:oid:2.16.840.1.114222.4.11.7474"
          }
        ],
        "version": 2,
        "name": "Type of Complication (VZ)",
        "status": null,
        "description": "Update based on new MMG guide",
        "publisher": "PHIN_VADS",
        "expansion": {
          ...
          "contains": [
            {
              "system": "2.16.840.1.113883.6.96",
              "code": "186509002",
              "display": "Postvaricella encephalitis (disorder)"
            },
            {
              "system": "2.16.840.1.113883.6.96",
              "code": "233604007",
              "display": "Pneumonia (disorder)"
            },
            ...
          ]
        },
        ...
      },
      ...
    },
    ...
  ]
}

Items of note:

  • While the URI used to obtain the section representation (https://sdp-v.services.cdc.gov/api/sections/S-101) did not include a version qualifier, the returned representation includes a canoncial identifier that does (/api/sections/S-101?version=1). While version 1 is the latest version of this section, the two URIs are equivalent but if a new version of the section is created the URI without the version qualifier will refer to the new version (a floating reference) while the canonical URI will always reference a version 1 of the section.
  • As per the guidance on HATEOAS, the representation contains links to other resources rather than reuiring clients to construct their own URIs based on knowledge of the URI structure used by the service, e.g. /api/questions/Q-1167?version=1 identifies one of the questions included in the section.
  • The section representation includes detailed information about the other resources that are linked to it (e.g. the question), this allows clients to get all the information they need in a single request rather than having to get the section then make additional requests to get information about questions included in the section.

Requests

The SDP-V API is currently read-only so all requests use the GET HTTP method. As described above, individual resource URIs support a version qualifier as a URI query parameter. Collection resources (e.g. https://sdp-v.services.cdc.gov/api/sections) also support qualifiers:

  • limit which limits the number of returned sections, defaults to 100 if no search parameter is supplied, infinity otherwise
  • search which limits the returned sections to those that contain the supplied text in their name, description or tags

E.g. the URI https://sdp-v.services.cdc.gov/api/sections?limit=5&search=complications would return a JSON array of a maximum of 5 section representations, each of which include the word 'complications' in their name, description or tags.

Versioning

For some time, SDP-V supported tagging of various resources with coded concepts. These tags are included in resource representations as JSON arrays of objects, one object per tag, e.g.:

Existing Tag Representation
"tags": [
      {
        "code": "36989005",
        "system": "SCT",
        "display": "Mumps (disorder)"
      },
      {
        "code": "",
        "system": "",
        "display": "disease"
      }
    ]

In practice, users would include both coded concept tags but also simple string tags as shown above. End users and API clients requested that the two different usages be separated into a simpler string-based tagging system and a restructuring of the existing representation of coded concept tagging, ideally along the following lines:

Desired Tag Representation
"tags": [
      "mumps",
      "disease"
    ],
    "code_system_mapping": [
      {
        "code": "36989005",
        "system": "http://snomed.info/sct",
        "systemVersion": "20180926",
        "systemDisplayName": "SNOMED-CT",
        "displayName": "Mumps (disorder)"
      }
    ]

This kind of restructuring would represent a breaking change to the SDP-V API: API clients created prior to the change that were using the tags field of resource representations would encounter issues parsing the new structure. The following subsections describe each of the options that were considered and the approach that was decided upon.

Breaking Change

SDP-V is a relatively new service and there are only a few known API clients whose owners were requesting the breaking change described above.

Pros:

  • Users requesting the change could be provided exactly what they requested
  • No need to maintain two versions of the API (old and new representations)

Cons:

  • Existing clients using the tags feature of the API would be broken
  • The SDP-V team does not have a complete list of all existing clients so would be unable to notify owners of the change

Custom Media Type

SDP-V could use media type versioning to maintain the existing resource representation for existing clients and offer a new representation to new clients. SDP-V would default to using the existing representation unless the client requests the new representation using a HTTP Accept header that includes the new media type.

Pros:

  • Users requesting the change could be provided exactly what they requested
  • Existing clients would not be impacted

Cons:

  • Need to maintain two versions of the API (old and new representations)
  • Slightly more complex for new clients since they would need to include an HTTP Accept header in all requests

Non-breaking Change

SDP-V could add the new fields to the existing representation, renaming the new string-based tags field to avoid a name clash with the existing tags field. The representation would then include the following:

Selected Tag Representation
"tags": [
      {
        "code": "36989005",
        "system": "SCT",
        "display": "Mumps (disorder)"
      },
      {
        "code": "",
        "system": "",
        "display": "disease"
      }
    ],
    "simple_tags": [
      "mumps",
      "disease"
    ],
    "code_system_mapping": [
      {
        "code": "36989005",
        "system": "http://snomed.info/sct",
        "systemVersion": "20180926",
        "systemDisplayName": "SNOMED-CT",
        "displayName": "Mumps (disorder)"
      }
    ]

Pros:

  • Users requesting the change could be provided the structure they requested, though with a different field name for the string-based tags
  • Existing clients would not be impacted
  • No need to maintain two versions of the API (old and new representations)

Cons:

  • Tagging information is duplicated in two fields

This option was selected as the best balance of pros and cons.

API Definition

The SDP-V API is described using the Open API specification as recommended in the API guidance. An interactive page for exercising the API is provided using the Swagger tooling, the machine processable description is available at https://sdp-v.services.cdc.gov/api/vocab.yaml.