OpenAPITools / OpenAPITools/openapi-generator

[REQ] [csharp] Partial update of only certain fields

Open
#17,159 6 comments 2 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Enhancement: Feature
Dominant language
Java
Stars
26.8k
Forks
7.7k
PR merge metrics
PR metrics pending

Description

Is your feature request related to a problem? Please describe.

Using the csharp generator, with OpenAPI 7.1.0:

--genereator-name csharp --addtional-properities=targetFramework=net48,disallowAdditionalPropertiesIfNotPresent=false

The _PartialUpdate API methods take in a Model object, whose inputs all have a default value, set with the default keyword. This evaluates to null for reference types.

Typically in a REST API, a paritial update allows only updating one of the fields, for example a model:

string name;
int? age;

On a partial update, you would be able to send:

{
  "name": "Bob"
}

This would update the model instances name field but leave age unchanged.

But with the csharp generated code, there is no way to create an Partial Update instance to the API. Every field must either have a value, or be null. The constructor looks like:

string name = default,
int? age = default

Where name is nullable in this case, but could just as well be string? if nullable types are used in csproj.

What this means is that if you try to only update the name field, you actually get:

{
  "name": "Bob",
  "age": null
}

Because the default values for those types is null, and this is sent and then the backend will save age as null rather than leaving it as whatever value it is.

Describe the solution you'd like

Some generators (in languages that support Union types, admittedly) allow for an UNSET sentinel to be used (and set by default for non-required fields, like those in partial updates

class Unset:
    def __bool__(self) -> Literal[False]:
        return False


UNSET: Unset = Unset()

In this kind of client, the default value for partial update models looks like:

    name: Union[Unset, None, str] = UNSET
    age: Union[Unset, None, int] = UNSET
  • Unset: Field is not sent in PATCH
  • None: Field sent with value null
  • str/int: Field sent with value supplied by user

This allows the generated client to choose whether or not a field is sent during an update.

It would be great to have some kind of a solution like this for the csharp generator. Or, perhaps at least some kind of configuration toggle on the actually request function that asks not to send fields if they are set to their default value? (Though this leads to edge cases where if you want to null out a field but not update other fields, you can't express this).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the csharp generator and the generated _PartialUpdate API methods described here, then trace how default-valued fields are serialized. Compare the desired three-state behavior—unset, null, and supplied value—with the current constructor and request output. Done means a partial update can omit an unchanged field while still explicitly sending null.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.