Show Calendar — Part 1: Setting Up the API
The Show Calendar project explores developing an app with the Event Sourcing and CQRS patterns. The goal is to understand how good these patterns are for fast-changing projects, like startups.
The project is implemented in JavaScript with a GraphQL API, but the ideas should work in any language.
We’re going to set up a GraphQL API that’ll serve as our entry point into the show calendar system.
The first step I usually take when starting my implementation is to think of the data model.
The Show data model
I want to keep it simple — we don’t need anything fancier than a single type Show
. Yes, we could have a more advanced data model, but in the name of simplicity, this is a reasonable starting point.
Show {
title: String
time: DateTime
host: String
location: String
}
I know this model has problems. For example, a show may, in reality, have more than one host. But instead of planning for that I’m going to later introduce it as a change of requirements. One of the points of this project is to see how easy or hard it is to handle this type of change.
(It’ll be interesting to see how things go… especially if there’s a pre-existing “legacy database” with a bunch of data that was added before we “knew” about the “new” requirement. Alas, onwards!)
CQRS… ?
We’re going to apply the Command Query Responsibility Separation pattern, or CQRS. This means splitting the functionality of reading and writing (e.g. creating, reading, updating) into separate things — Queries and Commands.
Queries are for reading data.
Commands are for writing data.
Our system will be simple and have only one query.
## Show Calendar Queries ##
GetShow -> Shows
The most basic command in the system is adding a show. For the time being we have no business rules. In other words, we can add multiple shows with exactly the same information.
## Show Calendar Commands ##
AddShow(title, time, host, location) -> void
And that’s it for now. Later on we might add more commands or queries, but for simplicity’s sake this is enough.
It’s coding time!
Implementing stuff always makes me understand things better. The Show Calendar app will be implemented in Node.js with a GraphQL API.
If you haven’t already, get the starter kit here: Part 0 — Starter Kit.
Set up the GraphQL API
In src/schema/index.js
, set up one query allShows
and one mutation addShow
. At the same time, add the Show
GraphQL type.
The CQRS pattern’s Query and Command concepts map really nicely onto GraphQL’s Query and Mutation types.
CQRS Query — GraphQL Query
CQRS Command — GraphQL Mutation
Now, start the server with npm start
and go to the GraphiQL playground (localhost:3000/graphiql - don't forget the the i
!) and paste the below query and mutation.
Note: npm start
from the starter kit will automatically restart the server when it detect that you've saved a code change. No need to start and stop!
query GetShows {
allShows {
title
time
host
location
}
}mutation AddShow {
addShow(
title: "Trolling"
time: "2018-04-01T13:37:00Z"
host: "Trollface"
location: "Reddit"
)
}
Using the play button, run the GetShows
query and you should receive the following response.
{
"data": {
"allShows": []
}
}
Running the AddShow
mutation should result in the following.
{
"data": {
"addShow": true
}
}
However, if you run the GetShows
query again we still receive an empty array—there's nothing hooked up to the API yet.
Before fixing that let’s fix another tiny issue.
The time value can currently be any string, but only valid time strings should be allowed.
Making sure time is time
In the Shows
type, we've accepted String
as the GraphQL type for the time
field. While this could work for some applications I'd rather have it be a type that actually represents date and time.
Let’s import GraphQlDateTime
from the graphql-iso-date
package and add it as the DateTime
scalar to the GraphQL API.
I’m not going to explain exactly what a scalar is, just know that if the DateTime
receives anything else than a valid ISO time string it'll throw an error.
Now you’ll receive a GraphQL error if you attempt to pass an invalid time string, like "2017-13-01T12:00:00Z"
(the 13th month?).
Let’s return some data
We’re done with the GraphQL API for now, but it’d be fun if the allShows()
query returns some shows.
For the time being, let’s return some mock data.
Running GetShows
is now a little bit more interesting.
Summing it up
Although playing with mock data is cool and all, it’s way more interesting if the AddShow
command saves the show so the GetShows
query can read it. Time for some plumbing...
If you want to you could now hook this GraphQL API up to a frontend app (for example using apollo-client
).
In Part 2 we’ll make the API work by using a re-e-eally simple in-memory storage: an array. We’ll also talk a lot about events and how what we store is, like totally, a simple variant of Event Sourcing.