I have a website for which I've written an API using mongoose models and nodejs.
Now, I am creating an app which will use the same API. Whether I create it in Xcode (just iOS) and Android Studio (just Android) or use a combined framework (like Flutter), I find myself creating classes that duplicate the Mongoose models. For example, I have a mongoose model for User, and I have now, in a separate location, a class for User.
My concern here is maintainability. If I update the API or make a change to the underlying models, I have to do this in two places. While I don't have a big application, I still feel as though I am doing this wrong.
Advice requested. :)
Okay, y'all. I think I just need to get my head around it. For the website, I have written an API that relies on the mongoose models, so I don't end up recreating them in that instance (for the front end). Unfortunately, I set up the API such that it returns the front end pages. That means that I cannot use it for mobile. I think that I can write a separate API for my mobile apps that lives on the same server and then will not have the redirects (and potentially then go back and have one pretty unified API that knows if it is serving a mobile app or the website).
I can create dart classes for Flutter (or do it uniquely for iOS and Android), so I can also have local cache of data.
Top comments (7)
"While I don't have a big application, I still feel as though I am doing this wrong." You're not doing it wrong, it's "normal" to have to re-create some sort of model on the client (android, iOS, web frontend).
What could help you is sharing the data class (eg. Using JS for the apps and the backend) although that gets super tricky quite quickly.
Another way is to share some sort of JSON API spec from which your data models are constructed in the apps, again complicated and is probably more effort than its worth.
You can't escape that, especially because they are two different applications, even if one is the client and the other the server.
Keep in mind that you don't know if those two models will evolve the same way even if now it seems you have two identical domain objects...
Let's face it from the other direction:
Say, you want to solve this problem once and for all and write your backendcode once and develop an abstraction framework to do the rest.
Say you want to make changes to your model which aren't reflected in your framework, you have to make changes in the model and in your framework. Or think about errors in your framework, which lead to strange behaviour not introduced without your framework.
I would argue, that on the long run, it is cheaper to live with some doubling of concepts and code, that to develop a solution to prevent this - including costs for teaching new team members your "magic".
Also, I learned that it is also good practice to decouple the database model from what is actually returned by the API, that's where DTO (Data Transfer Object) comes from. You have the database model, where you can change if needed, and the DTOs, that makes part of the contract between API and client and cannot be changed.
There are a few languages that work both on the server and clients, which opens the possibility of sharing data models. Most notable here is C# with the Microsoft stack, but more recently Kotlin is working to be a universal language as well.
But in general, as everyone else has mentioned, it is a normal thing for the client and server to create their own models. However, that's not necessarily a bad thing. The server will typically send out much more data than a single client actually needs. You can make your client code cleaner by only including the fields the client needs to work with, and leave the rest out.
For Android and iOS you cannot really avoid it, since there are different Languages involved.
But regarding Flutter, you would write your models in Dart (as a separate library for instance) that you would use in your WebApp (via AngularDart for instance) and in your both Mobile Apps in Flutter.
Use OPEN Api aka the standard derived from Swagger and their code generators.
When you modify the specs you just generate a new library.