https://kotlinlang.org logo
Title
m

maxmello

04/11/2020, 3:18 PM
Hey guys, I have a question regarding REST APIs and Kotlin. Normally, we define mutability of properties through `val`and
var
. But when a model is stored in a database and edited in a frontend, we (de-)serialize the model, which removes the usefulness of
val
, because objects are newly created when deserialized (e.g. from a JSON request body). In my
PUT
endpoints, I want to make sure only the fields are updated which are actually mutable, so right now I manually get the old version of the model from the database and update mutable fields one by one manually from the new instance. For me, this has 2 problems: If I only update the var fields, the client might wonder why the other fields did not update on the next request. Secondly, when the model changes, it is easy to forget updating the manual updating code. Anybody got a better approach to this? Do you prever PUT endpoints per mutable property instead?
s

Shawn

04/11/2020, 3:44 PM
But when a model is stored in a database and edited in a frontend, we (de-)serialize the model, which removes the usefulness of 
val
, because objects are newly created when deserialized (e.g. from a JSON request body)
this is a common misconception. there are in fact libraries that will let you deserialize to classes with val properties, see
jackson-datatype-kotlin
for an example
m

maxmello

04/11/2020, 6:16 PM
I know that and use the library. My point is that immutability of a single JVM object is not the same as immutability of the “same” logical object (so a model with the same ID), as there could be multiple instances of an object with the same ID, one from the DB and one from the request, but maybe there just is no automatic way to achieve what I want
s

Shawn

04/11/2020, 6:30 PM
is that not true of literally any language though? I don’t see how this is a Kotlin thing, or even a referential immutability thing when talking about a greater system that concerns itself with multiple nodes that could have multiple “instances” of a logical object-like concept in transit in either direction at one time
👍 1
a

araqnid

04/13/2020, 12:41 PM
Sounds like the start of reinventing Hibernate and merging detached objects into the session 😨
😱 3
j

Johannes Zick

04/14/2020, 8:00 AM
Mostly it sounds like you allow fields on a put request that should not be modified. I'd recommend disallowing those fields, or ignoring them. One informs the user that he sent a field which cannot be changed, the other makes it easier to reuse objects especially in JavaScript. A matter of taste. Just in case, although I cannot tell if this is what is going on, never use Hibernate (or whatever you use) models for the API. Always keep those separate. Probably even the input and return models for the API.
👍 1
d

David Eriksson

04/15/2020, 9:00 AM
I don't see how val/var helps in this case. Updating "resources" is a pain point in REST(ish) APIs.
e

Eamonn

04/16/2020, 1:28 PM
Sounds like you need a DTO object that only contains those fields the user can change. Load the request data into the DTO, validate, and if correct, then map to the corresponding domain class to store in the database. Also don't forget about the copy method you get free with data classes which might help if merging data is not an option.
2
m

maxmello

04/16/2020, 3:17 PM
I agree that my initial post was a little bit stupid, usually I use DTOs and map them into the original model, but I was working in an annoying situation where I have polymorphic deserialization for my model (around 10 subclasses), so I would need to recreate the whole class hierarchy again as DTOs and then still map them somehow anyway, which was an annoying thought. As a middleground I added an
open fun updateModel(newModel)
which I can call on the existing model from the database, pass the one from the API call and in there decide what is allowed to be updated. It’s still not as clean as DTOs, so maybe I will change it in the future. Also true that it is not very Kotlin specific, I should have posted it in #random or thought about it more myself before posting at all.
I think what I actually wanted in the @Immutable annotation from Hibernate, except I’m working with KMongo/MongoDB so anyway.