This Annex provides information about the changes in the API that are considered as backwards compatible and those that are considered as backwards incompatible. This list is to be considered informative and it may be expanded in future releases, when necessary.
Backward compatible changes are additions or changes in the API that do not break the existing Service Consumer behaviour. Examples of backward compatible changes include:
Adding a new, optional child resource/URI;
Supporting a new HTTP method;
Adding new elements to a resource representation;
Changing the order of fields in a resource representation;
Addition of a new status code:
Corrections of obvious errors in an OpenAPI file required to enable a correct parsing of the file such as misspelled references;
Corrections that only relate to smaller and optional parts of the functionality (e.g. a supported feature, see TS 29.500, clause 6.6.2), even if the changes are backward incompatible with respect to that part of the functionality; and
Backward-compatible changes related to the semantics (i.e. functional behaviour) specified for an API.
Changes in the API that do not result in any loss of existing functionality (i.e. functionality that works fine if both consumer and provider do not support the change) if only consumer or only provider implements the change can be considered as backwards compatible corrections or additions.
Backward incompatible changes are additions or changes in the API that break the existing Service Consumer behaviour. Here is a list of backward incompatible changes that shall require incrementing the 1st field (MAJOR) of the API version number unless they only relate to smaller and optional parts of the functionality (see above):
Removing a resource/URI:
Removing support for an HTTP method;
Renaming a field in a resource representation;
Adding mandatory parameters to a resource URI or resource representation;
Attribute data type changes;
Cardinality changes (NOTE 3); and
Backward incompatible changes related to the semantics (i.e. functional behaviour) specified for an API.
Changes in the API that result in loss of existing functionality (i.e. functionality that works fine if both consumer and provider do not support the change) if only consumer or only provider implements the change can be considered as backwards incompatible modifications.
When a change although being categorised as backwards compatible correction or addition results in interoperability issues, it is expected that the issue will be resolved by implementing the change at both consumer and provider.
When designing an API, one shall first think of defining the set of resources consumed. Resources represent objects that are modified by standard HTTP methods and that can be modelled with one of 4 archetypes detailed below. Resource archetypes help API designers to structure the resources. In this process the designer should refer to the appropriate archetype when the resource definition perfectly matches the archetype one. Referring to an archetype immediately defines what operations and HTTP methods are supported by the resource.
The archetypes provided hereafter don't preclude the existence of resources of different types.
The document archetype is the conceptual base archetype of the other ones. Any resource that is not identified with one of the other resource archetypes is a document.
A document may have child resources that represent its specific subordinate concepts.
The archetype does not place any restriction on HTTP methods when acting on a document.
Only CRUD operations are performed directly on a document resource, i.e. by sending an HTTP request to the URI of that resource. Custom methods are not performed directly on the resource, but by sending an HTTP request to a URI that is associated by a convention with the URI of the resource.
The collection archetype can be used to model a resource that serves as a directory of resources. A collection is NF Service Provider-managed so the NF Service Provider decides the URIs of each resource that is created in the collection.
The Create and Read operations are performed on a collection directly.
More specifically:
A collection child resource is created by sending a POST with the collection URI if accepted by the collection;
A collection is read by sending a GET with the collection URI;
The PUT and PATCH methods with the collection URI are not allowed;
The DELETE method with the collection URI is only allowed if the collection resource has been created dynamically based on a request from the NF Service Consumer.
The authorized operations on a collection child resource depend on that resource's archetype.
The store archetype can also be used to model a resource that serves as a directory of resources but a store is NF Service Consumer-managed. The NF Service Consumer solely decides what resource shall be added to / deleted from a store. The NF Service Consumer decides what the URI of the added resource is.
The Read operation is performed on a store directly, and the Create operation is performed on store child resources.
More specifically:
A store child resource is created by sending a PUT with the URI of the child resource to be created.
A store is read by sending a GET with the store URI;
The POST, PUT and PATCH methods with the store URI are not allowed;
The DELETE method with the store URI is only allowed if the store resource has been created dynamically based on a request from the NF Service Consumer.
Apart from Create (PUT), the authorized operations on a store child resource depend on that resource's archetype.
The custom operation archetype can be used to model an unsafe and non-idempotent operation that is not a Create on a collection.
A custom operation does not operate directly on the resource that would be identified by the custom operation URI. Instead, when the custom operation is associated with a resource, the operation is performed on this associated resource. For instance, a custom operation may modify the associated resource in a special way. This associated resource is identified by stripping the suffix string "/<custOpName>" from the custom operation URI template in clause 4.4.2.
When the custom operation is not associated with any resource but with the service, it acts as an executable function with input parameters and returns the result of the executed function in the response body, not modifying any resource.
POST is the only method allowed with a custom operation URI.
The semantic of the custom operation is encoded in the last segment of the URI template in clause 4.4.2: /{custOpName}.
As described in clause 4.6.1.1.3.2, the bodies of HTTP PATCH requests will either use a "JSON Merge Patch" encoding as defined in RFC 7396, or a "JSON Patch" encoding as defined RFC 6902. This Annex provides an example OpenAPI Specification [4] allowing both encodings.
openapi: 3.0.0
info:
version: "1.0.0"
title: PATCH Example
paths:
/inventory:
post:
summary: adds an inventory item
operationId: addInventory
description: Adds an item to the system
responses:
'201':
description: item created
'400':
description: 'invalid input, object invalid'
'409':
description: an existing item already exists
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/InventoryItem'
description: Inventory item to add
/inventory/{id}:
get:
summary: read inventory item
parameters:
- name: id
in: path
required: true
schema:
type: integer
responses:
'200':
description: search results matching criteria
content:
application/json:
schema:
$ref: '#/components/schemas/InventoryItem'
'400':
description: bad input parameter
patch:
summary: patch inventory item
parameters:
- name: id
in: path
required: true
schema:
type: integer
requestBody:
required: true
content:
application/json-patch+json:
schema:
$ref: '#/components/schemas/PatchInventoryItem'
application/merge-patch+json:
schema:
$ref: '#/components/schemas/MergePatchInventoryItem'
responses:
'200':
description: Patch was succesfull and updated Inventory Item is returned.
content:
application/json:
schema:
$ref: '#/components/schemas/InventoryItem'
'204':
description: Patch was succesfull
'400':
description: bad input parameter
components:
schemas:
InventoryItem:
type: object
required:
- name
- manufacturer
properties:
id:
type: integer
name:
type: string
manufacturer:
$ref: '#/components/schemas/Manufacturer'
customers:
type: array
items:
type: string
Manufacturer:
type: object
required:
- name
properties:
name:
type: string
homePage:
type: string
format: url
phone:
type: string
PatchInventoryItem:
type: array
description: A JSON PATCH body schema to Patch selected parts of an Inventory Item
items:
anyOf:
- oneOf:
- type: object
description: Modifies the URL of a Manufacturer
properties:
op:
type: string
enum:
- "add"
- "remove"
- "replace"
path:
type: string
pattern: '^\/manufacturer\/homePage$'
value:
type: string
format: url
required:
- "op"
- "path"
- type: object
description: Modifies a Manufacturer
properties:
op:
type: string
enum:
- "replace"
path:
type: string
pattern: '^\/manufacturer$'
value:
$ref: '#/components/schemas/Manufacturer'
required:
- "op"
- "path"
- "value"
- type: object
description: Modifies a Customer
properties:
op:
type: string
enum:
- "add"
- "remove"
- "replace"
path:
type: string
pattern: '^\/customers\/(-|\d+)$'
value:
type: string
required:
- "op"
- "path"
- type: object
description: Open Alternative
minItems: 1
MergePatchInventoryItem:
description: A JSON Merge PATCH body schema to Patch selected parts of an Inventory Item
type: object
properties:
manufacturer:
$ref: '#/components/schemas/Manufacturer'
nullable: true
customers:
type: array
description: Allows to replace the entire array, but not to modify individual elements.
items:
type: string
This Annex provides guidelines on the use of JSON arrays on the SBI APIs of the 5GC.
As described in clause 5.2.4, the data model of an API definition in a 5GC API consists of any of the different data types supported by OpenAPI, corresponding to the different data structures found in the JSON data format. One of these structures is the "array", representing a set of ordered values.
It should be noted that, while JSON allows that the value of the elements of an array may be of different types, in OpenAPI Specification [4] this is further restricted, and all elements of an array shall be of the same type.
Also, it is important to note that the JSON format itself, as specified in RFC 8259, does not define any syntax to refer to specific array elements.
However, there are certain conventions to specify mechanism to refer to array elements, e.g. based on the position a given element has in the array.
In particular, the JSON Pointer syntax defines a string syntax for identifying a specific value within a JSON document. This syntax consists of a number of tokens separated by the "/" character; in order to refer to a specific element in an array, then token shall contain an unsigned decimal value, indicating the zero-based index of the element in the array.
EXAMPLE:
JSON Pointer expression "/attr3/0" evaluated on such JSON document: 1
There are several scenarios, frequently employed in the 5GC APIs, that make use of the JSON Pointer mechanism to refer to specific elements in an array:
Update of resources using the PATCH method, as described in clause 4.6.1.1.3.2. If the syntax used in the PATCH request payload is based on the "JSON Patch" format, then the JSON Pointer mechanism is used to specify patch operations applied to specific array elements.
Notifications of events (such as data changes), as described in clause 4.6.2.3, using as notification payload the notation defined in "NotifyItem" / "ChangeItem" data types defined in TS 29.571. This notation is similar to "JSON Patch", so it also makes use of the JSON Pointer syntax to refer to specific array elements.
Explicit usage of attributes containing JSON Pointer expressions in request or response payloads.
In these scenarios, it is critical that any JSON Pointer expression is applied by both client and server on the exact same array representation, since otherwise the indexes may vary, and the JSON Pointer will give unexpected results.
A typical scenario that may create issues could be as follows:
NF Service Consumer sends a first GET request towards a NF Service Producer, including certain query parameters in the HTTP request, that result into retrieving a resource representation that contains a subset of the data that the NF Service Producer holds under such resource. When such subset refers to returning just some of the elements of an array, rather than the entire array, then the content of the array will differ between consumer and producer.
The NF Service Consumer sends a subsequent PATCH request towards the NF Service Producer, with the intention to modify a given element of the array (specified by the array index, per the JSON Pointer syntax). This results into the server modifying a wrong element in the array, given that the NF Service Producer contains a different array.
The NF Service Consumer may subscribe to be notified by the NF Service Producer when a given resource representation has changed. When the NF Service Producer detects such a change, it sends a notification that may include a reference to an array index, which may be different than the array index kept by the NF Service Producer.
The NF Service Consumer is a stateless NF Service Consumer that has no local representation of the array that subscribes to be notified by the NF Service Producer when a given resource representation has changed.
Another scenario that may lead to incorrect array updates is:
A first NF Service Consumer NF1 sends a PATCH request towards the NF Service Producer, with the intention to delete a given element of the array (specified by the array index, per the JSON Pointer syntax). This results in some of the array indexes being changed (of those elements placed after the deleted element)
A second NF Service Consumer NF2, sends another PATCH request towards the NF Service Producer, to modify any of the elements of the array whose index was affected by the previous operation done by NF1. This results in modifying unintendedly the wrong array element.
The design of 5GC SBI APIs should take into account these scenarios and provide mechanisms to avoid unintended modifications of array elements, when they are referred by their position index in the array.
To achieve these, both NF Service Consumer and Producer (taking the role of HTTP client and server) should ensure that any resource update takes place on a known and current resource representation, based on the content of ETag values sent along with resource representations by the resource owner.
If an NF Service Consumer needs to cache a resource representation received from an NF Service Producer (i.e. the JSON information received in an HTTP response message), it shall use the exact same representation of arrays as received from the service producer.
When sending notifications or modifications whose semantics is based on the JSON Pointer syntax, the sending NF shall use the exact same representation of arrays as previously signalled in a previous interaction with the receiver of such notifications/modifications.Further, when sending notifications whose semantics is based on the JSON Pointer syntax, if the NF Service Consumer is a stateless NF Service Consumer and thus has no local representation of the array, the NF Producer shall use the complete replacement array representation as the NF Service Consumer is otherwise required to request the complete data from the NF Service Producer with a GET request.