Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.In my opening post I went over some of the issues I encountered when initially developing an HTTP API. In this post I’m going to cover some of those pain points and what I think the solution was.
ObjectsThe first pain point revolves around the idea of your HTTP API returning objects. Meaning you serialize an object to JSON and return to the client. This seems pretty typical. Almost every example you find in regards to Web API describes this behavior. Here’s an example of what this looks like: We’re doing nothing more than fetching a record out of our repository/database and serializing it down the to the client. On the flip side, all of our endpoints for mutating state of our system take the same object back.
Object as ResourceThere was a great and short blog post by Alex Moore last year.
You’ve doubtless seen the OAR pattern out in the wild. I’d define its constraints this way: 1. a resource maps 1:1(-ish) to an object in your server’s application logic, 2. uris and http methods are given conventions mapping to CRUD operationsThese are what most examples I find describe. If you ever used OData with Entity Framework, it’s another great example of OAR.
Model ChangesThe first obvious issue with this is your exposing your internal data structure to your consuming clients. If you do not have ownership over the clients, then making any breaking change to the structure
TodoItem is going to be pretty difficult.
This is really problematic when your internal models are still evolving.
DTOThe obvious answer is to create DTO (Data Transfer Objects) as the essentially a contract to your consuming clients. Meaning you will create a separate object that will be serialized and return to clients rather than your database entity. This is generally a recommended approach that I use. This is where a library like AutoMapper shines.
RepresentationBut we need to take this a step further. The idea of returning serialized DTO that still are in a 1:1-ish with some underlying data entity only provides our clients a single piece of information. Often times in order for the client to perform a given action, they generally need related data. An example, maybe our Todo application had the ability to create different categories so we could break up and categorize our items. If we wanted to edit our TodoItem to specify a Category, we would need to pass it the CategoryId. How exactly do we get the list of categories from the client? Would the client be required to call another endpoint to them? Why not return them in our DTO? We would be doing this already if you were creating an MVC application returning a rendered HTML to the client/browser. Your edit screen would contain a
<select> list of all the categories in your edit
MessagesIf you start thinking about sending down messages to the client rather than objects, you can open up to the idea of your messages being a much more rich representation. This representation could contain referential data, actions the client could preform or other places the client could navigate your HTTP API. Last year, I wrote a blog post about your Resource Model not being your Data Model after I seen a great tweet by Mike Amundsen.
NextIn my next post I’m going to look at how we build HTML web applications and what we can learn and use to develop our HTTP APIs. If anyone has any other suggestions or recommendations about this series, or the sample project to convert, please leave comment or let me know on twitter.
- Building a Self Descriptive HTTP API in ASP.NET Core
- Object as Resource
- Hypermedia Clients