Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpenAPI support for Atomic Operations #1580

Merged
merged 7 commits into from
Jun 30, 2024
Merged

OpenAPI support for Atomic Operations #1580

merged 7 commits into from
Jun 30, 2024

Conversation

bkoelman
Copy link
Member

@bkoelman bkoelman commented Jun 29, 2024

This PR adds full support for using atomic operations with OpenAPI. Tests and examples using NSwag and Kiota are provided.

Various types have been renamed, which heavily affects generated clients. For example, personPatchRequestDocument is now updatePersonRequestDocument, and personAttributesInPostRequest has become attributesInCreatePersonRequest. These renames were done because atomic operations are reusing existing schemas. As we're breaking big now (sorry), I did some extra cleanups in schema names. The easiest way to overcome that is to use target-typed new.

Both id and lid are exposed in all request types, to avoid an explosion of schema types. But this only happens when an operations controller is found. The effect is that you can send a lid in a post-resource request (which will be rejected by the server). Because of the id/lid distinction, separate schemas are generated for resource identifiers in requests and responses (so staffMemberIdentifier is replaced by staffMemberIdentifierInRequest and staffMemberIdentifierInResponse).

Another change is that the id property has moved from the abstract dataInResponse type into the resource-specific derived types. The effect is that you first need to upcast/type-check before getting access to the id.

Both NSwag and Kiota choke on the quotes in the application/vnd.api+json; ext="https://jsonapi.org/ext/atomic" media type, generating code that doesn't compile. Therefore, OpenAPI uses the relaxed variant introduced in #1553.

The exposed operations in OpenAPI are based on the GenerateControllerEndpoints by default, but can be customized using your own IAtomicOperationFilter, a new feature that was introduced in #1561.

The generation of id/lid properties takes ClientIdGenerationMode into account for create-resource operations. Likewise, get-only or set-only attribute properties are hidden in the appropriate schemas.

There is currently no way to send null/default attribute values in an operations request with NSwag. This is tracked at #1577.

Example usage:

var operationsRequest = new OperationsRequestDocument
{
    Atomic_operations =
    [
        new CreateTagOperation
        {
            Data = new DataInCreateTagRequest
            {
                Lid = "new-tag",
                Attributes = new AttributesInCreateTagRequest
                {
                    Name = "Housekeeping"
                }
            }
        },
        new CreatePersonOperation
        {
            Data = new DataInCreatePersonRequest
            {
                Lid = "new-person",
                Attributes = new AttributesInCreatePersonRequest
                {
                    LastName = "Cinderella"
                }
            }
        },
        new CreateTodoItemOperation
        {
            Data = new DataInCreateTodoItemRequest
            {
                Lid = "new-todo-item",
                Attributes = new AttributesInCreateTodoItemRequest
                {
                    Description = "Put out the garbage",
                    Priority = TodoItemPriority.Medium
                },
                Relationships = new RelationshipsInCreateTodoItemRequest
                {
                    Owner = new ToOnePersonInRequest
                    {
                        Data = new PersonIdentifierInRequest
                        {
                            Lid = "new-person"
                        }
                    },
                    Tags = new ToManyTagInRequest
                    {
                        Data =
                        [
                            new TagIdentifierInRequest
                            {
                                Lid = "new-tag"
                            }
                        ]
                    }
                }
            }
        },
        new UpdateTodoItemAssigneeRelationshipOperation
        {
            Ref = new TodoItemAssigneeRelationshipIdentifier
            {
                Lid = "new-todo-item"
            },
            Data = new PersonIdentifierInRequest
            {
                Lid = "new-person"
            }
        }
    ]
};

ApiResponse<OperationsResponseDocument> operationsResponse =
    await _apiClient.PostOperationsAsync(operationsRequest, cancellationToken);

var newTodoItem = (TodoItemDataInResponse)operationsResponse.Result.Atomic_results.ElementAt(2).Data!;
Console.WriteLine($"Created todo-item with ID {newTodoItem.Id}: {newTodoItem.Attributes!.Description}.");

Closes #1060.

QUALITY CHECKLIST

Copy link

codecov bot commented Jun 29, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 91.39%. Comparing base (1053099) to head (e9476b8).

Additional details and impacted files
@@             Coverage Diff             @@
##           openapi    #1580      +/-   ##
===========================================
+ Coverage    91.27%   91.39%   +0.11%     
===========================================
  Files          398      412      +14     
  Lines        12905    13421     +516     
  Branches      2038     2095      +57     
===========================================
+ Hits         11779    12266     +487     
- Misses         731      750      +19     
- Partials       395      405      +10     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@bkoelman bkoelman marked this pull request as ready for review June 30, 2024 00:37
@bkoelman bkoelman merged commit 67924c4 into openapi Jun 30, 2024
16 checks passed
@bkoelman bkoelman deleted the openapi-operations branch June 30, 2024 00:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

1 participant