Designing an API
Learning new principles and techniques is one of the driving factors for Draftsman. We looked at Actor based programming, Serverless concepts, and different implementations of event stores.
We made some choices after we learned enough to compare some concepts. We ditched Actor based programming and doubled down on Serverless Architecture. We favored building a Python module to support event sourcing and stopped researching Axon Server and Event Store.
We prefer well-maintained open-source projects over programming libraries ourselves. Although, serverless fit is more important.
We intend to opensource our reusable Python modules once they are mature enough.
During ideation, we stumbled upon GraphQL. And wondered, is this something worth learning? My first reaction was, looks interesting, but not now. We had a lot on our plate, learning serverless architecture, what is it and how do we use it? Thus my thought was, park GraphQL for now and do something simple, something we know, like REST.
Is REST simple though? Implementing a good REST interface is not that easy. This is because it is an architectural style and not a protocol. This means REST does not dictate to how you should implement an API but only defines guidelines. Guidelines how in an ideal world an API should be structured. REST stands for, Representational State Transfer and puts uniform resources at its center. Hence implementing a REST API requires a lot of technical design choices, how are resources structured and how do we interact with these resources.
Let's take a step back, how do we want to model our applications. We speak of views and commands as separate models. We need to combine our two models into one API, a daunting and technical-driven job. Especially as the architecture style requires us to use uniform resources because that requires merging the two models. Chance is, we end up with an ugly incomprehensible interface. The risk with choosing REST is that implementation details leak through to my modeling language.
Absorbing this, our API should be detached from our architecture and modeling language. Or more specifically, the API implementation may not influence architecture or modeling language. Our model speaks of views and commands.
Commands are processed asynchronously in our architecture. From the API perspective, we should only define input. The API is responsible for the transformation from synchronous to asynchronous communication. The receipt is generic "We received your request, and will process it shortly. Here is your trace ID".
Views are clusters of information in our architecture. We model the attributes and map them to information structures in the domain. Finally, we model how we can query these views.
This means the responsibility of the API is threefold, query functionality regarding views, technical transformation regarding the command bus, and for both these functions, it has to handle identity and access checks. Resume, in our model we only want to define "what is possible" within the application. Not the specific access patterns you should use.
Therefore we think we would benefit more from utilizing a Data Query Language like GraphQL than an Architectural Pattern like REST.
Let's take a look at the example schema above. A GraphQL schema is a contract, defining what we can do with the API. For this post, I only want to highlight one core concept. At the heart of the schema we see, Query and Mutation... We could not wish for a better fit.