0

I'm having a trouble with updates in a Api C# Client generated with NSwag and how to use the HTTP PUT verb.

Let's say I have a DTO called customer

public class CustomerDTO
{
    public int id { get; set; }
    public string name{ get; set; }
    public string email { get; set; }
}

I have a consumer of that C# Client that wants to modify the customer e-mail.

So he creates a call to CustomerPut to replace the resource.

CustomerDTO customer = await CustomerGet(); // Performs a get on the entity
customer.email = "newemail@abc.com";
await CustomerPut(customer);

All right for the moment.

The problem arises when I decided to add a new field into the CustomerViewModel

public class CustomerDTO
{
    public int id { get; set; }
    public string name{ get; set; }
    public string email { get; set; }
    public string? likesApples {get; set;}
}

If I ever do that, the code in my consumer has to be updated, or he will unset the likesApples property. It means the value from likesApples wil get erased every time the outdated client tries to update something.

Is there a solution so I don't have to update my client code for every new simple field I want to add?

Bernard Vander Beken
  • 4,848
  • 5
  • 54
  • 76
Luc
  • 59
  • 7
  • Don't use `PUT`, use `PATCH` instead. If you need to stick with `PUT` then you need to pass the complete payload (=update every client). Or, you could version your API, keeping backward compatibility for outdated clients. – BackSlash Mar 06 '19 at 15:52

2 Answers2

1

Is there a solution so I dont have to update my client code for every new simple field I want to add?

Versioning of your API. By using PUT you assign a given resource to the given identifier, overwriting the previous version of that resource.

Adding a new field to a resource requires a new contract, so a new API version.

If you want to keep adding new fields and allow partial updates, look into PATCH.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • The idea is to use PUT only if the entities doesn't change very often? I'm confused because the problem doesn't arise in dynamic languages where the GET always uses the updated version, is that right? – Luc Mar 06 '19 at 15:57
  • No, the idea is that the minute you publish an API, you consider that a contract that clients can rely on. If you decide to publish a new version containing additional fields, you have a new API version and need to handle accordingly. – CodeCaster Mar 06 '19 at 15:58
  • Or, if you don't consider adding a new, optional field to be a breaking change, you could let your client use `dynamic` or `ExpandoObject`-derived types to store data from fields unknown to them. – CodeCaster Mar 06 '19 at 16:01
1

You can write a different Put API. This is a psuedo code, so forgive me if doesn't compile.

Take email and customerUpdateRequest from put request. and set customer value with propertyName and reflection. If you use EF, you can select your customer from DB and change which field you want.

[HttpPut]
public JsonResult UpdateCustomerValues(string email, CustomerUpdateRequest request)
{
    var customer = new Customer();
    customer.Email=email;
    PropertyInfo propertyInfo = customer.GetType().GetProperty(request.propertyName);
    propertyInfo.SetValue(customer, Convert.ChangeType(request.value, propertyInfo.PropertyType), null);

}

public class CustomerUpdateRequest
{
    public string propertyName{get;set;}
    public string value{get;set;}

}
ibrahimozgon
  • 1,137
  • 1
  • 12
  • 19