Adding Our First Endpoint


Creating directories, installing dependencies, adding our project files to git, even setting up TypeScript... all necessary, but all really rather dull.

Far more interesting is the act of creating a server, putting it "online", sending in requests, and seeing responses.

There's very little we truly need to do to get a Koa JSON API online. Here goes:

mkdir src
touch src/server.ts

Into our src/server.ts file, we will add the following contents:

import Koa from "koa";
import bodyParser from "koa-bodyparser";
import cors from "koa2-cors";
import logger from "koa-logger";

const app = new Koa();

const PORT = process.env.PORT || 7654;

app.use(bodyParser());
app.use(
  cors({
    origin: "*"
  })
);
app.use(logger());

const server = app
  .listen(PORT, async () => {
    console.log(`Server listening on port: ${PORT}`);
  })
  .on("error", err => {
    console.error(err);
  });

export default server;

We'll cover each of these steps in more detail in the video.

That's just a touch beyond the bare bones. We don't need the bodyParser, cors, or logger middleware to bring our server online. But they are all very useful in any real project, so we're going to include them right from the get-go.

At this stage we can bring our server online:

npm run start

> koa-ts-tutorial@1.0.0 start /home/chris/Development/koa-ts-tutorial
> ts-node-dev src/server.ts

Using ts-node version 3.3.0, typescript version 3.5.3
Server listening on port: 7654

Great!

But... it doesn't do very much, does it?

Adding Our First Route

To demonstrate something quickly, we will add a route inside the server.ts file. As we advance through this tutorial, we will cover extracting this kind of thing out into its own file. But for now, simplicity is easiest.

import Koa from "koa";
import bodyParser from "koa-bodyparser";
import cors from "koa2-cors";
import logger from "koa-logger";

const app = new Koa();

const PORT = process.env.PORT || 7654;

app.use(bodyParser());
app.use(
  cors({
    origin: "*"
  })
);
app.use(logger());

// NEW STUFF BELOW
import Router from "koa-router";
const router = new Router();

router.get(`/`, async (ctx) => {
  try {
    ctx.body = {
      status: "success",
    };
  } catch (err) {
    console.error(err);
  }
});

app.use(router.routes());
// NEW STUFF ABOVE

const server = app
  .listen(PORT, async () => {
    console.log(`Server listening on port: ${PORT}`);
  })
  .on("error", err => {
    console.error(err);
  });

export default server;

Alright, we're having a good time.

Due to ts-node-dev handling our TypeScript (re)compilation and helpfully restarting our server for us auto-magically (see package.json's scripts.start for why that works), our server should have automatically restarted and we can send in a GET request to 0.0.0.0:7654/ and see a 200 / happy response:

{
    "status": "success"
}

If that isn't blowing your socks off, then I feel sad for you.

Remember back to the late 1990's (if you're old enough), or the early to mid 2000's. Code was often procedural. Everything in one file. Why use more than a single file though? Got to preserve those precious inodes.

Well, I hate everything in one file. Beyond about 20 lines my brain just says... nope!

Let's tidy up our house in the very next video.

Episodes