University API Standard

Version 1.0

The University API Standard is licensed under The Apache License, Version 2.0.

Introduction


The University API Standard defines the technical structure recommended when designing and implementing an API in the University API URL namespace (api.byu.edu/byuapi), or in the namespace of a specific domain (e.g., api.byu.edu/domains/erp). The University API Standard specifically addresses URL design, HTTP method selection and use, and structural representations of the recommended mime-type (application/json), including the use of a custom HATEOAS link design pattern to convey available operations and state transitions. These standards will provide consistency for both on-campus and external consumers of APIs.

Terms


HTTP

Hypertext Transfer Protocol

REST

Representational State Transfer

Resource

A domain-model object that has a structural representation and set of allowable HTTP methods.

Representation

The structure of a domain-model object in the context of a specified mime-type. A representation is what is returned in response to a request or what is submitted in the body of a request.

Attribute

Key/value pairs defined in a representation.

HATEOAS

Hypermedia As The Engine Of Application State

Contract

A published definition of a resource, its associated representation and URL design (constituting an API) that consumers rely upon.

URL Design


To adhere to this standard, URL design should follow the patterns:

namespace/resource/identifier
namespace/top-level-resource/top-level-resource-identifier/sub-resource/sub-resource-identifier

The simplest pattern listed first conveys the convention of defining a namespace, identifying a resource (or resources), and specifying the type and form of the identifier of the resource. The following documentation will detail the second listed pattern that defines the BYU Standard implementation of namespace, resource, top-level resource, sub-resource, and identifier.

Namespace

BYU APIs are segregated into two distinct categories: the University API and Domain APIs. The University API represents the collaborative product of common Domain APIs addressing common business use cases. Following the Domain Driven Design philosophy, Domain APIs are produced and managed by identified domains within the University. The differences between the University API and Domain APIs are detailed on this reference page. Both the University API and Domain APIs have distinct namespaces.

The namespace designated for the University API is:

https://api.byu.edu/byuapi

The namespace designated for Domain APIs is:

https://api.byu.edu/domains/{domain_name}

The domain_name portion of the Domain API namespace is determined by the domain team. For example, if a domain team had chosen the domain_name "identity," its namespace would be:

https://api.byu.edu/domains/identity

Resource

The resource portion of the URL design represents a category of data or domain model entity managed by the API. For example, the resource "identities" contains all data related to a University identity; the resource "identities" represents a collection of identities and any data related to that collection of identities.

Examples of URLs pointing to resources are:

University API:

https://api.byu.edu/byuapi/identities

Domain API:

https://api.byu.edu/domains/identity/identities

If the resource represents a collection of data (meaning that, if you invoke an HTTP GET method against the resource, it returns a collection, set, or list of that defined resource), then it must be written in the plural form, i.e. identities rather than identity.

Top-level Resources

Resources are "top-level" resources if they are the first resource under the namespace in which they are found.

Examples of URLs pointing to a top-level resource are:

University API:

https://api.byu.edu/byuapi/identities

The resource "identities" is the first resource after the University API namespace (byuapi).

Domain API:

https://api.byu.edu/domains/identity/identities

The resource "identities" is the first resource after the "identity" domain namespace.

Resource Identifier

If a resource represents a collection of data, an item in that resource collection should also be addressable in the API URL.

Examples of URLs pointing to the addressable form of an item in a collection of resources are:

University API:

https://api.byu.edu/byuapi/identities/{identifier_key}
https://api.byu.edu/byuapi/identities/123456789

Domain API:

https://api.byu.edu/byu.edu/domains/identity/identities/{identifier_key}
https://api.byu.edu/byu.edu/domains/identity/identities/123456789

The identifier value "123456789" is the key of an item in the collection resource "identities". If you were to invoke an HTTP GET method against the example URL "https://api.byu.edu/identities/123456789", the result would be the structural representation of a single "identity" item that at least contains the identifier key "123456789".

Note: If a resource is not a collection, the plural form of the resource name is still used to represent the resource in the URL, but there is no need to include an identifier in the URL or in the resource representation that is returned. Simply calling the resource URL will return all relevant information because there is only one resource.

Resource Composite Identifier

Some resources must be identified using a composite identifier. A composite identifier uniquely identifies a resource by multiple pieces of information instead of just one.

Composite identifiers should conform to the pattern:

namespace/resource/{key}[,{additional_keys}]

Examples of URLs pointing to composite resources are:

University API:

https://api.byu.edu/byuapi/classes/Fall+2016,MATH+110,001

Domain API:

https://api.byu.edu/byu.edu/domains/class_schedule/classes/20165,06387,001,001

Note: In the URL, use '+' to designate white space and ',' as a composite key delimiter. The symbol "+" (plus sign)  is a standard URL special character used in place of a single white space. The symbol "," (comma) is the University API Standard character indicating separation between two parts of a composite key. 

Sub-resources

Resources are "sub-resources" if they fall under a top-level resource in the URL path structure.

Examples of URLs pointing to sub-resources are:

University API:

https://api.byu.edu/byuapi/identities/123456789/addresses
https://api.byu.edu/byuapi/identities/123456789/classes

The resources "addresses" and "classes" fall under the top-level resource "identities." The sub-resource "classes," being a collection, will require a sub-resource identifier. The sub-resource "addresses", assuming it is not a collection of resources, will not have a sub-resource identifier.

https://api.byu.edu/byuapi/identities/123456789/classes/Fall+2016,MATH+110,001

Domain API:

https://api.byu.edu/domains/identity/identities/123456789/addresses
https://api.byu.edu/domains/identity/identities/123456789/classes

The resources "addresses" and "classes" fall under the top-level resource "identities." The sub-resource "classes," being a collection, will require a sub-level-resource identifier. The sub-resource "addresses", assuming it is not a collection of resources, will not have a sub-resource identifier.

https://api.byu.edu/domains/identity/identities/123456789/classes/20165,06387,001,001

Note: Simplify the options on the URL segments and do not allow redundant URL paths. Although there may be multiple ways to logically represent a specific resource in your URL design, you should only allow for one option in your code. This simplifies things for the consumer and provides a better experience overall. For example, you might think of multiple ways in the URL design to access a resource "classes":

  • teaching area and catalog number

    https://api.byu.edu/domains/curriculum/courses/MATH+110
  • curriculum_id and title_code

    https://api.byu.edu/domains/curriculum/courses/06387,001

When faced with different options of URL resource identifiers to choose from, you must choose to implement only one of the options on the URL path. The other option(s) could be implemented as query parameters to filter on the collection of resources. For example:

https://api.byu.edu/domains/curriculum/courses?curriculum_code=06387&title_code=001

Note: The teaching area and catalog number are commonly represented as text separated by a space. This example decided to represent those combinations as a single identifier (not a composite identifier) but separated by a space in that identifier value.

Resource Representation


The aggregated properties of a resource combine to define the representation of a resource. The resource representation is provided as the response to HTTP GET requests or as input to HTTP PUT or POST requests. The University API Standard recommends the default mime-type for the structure of a representation to be "application/json". This section of the University API Standard defines the patterns in designing representations for API resources:

The following are root level properties for a non-collection resource representation

  • links
  • metadata
  • properties
{
  "links": {},
  "metadata": {},
  "property_1": {},
  "property_2": {}
}

The following are root level properties for a collection of resources representation

  • links
  • metadata
  • values
{
  "links": {},
  "metadata": {},
  "values": []
}

It is important to note that the API contract defined by the resource representation is associated to the URL resource name and not by any URL segments added to the resource name, such as query parameters. An example of a consistent resource representation associated with a URL resource would be a call to a specific identity resource:

https://api.byu.edu/byuapi/identities/123456789

The resource representation returned would be:

{
  "link":{},
  "metadata": {},
  "property_1": {}
}

If a call to the resource collection was made with a filtering query parameter,

https://api.byu.edu/byuapi/identities?id=123456789

the resource representation would be for the collection. But each item resource representation in the collection would be the same as a specific identity resource request.

{
  "link":{},
  "metadata": {},
  "values": [
    {
      "link":{},
      "metadata": {},
      "property_1": {}
    }
  ]
}

The "links" property is an object that contains named properties that are patterned after the HATEOAS approach. Our definition and use of a HATEOAS link includes the following properties:

Property Description
rel The rel contains the name of the HATEOAS link or "self" as a special name for the link that you would invoke to get back the resource that was just returned. The value should be in the form of <resource-name>__<action>.
href

The href contains the URL used to perform the HATEOAS link action (this may also be a templated URL according to RFC 6570).

method

The method contains the HTTP method used when invoking the URL in the href property.

 

An example links object for the identities resource collection would look like:

  "links": {
    "identities__info": {
      "rel": "self",
      "href": "https://api.byu.edu/byuapi/identities?page_start=:page_start,page_size=:page_size",
      "method": "GET"
    },
    "identities__prev": {
      "rel": "identities__prev",
      "href": "https://api.byu.edu/byuapi/identities?page_start=:page_start,page_size=:page_size",
      "method": "GET"
    },
    "identities__next": {
      "rel": "identities__next",
      "href": "https://api.byu.edu/byuapi/identities?page_start=:page_start,page_size=:page_size",
      "method": "GET"
    },
    "identities__create": {
      "rel": "identities__create",
      "href": "https://api.byu.edu/byuapi/identities",
      "method": "POST"
    }
  },

Metadata

 

metadata attribute

description

collection_size

The number of items of the resource which exist in the collection. This is not how many were returned in this "page" of the collection.

default_page_size

Unless overridden in query parameters, this endpoint would default to the following "page" size.

max_page_size

The largest "page" size that the implementation of the API will support.

page_size

The number of items which were returned in this "page" of the collection.

page_start

The item of the collection on which the returned "page" of the collection starts

page_end

The item of the collection on which the returned "page" of the collection ends

 

To include metadata information in the answer, modify the standard JSON structure in the following manner:

"metadata": {
  "collection_size": 3,
  "default_page_size": 50,
  "max_page_size": 1000,
  "page_size": 50,
  "page_start": 1,
  "page_end": 3
 }

 

Values

Complex value objects

Tag Name

Description

api_type

Describes how this data attribute may be used in this API. For example, may it be modified. For a list of the possible values for api_type and the rules associated with each value, click here.

description

Explains the data value in human-friendly terms.

display_label

Provides a string to use when creating a label for this property in the user interface if the name of the property is not appropriate (or is too cryptic) to use as a user interface label.

domain

Especially with code values, there is a limited set of allowable codes. This tag contains the URL that can be used to retrieve the set of allowable codes.

"domain": "https://api.byu.edu/byuapi/meta/year_terms"

long_description

Explains the data value in human-friendly terms; contains more information than the (short) description.

related_resource

If the API type is "related" (see next section for more information), this tag will contain the resource-name that "owns" this data attribute. Usually, the resource-name can be used to find a HATEOAS link (the "rel" will be resource-name__info) that can access this data attribute.

value

Contains the data.

 

Example:

"byu_id": {
  "api_type": "system",
  "display_label": "BYU ID",
  "key": true,
  "value": "764634873"
}

 

Rarely will a single data attribute use all of the available tags, but value and api_type will always be included. The possible values of api_type are:

 

api_type

May be modified?

Description

key

Depends on the API

The data attribute is one of the key elements for this resource. This has several implications. First, key fields are required fields - they are not allowed to be blank or null. Second, it is used in the URL segment of the URL to access a specific item in the resource collection. Some resources may not allow a key value to be modified, but they are the exceptions. Refer to the documentation for the API. Some resources may assign the key value when the item is added. Once again, refer to the documentation for the API.

read-only

No

There are instances when this data attribute may be modified, but there are either business rules or authorization considerations that do not allow the data attribute to be changed at this time by this client.

modifiable

Yes

The data attribute may be modified.

derived

No

This is an attribute that was derived by a "calculation" on other data attributes. An example might be GPA. An API will not support the modification of derived data. In our example, to modify a GPA, you would have to modify grades or credit hours on individual classes.

related

No

This means that the data attribute was included in this API to make the API more useful, but it doesn't really belong to this API and the business logic to modify the data attribute exists in the "related_resource". In our example, "owner_name" is a "related" data attribute. We included the owner_name in the Cars API because our business analysis showed that it is always wanted when clients retrieve a list of cars. (Owner_id isn't that useful.) But, a single owner may own dozens of cars and it would not be appropriate to change the owner_name on a single car. Instead the client application is referred to the "owners" API.

system

No

The data value was assigned by the system. If it can be modified, it will be by the system and not through API input. A date-time field that tracks the last time the resource was updated is a good example of a system data attribute.

URL Query Parameters


Query strings are used to filter through a collection, returning all resources whose values match what has been specified. For example, "https://host-name/cars?color=red&make=Ford" returns a JSON array that only contains red Fords. Similarly, "https://host-name/students?major=CS" returns a JSON array that contains only students whose major is Computer Science (CS). 

This is the standard structure of a query string: 

namespace/resource?query-parameter=value
namespace/top-level-resource/top-level-resource-identifier/sub-resource?query-parameter=value

Note: Do not attempt to GET a resource collection using the structure namespace/resource/query-parameter/value (e.g., .../students/major/CS). Such a call does not make sense.

collection parameters

  • page_size
  • page_start
  • page_end

filter parameters

  • identifiers
  • properties

HTTP Methods


The following is a list of recommended HTTP methods to support in an API and the philosophy behind each HTTP method.

HTTP Method

Description

Notes

OPTIONS

Returns the set of http_methods allowed for the URL that addresses a collection

According to HTTP protocol the list of options is returned in an HTTP header with a key name of "Allow". For example, if a URL allows the GET, POST, and OPTIONS methods, the HTTP header would contain "Allow: GET,POST,OPTIONS". Similarly, the University API returns a JSON array in the body of the response
that lists all supported methods. The JSON array looks like this:

{
   "supported_methods": [
     "GET",
     "POST",
     "OPTIONS"
   ]
}

GET

Returns a resource or collection of resources.

Sometimes, a combination of query string filters or URL segments may return only one (or even zero) items. That's okay. Even the empty set is a valid set. In the University API, we have elected to always return a JSON array structure, even when there is only one or zero items returned. This allows the developer to code for a predictable JSON data structure. We don't change the contract of the return body based on the number of items selected.

POST

Creates a new resource. If the resource is part of collection, the request creates a new item in the collection.

In most instances, the body will contain a single item to be added, but the request body may contain a JSON array structure of resource(s) to be created (added). The return body is the item that was added or a JSON array structure that contains information about each resource for which an add attempt was made.

PUT

Modifies the resource or a set of resources in a collection.

While there may be cases where we perform bulk updates, we have tried to avoid them in the University API. Generally, the URL defines a single item instead of a collection, and that single item is modified to "look like" the resource in the request body. The modified resource is generally then returned in the return body. Sub-resources are added and removed by put, not by post or delete.

DELETE

Deletes the resource or collection of resources.

While there may be cases for bulk deletes, we have tried to avoid them in the University API. Since the URL completely defines the resource to be deleted, there is generally no request body or return body for this method.

HTTP Headers


HTTP Header Name

Type

Description

Accept

Request

 

Content-Type

Response

 

Authorization

Request

 

HTTP Status Codes


The following HTTP status codes and the suggested descriptions are the minimal set of status codes to support in an API.

HTTP Status Code

Description

200

Request was successful

400

Request not understood (syntax error)

401

Request not authenticated

403

Request not authorized

500

Server error