DEV Community

Jess Chandler
Jess Chandler

Posted on • Edited on

Do I really need to create classes in two places?

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)

Collapse
 
hugo__df profile image
Hugo Di Francesco

"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.

Collapse
 
rhymes profile image
rhymes

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...

Collapse
 
cjbrooks12 profile image
Casey Brooks

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.

Collapse
 
leoat12 profile image
Leonardo Teteo • Edited

This is the common practice, I don't think there is a good way to escape from it, except by using the same language in both client and API, using Javascript, most of the time. But not always this is possible, so in professional development I've seen practices to keep it updated, one of them is by using a specification, which the most used one is Swagger, which is known now as Open API specification. It happened before where I work where we developed the API and the application was made by another company, we did a specification using Swagger, it is like a contract that specifies how to communicate with the API. You can change the internals of the API the way you desire, but you CANNOT in any circumstance change the endpoints, the interfaces known by the client application. If you really need to change, the specification will have to be updated and the client will have to be notified. You can also make versions of an API like: "api.example.com/v1/endpoint" and "api.example.com/v2/endpoint" and you have to maintain all of them for the necessary time, you have to notify all the clients, if there are many you will need to maintain an old version for a long time. You can make a new endpoint with new functionality, mark the old one as deprecated in the docs/spec, but to keep backward compatibility you will need to keep old endpoints/versions most of the time.

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.

Collapse
 
5422m4n profile image
Sven Kanoldt

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.

Collapse
 
thomasjunkos profile image
Thomas Junkツ

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.

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".

Collapse
 
bgadrian profile image
Adrian B.G.

Use OPEN Api aka the standard derived from Swagger and their code generators.

When you modify the specs you just generate a new library.