Why not to consider models in REST API versioning?
Asked Answered
A

1

0

There was an answer to similar question but that was too specific to an example and doesn't answer in general.

Can any one please tell how to handle the below scenario if models are not versioned?

PUT /v1/users
username (string)
email (string) (required)
password (string) (required)
POST /v2/users
username (string) (required)
email (string) required
password (string) (required)

Assuming the model name is UserModel, in v1 version username is optional but in V2 it's required.

If we use a schema validator like ajv, it fails even for v1 api requests as the latest specification/model mentions username is required field.

There should be a strong reason for everyone saying models shouldn't be versioned but I might be missing something clearly. Here in this case, versioning the models makes more sense as it doesn't break backward compatibility easily.

Alpestrine answered 25/5, 2019 at 10:29 Comment(7)
That schema is for the request payload, not the persistence model.Bikaner
My models are generated from the swagger schema. I suppose thats how all do it too. they do depend on the schema for creating the model.Alpestrine
Transport models, perhaps, but if you're relying on the database schema exactly and always matching the API schema then this is the kind of problem you'll have.Bikaner
Can you please share an example if possible?Alpestrine
I'd suggest some research, these are often called Data Transfer Objects (DTOs) and Data Access Objects (DAOs). It's unclear what benefit you think the edit had.Bikaner
Thanks for pointing about DTO/DAO. My code is generated through Swagger Codegen and thats why I see close relation between models and schemas.Alpestrine
Let us continue this discussion in chat.Alpestrine
K
6

You are probably confusing the models that represent the domain of your application with the models that represent the data handled by your API.

These are (or at least should be) different concerns and should be decoupled from each other. You don't want to break your API clients when you add, remove or rename a field in your application domain model.

Having said that, while your service layer operates over the domain/persistence models, your API controllers should operate over a different set of models.

As your domain/persistence models evolve to support new business requirements, for example, you may want to create new versions of your API models to support these changes. You also may want to deprecate the old versions of your API as new versions are released. As your clients update their code, you may drop the support to old versions.


Example

For example purposes, let's imagine you are creating an application for task management. And here's how you represent a task in your domain:

+----------------------+
|         Task         |
+----------------------+
| - id: Long           |
| - title: String      |
| - completed: Boolean |
+----------------------+

Your application will provide an API, so clients can manager their tasks.

To create a task in your API, the clients need to POST a JSON representation of the task, with the title and a boolean value indicating whether the task is completed or not. They are not supposed to provide a value for the id, as it will will be generated by the server. Good stuff.

There are different ways to version your API, which include URL and media type versioning. That's a big topic though and I won't cover the pros and cons of each approach in this answer. For example purposes, however, I'll use media type versioning:

POST /tasks HTTP/1.1
Host: example.org
Content-Type: application/vnd.foo.v1+json

{
  "title": "Send report to manager",
  "completed": false
}

Long after you release your application to production, you realise that using a boolean value to represent the status of the task is not great. And using an enumeration with some values such as NOT_STARTED, STARTED and COMPLETED would suit your business requirements much better than a boolean value.

That would require a change in your domain model and in the database as well. Here's what your domain will be like:

+----------------------+
|         Task         |
+----------------------+
| - id: Long           |
| - title: String      |
| - status: String     |
+----------------------+

So you release a new version of your API. The task representation now has a status rather than a completed property:

POST /tasks HTTP/1.1
Host: example.org
Content-Type: application/vnd.foo.v2+json

{
  "title": "Send report to manager",
  "status": "NOT_STARTED"
}

That's much cooler. But don't forget your application is already in production and you don't want to break the clients that use your old API.

So you'll deprecate the old version of your endpoint but you'll support it for a while, so your clients can update their code.

When mapping the old task representation to the task domain model, you would consider the following:

  • If completed is true, then the task status will be COMPLETED
  • If completed is false, then the task status will be NOT_STARTED
Keare answered 25/5, 2019 at 11:3 Comment(6)
I'm using Swagger Codegen for generating models and the api code. If you mean i need to decouple the models in swagger from the db models, can you please suggest a good workflow on how to handle it? Do i need to version the schemas generated by swagger and have models non-versioned which are direct relation to my db coded manually?Alpestrine
@Alpestrine Yes. The majority of your application should not know about the API at all, it should be about implementing the required business logic. You don't want to have separate database tables depending on what API version people use, for instance, so how you persist to the DB should be a completely separate concern (e.g. using an ORM). The versioned part should be like a templating layer: translating the internal data into a different format for other people to use.Instil
Thanks @Instil for clarification.Alpestrine
@Keare Thanks a lot for taking time in explaining clearly. So, models generated for domain can be versioned but not the db models. Right?Alpestrine
@Alpestrine You may want to version the models generated by Swagger, but not the domain model of your application.Keare
Thanks makes it more clear :) Once again thanks for taking time in writing a great answer! Can you please point a single example project which is available on internet which implements this way? Mainly versioning the schema/swagger models and not versioning the main db models?Alpestrine

© 2022 - 2025 — McMap. All rights reserved.