In July of 2018 I talked about Polyglot, a very simple project I’d launched whose only purpose was simply to bolster my software development skills. Work on Polyglot has been sporadic at best, coming in fits and spurts, and thus far focused on building a model for the APIs that would be found in the project. Since I am not a software engineer by training (I have no formal training in software development), all of this is new to me, and I’ve found myself encountering lots of questions about API design along the way. In the interest of helping others who may be in a similar situation, I thought I’d share a bit here.
I initially approached the API in terms of how I would encode (serialize?) data on the wire using JSON (I’d decided on using a RESTful API with JSON over HTTP). Starting with how I anticipated storing the data in the back-end database, I created a representation of how a customer’s information would be encoded (serialized) in JSON:
{ "customers": [ { "customerID": "5678", "streetAddress": "123 Main Street", "unitNumber": "Suite 123", "city": "Anywhere", "state": "CO", "postalCode": "80108", "telephone": "3035551212", "primaryContactFirstName": "Scott", "primaryContactLastName": "Lowe" } ]
}
It’s pretty obvious, though, that this representation is closely tied to how I anticipate I’ll store customer data in the back-end database, right down to the field names. One of the books I’ve been reading is Building Microservices, an O’Reilly book by Sam Newman (see here; I’ll post a review of the book once I complete it). One of the things Newman cautions readers against in his book is exposing implementation details internal to a service to other services—did this qualify? Newman also discussed hypermedia as the engine of application state (HATEOAS, what an acronym!), but I’ll be honest in admitting that it didn’t click with me at first.
While still working through Newman’s book, I added REST API Design Rulebook by Mark Masse to the mix (see my review of the book). Masse talked extensively about HATEOAS, but—as you can see in my review of the book—it still didn’t click for me.
Next up, I added RESTful Web APIs by Leonard Richardson, Sam Ruby, and Mike Amundsen to my reading list (here’s the O’Reilly page for the book; I’m still reading the book so no review yet). Whether by repetition or by seeing the information presented in a different context, the discussion of HATEOAS and hypermedia by Richardson et al. finally made sense. It also unlocked some of the ideas presented by Masse and Newman earlier, so that I was able to really understand that I’d made several critical mistakes in my approach thus far:
- I chose a media type (JSON) before fully understanding the particulars of my application without realizing the constraints that media type creates.
- The client representation was too closely tied to the back-end/server-side implementation, making things far too brittle (what would happen if I needed to change the database schema?).
- I invented new field names instead of re-using properties and fields that are already well-known and well-accepted (like re-using information from an appropriate microformat).
- The client representation doesn’t provide any information on state transitions (How is a customer record updated? How is a customer record deleted?) or relationships between resources (What’s the relationship between an order record and a customer record? Or vice versa?).
It’s clear that something more than just encoding data in JSON is required.
The question, for me, is how much more? And what to include, exactly? Richardson et al. seem to advocate the Collection+JSON format, but it’s only a personal standard (see his book for definitions of various standards) and not necessarily widely accepted/used. However, even within Collection+JSON, the specific links provided as hypermedia are left as “implementation details.” So what sort of information makes sense?
Given that Polyglot is intended to be a simple order entry/lookup system, a few potential ideas come to mind:
- All discussions of HATEOAS and hypermedia agree that a “self” link is needed that provides the URL to the resource (customer record or order record) being returned.
- It seems reasonable to return “related” information. So, if viewing an order record, provide a link to the associated customer record (for example), the previous order, the next order, etc.
Clearly I have lots of work to do!
Now comes the task of shaping the limited work I’ve done so far into something more usable. I also need to finish reading RESTful Web APIs; although the content was difficult for me to grok at first, recently I’ve found that I’m beginning to more fully understand the concepts the authors are presenting. I still have lots of questions—how do things like OpenAPI fit in here?—so if you have answers, feel free to hit me on Twitter. This is definitely a learning exercise for me, so I welcome any other resources I should be using to help guide my way.