Open pvdbosch opened 1 year ago
Zalando's guideline MAY expose compound keys as resource identifiers on this topic is not very clear to me.
Examples both with slashes as colon as separator. When using slash, should the parent path also resolve? Should the OpenAPI spec specify all compound key components separately but clients should use them as a whole to allow evolvability? Why not make them entirely opaque then by not documenting how it splits in components?
Note: Exposing a compound key as described above limits ability to evolve the structure of the resource identifier as it is no longer opaque. To compensate for this drawback, APIs must apply a compound key abstraction consistently in all requests and responses parameters and attributes allowing consumers to treat these as technical resource identifier replacement. The use of independent compound key components must be limited to search and creation requests, as follows ...
Axway now supports colon separators in resource paths from SP Aug23 and using patch API Gateway 7.7.20230228 Patch 30438 (allOS) so the platform is ready to support it.
e.g. /reports/{year}:{month}
The composite identifier is still 1 path segment respecting our design of document resource. Using slashes the identifier would be spread into multiple path segments.
Guidelines we may consider:
Context: the identity/uniqueness of a resource is determined by the combination of multiple immutable properties
design options:
composite identifier = identifier composed from multiple property values, e.g. {employeeId}:{month}
0) Introduce new resource identifier which is not composite: +: clients cannot do string manipulation +: stable when the business rules around uniqueness change -: two-step lookup -: new identifier values have to be generated and managed, with checks that the properties are still unique
1) Opaque composite identifier: the business identifier is technically composed from multiple values, but this is undocumented and opaque when using the API.
request :
/declarations?employeeId=12345&month=2024-12
response:
{
"items": [ {
"id": "12345:2024-12" # "type: string"
"employeeId": 12345,
"month": "2024-12"
}
]
}
Once id is found, it can be used in direct resource lookup:
GET /declarations/12345:2024-12 # /declarations/{declarationId}
{
"id": "12345:2024-12" # "type: string"
"employeeId": 12345,
"month": "2024-12"
}
+: adaptable when the business rules around uniqueness/identity change +-: clients might do string manipulation which would prevent evolvability, but unlikely if not documented -: two-step lookup
2) Partially opaque composite key: composition is documented only for the document resource URL:
request: /declarations/{employeeId}:{month} /declarations/12345:2024-12
response:
{
"id": "12345:2024-12"
"employeeId": 12345,
"month": "2024-12"
}
-: not adaptable when the business rules around uniqueness/identity change +: no two-step lookup of resource
3) Non-opaque key parts: only the individual components are documented and used
request
/declarations/{employeeId}:{month} /declarations/12345:2024-12
response:
{
"employeeId": 12345,
"month": "2024-12"
}
-: not adaptable when the business rules around uniqueness/identity change +: no two-step lookup of resource -: more complex identity checks bc no single identifier string
alternative representation: matrix-style parameters
Matrix-style parameters might be useful when there are multiple parts that can be optionally chosen from, e.g.
GET /actors/;enterpriseNumber=1234
GET /actors/;ssin=123456789
Alternative in path-param style:
GET /actors/enterpriseNumber:1234
WG:
For next WG, I'll work out some alternatives regarding to (non/partially/fully) opaque identifiers and matrix parameters.
On matrix params:
From https://www.w3.org/DesignIssues/MatrixURIs.html:
Just as the slash separated set of elements is useful for representing a tree, so a set of names and equally significant parameter can represent a space more like a (possible sparse) matrix. In this case navigation to "close" locations is done by varying one or more parameters which form the dimensions of the matrix. This is the purpose of the a=b; parts of URL syntax which was added later in the URL's history.
REST API designers sometimes struggle to represent resources that are defined by a composite business key with a proper URI.
E.g. in case of a monthly declaration of a an employer about an employee, these are possible:
1) /employers/{employerId}/employees/{employeeId}/declarations/{month}
2) /declarations/{employerId}-{employeeId}-{month}
3) /declarations/{delcarationId}
/declarations?employer=...&employee=...month=... should be used to retrieve declarationId
declarationId may be formed as the same composite key as 2 under the hood, but this is not part of the contract
Current documentation (not a rule): https://www.belgif.be/specification/rest/api-guide/#document
When defining child resources, stick to concepts within the same API. An employer resource could contain child concepts as employees, debts, taxes, mandates, declarations, risks, but putting all these different concepts below a single document resource becomes unmanageable. In that case prefer associations and create [links](https://www.belgif.be/specification/rest/api-guide/#links) to other APIs from the employer resource.