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 existdisabled
: a referenced resource cannot be deleted until all dependent resources that refer to it have been deletedmutual
: 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