Simple backend system for frontend workshops in Javascript
Tags: javascript, backend, frontend, database
Published: 2019-05-29 11:19:13

---
title: Simple backend system for frontend workshops in Javascript
published: true
description: While teaching Javascript with or without React or Vue, it's hard to figure out what to do with backend. I built a simple system that can be plugged into any of them to act as backend, storage and API.
tags: javascript, backend, frontend, database
---

I coach in many programming workshops. If you have coached in one too, you might have noticed that it's challenging to find the right balance between depth and width. Especially in frontend workshops, I don't want to confuse students with building backends or API systems but I do want to provide them easy to use and extendable system.

I built a starter kit based on [create-react-app](https://github.com/facebook/create-react-app) that doesn't touch the basic React side of the frontend but adds a backend, couple of commands and an API client so that the user doesn't have to worry about doing HTTP calls themselves.

You can find my starter kit code from [Hamatti/cra-with-json-server](https://github.com/Hamatti/cra-with-json-server)

## My workshop philosophy

There are many ways to teach. Some take a theory-first approach and only advance to next thing when something has been sufficiently learned. It's a great approach for long-term learning but in short workshops (like a two-day workshop over a weekend), you end up not getting much done.

I like the way [Rails Girls](https://railsgirls.com) does it and my philosophy has been very much influenced by it. You get a lot of things done by taking advance of pre-built stuff. The point of the workshop is not to master things but to get interested, see all the different parts of building a project and deploying something to cloud to show to your friends.

When you then want to learn more, you can come back to certain steps and learn more about that.

## Backend Storage

Luckily, a friend of mine, [Johannes](https://twitter.com/jelmnai), introduced me to [`json-server`](https://github.com/typicode/json-server). It's a wonderful npm package that provides you with HTTP endpoints into data stored in a simple JSON file.

`json-server` is a tool that provides a lot more than what we're gonna go through today. It's great for prototyping and mocking APIs with a huge offering of endpoints. Today, we are mainly interested in simplest GET, POST, PATCH and DELETE endpoints.

As mentioned earlier, my first approach (I'm hoping to make it easier to plug in to any system later) was using create-react-app, so if you want to follow along, create a new app with

```
$ create-react-app my-new-project
```

and install `json-server`

```
$ npm install -g json-server
```

Next we create a JSON storage into `backend/db.json`. I also added a `backend/readme.md` that explains how to use it. Your `backend/db.json` can either start as an empty JSON


```json
{}
```

or if want to set it up for a tutorial, you can pre-populate it with collections you want. A collection in this case is just a key with an array of objects.

```json
{
  "authors": [
    {
      "name": "Juhis",
      "username": "hamatti",
      "email": "juhamattisantala@gmail.com"
    }
  ]
}
```

If you then run

```
$ json-server backend/db.json -p 3001
```

you will gain API access into http://localhost:3001. You can try this by running a curl in a new terminal tab to fetch data:

```bash
$ curl http://localhost:3001/authors
```

You should see 

```json
[
  {
    "name": "Juhis",
    "username": "hamatti",
    "email": "juhamattisantala@gmail.com"
  }
]
```
in your terminal.

To make it simpler, I added a npm script to `package.json` to run it.

```json
"scripts": {
    "backend": "json-server ./backend/db.json -p 3001"
}
```

Now you'll be able to start the backend API with `npm run backend` and you don't have to know what happens behind the scenes.

## API

In `src/api/apiClient.js`, I've created basic getters and setters to access the data in API:

```javascript
import axios from "axios";

const config = {
  baseURL: "http://localhost:3001",
  headers: {
    "Content-Type": "application/json"
  }
};

const client = axios.create(config);
```

I'm using axios for calls and create a client with the configuration. After the setup, I have these functions for interacting with the API.

```javascript
export function getAuthors(ctx) {
  return client.get("/authors").then(({ data }) => {
    ctx.setState({
      authors: data
    });
  });
}

export function updateAuthors(id, data) {
  return client.patch(`/authors/${id}`, data);
}

export function createAuthors(data) {
  return client.post(`/authors`, data);
}
```

With this simple setup, an user should never have to touch `backend/` folder nor the `src/api/` folder, they just need to import them where they wish to query the API.

The first function, `getAuthors` is currently very React specific: it expects a parameter to be `this` of a stateful React component and it saves the data directly into the state.

## Build new endpoints

A basic workshop can be done with just pre-defined data structure and endpoints but it's most fun when people can decide themselves what data to add.

So let's add a functionality to create that on the fly. **This script is currently not the most error-proof: if you run it twice with the same input, it will break.**

In `package.json`, I added a new script:

```
"scripts": {
    "generateAPI": "node generateAPI.js"
}
```

and the file `generateAPI.js`:

```javascript
"use strict";

const fs = require("fs");
const DB_PATH = "backend/db.json";
const API_CLIENT_PATH = "src/api/apiClient.js";

let key = process.argv[2];
if (!key) return;
key = key.toLowerCase();

let originalData = JSON.parse(fs.readFileSync(DB_PATH));
originalData[key] = [];

// Write to file
fs.writeFileSync(DB_PATH, JSON.stringify(originalData));

const titleCase = `${key.charAt(0).toUpperCase()}${key.substr(1)}`;

const newFunctions = `export function get${titleCase}(ctx) {
    return client.get("/${key}").then(({ data }) => {
      ctx.setState({
        ${key}: data
      });
    });
  }


  export function update${titleCase}(id, data) {
    return client.patch(\`/${key}/\${id}\`, data);
  }


  export function create${titleCase}(data) {
    return client.post("/${key}/", data);
  }`;

const originalApiClient = fs.readFileSync(API_CLIENT_PATH);

const newApiClient = `${originalApiClient}\n\n${newFunctions}`;

fs.writeFileSync(API_CLIENT_PATH, newApiClient);

console.log(`${key} was added into the database and API.

You can now import new functions with

    import { get${titleCase}, update${titleCase} and create${titleCase} } from './api/apiClient';

and you will have access to the data.`);

```

It's rather simple: you run it with `npm run generateAPI [model]` and it adds `model` into `backend/db.json` as a `"model": []` collection as well as generates `get[Model]`, `update[Model]` and `create[Model]` functions into `src/api/apiClient.js`.

It's a rather hacky system for now but with my testing, it works quite nicely. With a simple npm script command, you can add new collections into your storage and just import the new functionality from `apiClient.js`.