简体   繁体   中英

Different model requirements for POST and PUT

Say I have a controller CatController with actions for GET, POST and PUT. They all use the same Cat resource which could look like this:

public class CatDto {
  public int Id { get; set; }

  [Required]
  public string Name { get; set; }

  [Required]
  public bool IsFriendly {get; set; }
}

However, the Name and IsFriendly properties should only be required when creating a new cat (POST), but optional when updating it (PUT) to allow updating only a single property.

The way I've handled this until now is simply having two classes, a CreateCat and UpdateCat which have the same properties but different data annotations. However I don't want to have to maintain two almost identical classes.

I could of course validate the model manually in each action, but data annotations are very useful for things like global model validators and automatic generation of Swagger schemas.

I'm also using the Swagger schema to automatically generate SDK's (using ApiMatic ), and that results in having two duplicate classes generated ( CreateCat and UpdateCat ) for what really should only be a single resource ( Cat ).

Is there an alternative way to achieve what I'm trying to do with only a single class?

I prefer to keep separate models to be honest. You could have a base abstract ( or not ) model with all the common properties although this is not required and simply adds a third class. Is there a need for it? I'd say no.

There are slight differences between POST and PUT.Neither POST nor PUT require the Id property if you already have that in the PUT endpoint. This negates the need of checking if that Id in URL matches the Id in the model.

Your example does not make the difference visible, but in many cases there are fields you don't really want to update. For example let's say you have a Created and Updated date fields, you would not want to change your Created date via a PUT for example. The more data you have that you do not want to update via a PUT, the more obvious and worthwhile the differences between the models become.

In your case even with those 2 properties I would still create 2 different models, even if they are virtually the same, this sets the expectation on how the API works and creates a clear design in the mind of everyone else who is working on it.

I would recommend against the design you are asking for. According to RFC [RFC7231] you can find here it is advised not to have partial content update in PUT methods.

"An origin server that allows PUT on a given target resource MUST send a 400 (Bad Request) response to a PUT request that contains a Content-Range header field (Section 4.2 of [RFC7233]), since the payload is likely to be partial content that has been mistakenly PUT as a full representation. Partial content updates are possible by targeting a separately identified resource with state that overlaps a portion of the larger resource, or by using a different method that has been specifically defined for partial updates (for example, the PATCH method defined in [RFC5789])."

The preferred solution is to use PATCH method instead of PUT. Patch method is described in the RFC in the this link . PATCH method were introduced for partial resource modifications

So look up PATCH methods or if you want to use PUT maybe have a separate endpoint that only takes one of the two values.

More information about PATCH method can be found here

So either go for a PATCH method or create different models and end point to cater for partial update using PUT.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM