I have a typical Spring boot Rest API to do crud operations on a user object.
Class User{
long id
String displayName
String email
String passwordHash
String passwordSalt
Instant passwordExpiryDate
boolean locked
Instant version (sql timestamp for optimistic locking)
}
POST users/
: create userGET users/{id}
: get user detailsPUT users/{id}
: update user name and emailPUT users/{id}/password
: update user passwordPUT users/{id}/unlock
: set lock status to falseDELETE users/{id}
:
what bothers me is that my full model User class is currently used as input or output, even though only some properties matter. Some examples:
POST users/
: you don't need to give id, password salt/hash or version, they are generated.GET users/{id}
: no need to return the id, it is already known by the requester.PUT users/{id}
: only need a new email, name and the version.PUT users/{id}/password
: only need a new password and the versionPUT users/{id}/unlock
: only needs the version
To cope with this I started to create several "request" classes:
- NewUserDetails
- UserWithoutId
- UserWithOnlyPassword
- UserWithOnlyPersonalDetails
- UserVersion
This ensures that my input and output only contains EXACTLY what is required, and no documentation has to be read to know which property is mandatory/used. The downside is that it is silly because they all represent the same entity, just different aspects of it. Also any validation (I use javax contraints annotations) is declared multiple times.
I was thinking about removing all the requestbodies and instead use requestparams (query parameters) to give only the necessary details, but this would result in me having put and post operations without requestbodies.
It seems there is no solution that is both clean for the clients of the api, and for the internal structure. What are best practices for this API design?