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