docs: extend api design with additional information and examples (#9856)

# Which Problems Are Solved

There were some misunderstandings on how different points would be
needed to be applied into existing API definitions.

# How the Problems Are Solved

- Added structure to the API design
- Added points to context information in requests and responses
- Added examples to responses with context information
- Corrected available pagination messages
- Added pagination and filter examples

# Additional Changes

None

# Additional Context

None
This commit is contained in:
Stefan Benz
2025-05-07 10:14:01 +02:00
committed by GitHub
parent 8cb1d24b36
commit 0d7d4e6af0

View File

@@ -73,6 +73,8 @@ For example, use `organization_id` instead of **org_id** or **resource_owner** f
#### Resources and Fields #### Resources and Fields
##### Context information in Requests
When a context is required for creating a resource, the context is added as a field to the resource. When a context is required for creating a resource, the context is added as a field to the resource.
For example, when creating a new user, the organization's id is required. The `organization_id` is added as a field to the `CreateUserRequest`. For example, when creating a new user, the organization's id is required. The `organization_id` is added as a field to the `CreateUserRequest`.
@@ -90,6 +92,65 @@ Only allow providing a context where it is required. The context MUST not be pro
For example, when retrieving or updating a user, the `organization_id` is not required, since the user can be determined by the user's id. For example, when retrieving or updating a user, the `organization_id` is not required, since the user can be determined by the user's id.
However, it is possible to provide the `organization_id` as a filter to retrieve a list of users of a specific organization. However, it is possible to provide the `organization_id` as a filter to retrieve a list of users of a specific organization.
##### Context information in Responses
When the action of creation, update or deletion of a resource was successful, the returned response has to include the time of the operation and the generated identifiers.
This is achieved through the addition of a timestamp attribute with the operation as a prefix, and the generated information as separate attributes.
```protobuf
message SetExecutionResponse {
// The timestamp of the execution set.
google.protobuf.Timestamp set_date = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"2024-12-18T07:50:47.492Z\"";
}
];
}
message CreateTargetResponse {
// The unique identifier of the newly created target.
string id = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"69629012906488334\"";
}
];
// The timestamp of the target creation.
google.protobuf.Timestamp creation_date = 2 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"2024-12-18T07:50:47.492Z\"";
}
];
// Key used to sign and check payload sent to the target.
string signing_key = 3 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"98KmsU67\""
}
];
}
message UpdateProjectGrantResponse {
// The timestamp of the change of the project grant.
google.protobuf.Timestamp change_date = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"2025-01-23T10:34:18.051Z\"";
}
];
}
message DeleteProjectGrantResponse {
// The timestamp of the deletion of the project grant.
// Note that the deletion date is only guaranteed to be set if the deletion was successful during the request.
// In case the deletion occurred in a previous request, the deletion date might be empty.
google.protobuf.Timestamp deletion_date = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
example: "\"2025-01-23T10:34:18.051Z\"";
}
];
}
```
##### Global messages
Prevent the creation of global messages that are used in multiple resources unless they always follow the same pattern. Prevent the creation of global messages that are used in multiple resources unless they always follow the same pattern.
Use dedicated fields as described above or create a separate message for the specific context, that is only used in the boundary of the same resource. Use dedicated fields as described above or create a separate message for the specific context, that is only used in the boundary of the same resource.
For example, settings might be set as a default on the instance level, but might be overridden on the organization level. For example, settings might be set as a default on the instance level, but might be overridden on the organization level.
@@ -99,6 +160,8 @@ The same applies to messages that are returned by multiple resources.
For example, information about the `User` might be different when managing the user resource itself than when it's returned For example, information about the `User` might be different when managing the user resource itself than when it's returned
as part of an authorization or a manager role, where only limited information is needed. as part of an authorization or a manager role, where only limited information is needed.
##### Re-using messages
Prevent reusing messages for the creation and the retrieval of a resource. Prevent reusing messages for the creation and the retrieval of a resource.
Returning messages might contain additional information that is not required or even not available for the creation of the resource. Returning messages might contain additional information that is not required or even not available for the creation of the resource.
What might sound obvious when designing the CreateUserRequest for example, where only an `organization_id` but not the What might sound obvious when designing the CreateUserRequest for example, where only an `organization_id` but not the
@@ -190,33 +253,54 @@ In case the permission cannot be checked by the API itself, but all requests nee
}; };
``` ```
## Pagination ## Listing resources
The API uses pagination for listing resources. The client can specify a limit and an offset to retrieve a subset of the resources. The API uses pagination for listing resources. The client can specify a limit and an offset to retrieve a subset of the resources.
Additionally, the client can specify sorting options to sort the resources by a specific field. Additionally, the client can specify sorting options to sort the resources by a specific field.
Most listing methods SHOULD provide use the `ListQuery` message to allow the client to specify the limit, offset, and sorting options. ### Pagination
```protobuf
// ListQuery is a general query object for lists to allow pagination and sorting. Most listing methods SHOULD use the `PaginationRequest` message to allow the client to specify the limit, offset, and sorting options.
message ListQuery { ```protobuf
uint64 offset = 1; message ListTargetsRequest {
// limit is the maximum amount of objects returned. The default is set to 100 // List limitations and ordering.
// with a maximum of 1000 in the runtime configuration. optional zitadel.filter.v2beta.PaginationRequest pagination = 1;
// If the limit exceeds the maximum configured ZITADEL will throw an error. // The field the result is sorted by. The default is the creation date. Beware that if you change this, your result pagination might be inconsistent.
// If no limit is present the default is taken. optional TargetFieldName sorting_column = 2 [
uint32 limit = 2; (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
// Asc is the sorting order. If true the list is sorted ascending, if false default: "\"TARGET_FIELD_NAME_CREATION_DATE\""
// the list is sorted descending. The default is descending. }
bool asc = 3; ];
// Define the criteria to query for.
repeated TargetSearchFilter filters = 3;
option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = {
example: "{\"pagination\":{\"offset\":0,\"limit\":0,\"asc\":true},\"sortingColumn\":\"TARGET_FIELD_NAME_CREATION_DATE\",\"filters\":[{\"targetNameFilter\":{\"targetName\":\"ip_allow_list\",\"method\":\"TEXT_FILTER_METHOD_EQUALS\"}},{\"inTargetIdsFilter\":{\"targetIds\":[\"69629023906488334\",\"69622366012355662\"]}}]}";
};
} }
``` ```
On the corresponding responses the `ListDetails` can be used to return the total count of the resources
On the corresponding responses the `PaginationResponse` can be used to return the total count of the resources
and allow the user to handle their offset and limit accordingly. and allow the user to handle their offset and limit accordingly.
The API MUST enforce a reasonable maximum limit for the number of resources that can be retrieved and returned in a single request. The API MUST enforce a reasonable maximum limit for the number of resources that can be retrieved and returned in a single request.
The default limit is set to 100 and the maximum limit is set to 1000. If the client requests a limit that exceeds the maximum limit, an error is returned. The default limit is set to 100 and the maximum limit is set to 1000. If the client requests a limit that exceeds the maximum limit, an error is returned.
### Filter method
All filters in List operations SHOULD provide a method if not already specified by the filters name.
```protobuf
message TargetNameFilter {
// Defines the name of the target to query for.
string target_name = 1 [
(validate.rules).string = {max_len: 200}
];
// Defines which text comparison method used for the name query.
zitadel.filter.v2beta.TextFilterMethod method = 2 [
(validate.rules).enum.defined_only = true
];
}
```
## Error Handling ## Error Handling
The API returns machine-readable errors in the response body. This includes a status code, an error code and possibly The API returns machine-readable errors in the response body. This includes a status code, an error code and possibly