API design best practices

Stop exposing your domain models

Returning only the necessary data to your API clients

Andre Lopes
Checkout.com-techblog

--

Photo by Clément Hélardot on Unsplash

Hi, multicellular organisms!

Today I want to talk about a very important topic regarding API designs. To not expose your domain models or your entities in your API endpoints.

Note that I’ll show examples in .NET but this is valid for any programming language.

Very often I see an endpoint like this:

This is a .NET controller where you fetch information from data storage and return it directly to your endpoint.

What is the problem with this design?

By allowing your API to return your domain models you are exposing it to some issues.

Domain models change more often than API resources

Your API return models are your API contracts, which determine the resources and endpoint receives and/or returns. They shouldn’t change as much as your domain models.

By doing so, you reduce the amount of breaking changes your API clients have to handle every time an update is released.

Security

Your domain models are the representation of your application logic, sometimes your database structure, depending on your architecture.

When you return them directly you are exposing this structure to any client that has access to your API.

Unintentional behaviors

Some unexpected behaviors can happen when returning your domain models directly.

A common scenario with entity framework is to have circular references between models, having a two-way reference between models. If you return them directly, you will probably face a self reference loop exception. This happens because the two models have a reference to one another and when it is being serialized to an JSON object, it faces an infinity loop. You can see an example below:

public class FirstModel
{
public int Id { get; set; }
public SecondModel SecondModel { get; set; }
}
public class SecondModel
{
public int Id { get; set; }
public FirstModel FirstModel { get; set; }
}

You can configure your JSON serialization to avoid these situations, but then you might get some strange behaviors after serialization that might not be what your clients are looking for.

What to return then?

The best practice is to have dedicated API models which, before returning a response, you’ll map from your domain models. This will ensure that you are only returning the necessary data your client needs.

An API model must be a contract with your client and it should be the most stable as possible to not break any calls that all your clients make to your API.

An example in .NET would be:

public Task<ActionResult<IEnumerable<ProductResource>> GetProducts()
{
var products = await _service.GetProducts();
var productResources = _mapper.Map<IEnumerable<ProductResource>>(products); return Ok(productResources);
}

This way you have more control over what you are returning by decoupling your responses from your domain and making sure that you’ll only return the necessary information required by your client.

Conclusion

Returning directly to your domain models and exposing them to your clients is considered a bad API design for many reasons.

You force your clients to be constantly updating their implementations that are dependent on your API.

You also are prone to having unexpected behaviors such as the one with circular references with .NET entity framework.

And another one is that it might expose some security issues as you might be exposing not only your models but also your database (if your domains models reflect your database entities).

So the best and most recommended practice is to decouple your domain from your API by having dedicated API models. Then you’ll map your domain models to your API models which you’ll return as the response.

Happy coding!

--

--

Andre Lopes
Checkout.com-techblog

Full-stack developer | Casual gamer | Clean Architecture passionate