slideshare quotation-marks triangle book file-text2 file-picture file-music file-play file-video location calendar search wrench cogs stats-dots hammer2 menu download2 question cross enter google-plus facebook instagram twitter medium linkedin drupal GitHub quotes-close
Chris standing under a heavy blanket.

Back in June, Code Enigma held its annual away week in Camos, Spain. We all had a wonderful time together, as we always do and I was able to lead a couple of short sessions for the developers, which I thought I'd summarise in this blog post.

I like theatrics. For my first session, I had found a box, which was about 300mm cubed. I'd made a hole in the top into which a single hand could fit. I'd also procured a deck of playing cards which I placed carefully inside the box, minding to keep it perfectly upright and steady as I explained to everyone that we were going to play a little game.

All that each player had to do was follow my instruction. As an example, I said an instruction might be:

"Take the card from the bottom of the pack."

Then I would move to the next player and give another instruction:

"Take the third card down from the top of the pack."

Of course, the catch being that the cards were inside the box.

To win, the players would have to follow my instructions perfectly. If they did, because I had rigged the deck ahead of time, we should finish the game with the first player holding the ace of hearts, the second player holding the two of hearts, the third player having the three of hearts and so on. If the cards were all hearts and in ascending order, that would be a win!

Now... what the players didn't know was that I hadn't put the cards in the box at all. Instead, I had rounded up the most random bunch of objects I could lay my hands on... to give you an idea of just some of the items that were in the box, I had:

  • a snooker ball
  • a small bluetooth speaker
  • my bank card
  • a couple of random cards from the game "Uno"
  • a pebble
  • my eldest daughters passport
  • a teddy
  • a toilet roll
  • my other daughters passport

Now, I know what you're thinking and let me assure you, this wasn't a serious attempt to offload my children onto my Code Enigma colleagues. I love them very dearly, my colleagues are very special and I would never burden them in such a way.

Having explained the rules, it was time to further add to the theatrics. I had borrowed a heavy double-bed spread and proceeded to get myself stood under it, which was quite a feat whilst holding the box steady. I explained that each player would take their turn without anyone else being able to see, that I would approach each player and envelop them under the big cover with me.

And so the game began.

Under the blanket I gave the instruction and each player stared at me confused and alarmed as they discovered not a pack of cards but all manner of things. I pretended to get impatient, "If you think it's gone wrong, don't worry, just pick any card and conceal it about your person.", so it went around the room.

There was a fair amount of laughter. I think people enjoyed the experience but I am not 100% certain, really.

Then came the reveal, "On the count of three, everyone hold up your cards!", of course, someone held the loo roll aloft whilst someone else presented an Uno card, someone else had a hair-brush and so on.

At this point, I revealed the reason I'd made up the game, I'd hoped it would be a fun way to remind everyone to...

NEVER USE ARRAYS!

Perhaps I'll write more about that in another blog post sometime.

The second session was a more practical one, more traditional, if you like.

I had recently picked up a ticket requesting that we add an API endpoint for the creation of users to an application, nothing special but the client have requested I supply an example blob of JSON so that they could know what to send in the payload.

Much better, I decided to create a JSON Schema.

JSON Schema is a great tool for describing the JSON an API will accept and provides clients with a schema to develop against. Ultimately, it avoids that point where developers of the service and of the client, end up on a call because of some data type mismatch bug is discovered a week before go live.

In addition to JSON Schema, there exists a bunch of tools written in a range of languages that will validate a blob of JSON against a JSON Schema. This is great for rapid feedback as you're developing the schema and also enables clients to test their JSON before the API endpoint is even developed. It perfectly avoids the situation where, because of timelines, separate teams are forced to work in parallel and when they come to join the two ends of the tunnel, there's a problem. 

JSON Schema is also evolved. Not only are you able specify data types, you can express dependencies: if this key is present with one of these values, then this other key must be present and so on.

Here's a simple example.

Say that our API endpoint expects the following JSON blob:

{
    "uuid": "d9675198-6d7e-4ccd-8dd1-b7a8a488160f",
    "firstname": "Chris",
    "lastname": "Example",
    "mail": "chris@example.com"
}

And that we want to express that all four properties are required, their data types, min and max lengths etc. We could achieve this with the following JSON Schema.

{
    "$schema": "https://json-schema.org/draft/2020-12/schema",
    "title": "User",
    "description": "JSON Schema for user",
    "type": "object",
    "required": [
        "uuid",
        "firstname",
        "lastname",
        "mail"
    ],
    "additionalProperties": false,
    "properties": {
        "uuid": {
            "description": "A UUID",
            "type": "string",
            "format": "uuid",
            "minLength": 36,
            "maxLength": 36
        },
        "firstname": {
            "description": "Forename",
            "type": "string",
            "minLength": 1,
            "maxLength": 255
        },
        "lastname": {
            "description": "Surname",
            "type": "string",
            "minLength": 1,
            "maxLength": 255
        },
        "mail": {
            "description": "An email address",
            "type": "string",
            "format": "email",
            "minLength": 3,
            "maxLength": 254
        }
    }
} 

The $schema is the version of JSON Schema you're using, the versions can be found at https://json-schema.org/specification

Beyond that, I think you'll agree that this schema is super-readable! I really appreciate how this can reduce the typical ambiguity you find when trying to thrash out these kind of details between disparate teams. Here there's no doubt, additionalProperties is set to false indicating that the client should not send anything other than what's specified in the schema.

As I mentioned before, there are many tools for validating JSON against a JSON Schema, there's a list of them at https://json-schema.org/tools

I wanted something I could use on the command line so I tried ajv-cli

It works really well. You have the ajv validator and then the ajv formats. There are installation instructions for each on the GitHub pages.

So given the two code samples above, the first saved as user.json and the schema saved as user.schema.json, I am able to run the following command to validate user.json

ajv validate -s user.schema.json -d user.json --spec=draft2020 -c ajv-formats

Which gives the reassuring output, "user.json is valid"

Tweak the user.json to make it invalid, changing the lastname to an integer, for example, and you'd get "user.json invalid" with the following:

[
  {
    instancePath: '/lastname',
    schemaPath: '#/properties/lastname/type',
    keyword: 'type',
    params: { type: 'string' },
    message: 'must be string'
  }
]

You can then bake your JSON Schema into your controller code if you so wish, so that incoming payloads are validated against the JSON Schema that you've developed, published and shared.

There's much, much more that you can do, the documentation for JSON Schema includes good examples.

I really like the way this plays into Design by Contract (DbC), also known as Contract Programming, Programming by Contract or Design by Contract Programming... or maybe it's just because I am old and I'm done with drama! I believe software should define formal, precise and verifiable interface specifications. I believe we should define formal, precise and verifiable interface specification.

I urge you, join the revolution!