API Extensions

An API Extension augments an OpenAPI definition with semantic information designed to improve the automatic generation of test cases. Extensions are used primarily by the AutoTest assistant to refine its randomly-generated test cases, but have wider applicability.

An extension comes in two parts:

  • Resources identify the key resource types managed by the API, and their methods
  • Properties attach semantic categories to schema properties, to constrain the format of values suggested for those fields

An extension is associated with a specific OpenAPI document and uses JSON Pointer notation to locate terms in that document.

Resources

The resources section contains a set of resource definitions, where each definition contains at least the following:

  • a name for the resource
  • a pointer to a schema of type object that models the resource
  • a collection of methods that operate on the resource

Typically, a resource definition also identifies a field within the schema that stores a unique identifier for instances of that type.

For example, consider this extract from an API extension:

resources:
  Book:
    schemas:
      primary:
        json_ptr: '#/definitions/Book'
    properties:
      id_name: '$.book_id'
    operations:
      create:
        - json_ptr: '#/paths/~1books/post'
      retrieve:
        - json_ptr: '#/paths/~1books~1{book_id}/get'
        - json_ptr: '#/paths/~1books/get'
      update:
        - json_ptr: '#/paths/~1books~1{book_id}/put'
      delete:
        - json_ptr: '#/paths/~1books~1{book_id}/delete'

The resources section contains a single resource definition with the following properties:

  • it defines a resource named Book
  • a book is modeled by a schema of the same name located in the OpenAPI document under definitions
  • each book has a property book_id that holds its unique ID
  • there are operations defined in the OpenAPI document under paths that create, retrieve, update and delete books

The correspondence between the resource name and the schema name is common but not required: a resource name can be anything, as long as it is unique within the API.

The unique ID field for a book is identified by a simplified form of JSON Path expression that locates a property (book_id) within the primary schema.

Operations (or methods) on a resource are grouped by category:

  • Create
  • Retrieve
  • Update
  • Delete

There can be multiple operations in each. In this example there are two operations that retrieve books: one that returns a single book by ID, and another that returns a list of books, and this is common. A different definition might have patch as well as (or instead of) put under update.

JSON Pointer expressions in a resource definition all refer implicitly to the associated OpenAPI document, so the prefix # introduces a relative location within that document. JSON Pointer syntax uses the string ~1 to stand for a forward slash character (/) to prevent confusion with the same character used as a separator, so the operation defined in the OpenAPI document by the term:

paths:
  /books/{book_id}:
    get:

is identified here by the JSON Pointer:

#/paths/~1books~1{book_id}/get

Dependencies

A resource definition may also describe a dependency from one resource type to another.

For example:

  Order:
    schemas:
      primary:
        json_ptr: '#/definitions/Order'
    properties:
      id_name: '$.order_id'
    dependencies:
      - name: Book
        required: true
        references:
          - name: $.book_id
            in: body
        dependee_deletion: disabled
      - name: Customer
        required: true
        references:
          - name: customer_id
            in: path
        dependee_deletion: mutual
    operations:
      create:
        - json_ptr: '#/paths/~1customers~1{customer_id}~1orders~1{order_id}/post'
      # rest omitted for brevity

This definition says that the resource Order has dependencies on two other resources Customer and Book (which must be defined in the same extension).

Both dependencies are required in the sense that an order cannot exist unless there is a customer (to place the order) and at least one book (to buy).

An order refers to an existing book through the property book_id in the primary schema, and to a customer through the path parameter customer_id, as in the create method shown (and in other methods omitted).

A customer owns a set of orders; this is a hierarchical relationship implicit in the path:

/customer/{customer_id}/orders/{order_id}

When a customer is deleted, all their orders are also deleted, and this behavior is indicated by the mutual value of the deletion property.

A different relationship applies to books: a book cannot be deleted until all the orders which refer to it have been deleted, so deletion is indicated as disabled in that case.

There are three possible values for the dependee_deletion property:

  • enabled: a referenced resource can be deleted even while dependent resources that refer to it still exist
  • disabled: a referenced resource cannot be deleted until all dependent resources that refer to it have been deleted
  • mutual: deleting a referenced resource deletes all the dependent resources that refer to it: this is typical where the dependent is owned by or contained in the referent

Pure resources

A pure resource is one that has no instances, or at least no instances that can be tracked with unique IDs, and is used as a placeholder for operations that do not behave as resource methods.

A pure resource differs from a standard resource in the following ways:

  • it has no ID field (because there are no instances)
  • dependencies have no dependee_deletion (for the same reason)
  • all operations are grouped under a single pure category

For example:

ServiceAvailability:
  schemas:
    primary:
      json_ptr: '#/definitions/ServiceAvailability'
    operations:
      pure:
        - json_ptr: '#/paths/~1service~1status/get'

ServiceAvailability is a type that is returned as the result of a service status request but has no unique, persistent state.

Properties

The properties section assigns semantic categories to schema properties occurring in operation payloads, to constrain the range of values interpolated into generated request bodies.

For example:

properties:
  - json_ptr: '#/definitions/CardPayment'
    items:
      - name: card_number
        semantic: credit_card_number
      - name: expiry_date
        semantic: expiry
      - name: security_code
        semantic: cvv

The JSON Pointer expression locates a schema named CardPayment in the API document under definitions; the schema must have object type with at least the properties card_number, expiry_date and security_code which are specified here to have particular semantics that will guide the auto-generation of appropriate values wherever a CardPayment occurs in a request payload.

Semantic categories must be drawn from the following set:

address                 cvv                     latitude                state_code
age                     date                    longitude               street
area_code               domain                  minutes                 temperature
birthday                email                   month                   time
certificate             expiry                  name                    timestamp
charset                 first_name              number                  token
cidr                    gender                  paragraph               twitter
city                    geo_location            percentage              url
color                   hours                   phone                   user_agent
content_encoding        humidity                phone_number            username
content_type            iban                    prefix                  uuid
coordinates             id                      pressure                version
country                 identity_provider       price                   year
country_code            ip_address              revision                zip_code
credit_card_number      language                sentence
currency                language_code           social_security_number
currency_code           last_name               state