More hapi and Typescript - routes
Tags: hapi, typescript
Published: 2021-03-12 09:55:17

---
title: More hapi and Typescript - routes
published: true
date: 2021-03-12 01:00:00 UTC
tags: hapi,typescript
series: Using Hapi
canonical_url: https://www.solarwinter.net/more-hapi-and-typescript-routes/
---

[Last time we left it](https://dev.to/arafel/using-typescript-with-hapi-138j), the server only had a single route and was all in one file. That’s fine to start with but it’s not exactly scalable. Let’s add some routes from external files.

We’ll go for something similar to the traditional “hello world”. We’ll have a route, `/hello`, which will say “Hello World”. We’ll also add a route “under” that, `/hello/name`, which will greet `name`.

The files we produce here are all in the [Github repo](https://github.com/arafel/hapi-typescript).

## Test it!

Of course since we’re adding new functionality, we know what comes first…

The good news is that we don’t have any setup at all to do this time, and we can just go right ahead with the test file.

`test/hello.test.ts`:

```ts
import { Server } from "@hapi/hapi";
import { describe, it, beforeEach, afterEach } from "mocha";
import { expect } from "chai";

import { init } from "../src/server";

describe("server greets people", async () => {
	let server: Server;

	beforeEach((done) => {
		init().then(s => { server = s; done(); });
	})
	afterEach((done) => {
		server.stop().then(() => done());
	});

	it("says hello world", async () => {
		const res = await server.inject({
			method: "get",
			url: "/hello"
		});
		expect(res.statusCode).to.equal(200);
		expect(res.result).to.equal("Hello World");
	});

	it("says hello to a person", async () => {
		const res = await server.inject({
			method: "get",
			url: "/hello/Tom"
		});
		expect(res.statusCode).to.equal(200);
		expect(res.result).to.equal("Hello Tom");
	});
})

```

The imports are much the same. In fact almost all of this is the same structure as the `index` test - the only real different is that we have two tests in one `describe` block.

Since they’re so similar, I’m going to assume that’s understandable and move on. Before we do though, just to check it fails:

```bash
  server greets people
    1) says hello world
    2) says hello to a person

  smoke test
    ✓ index responds

  1 passing (70ms)
  2 failing

```

Okay, that does exactly what we expect and fails. Onwards…

## Code it!

### Routes

Again - no setup work this time, just code. Diving straight in - we want to keep these routes in a separate file. Using the obvious name…

`src/hello.ts`:

```ts
import { Request, ResponseToolkit, ResponseObject, ServerRoute } from "@hapi/hapi";

async function sayHello(request: Request, h: ResponseToolkit): Promise<ResponseObject> {
  const name: string = request.params.name || "World";
  const response = h.response("Hello " + name);
  response.header('X-Custom', 'some-value');
  return response;
}

export const helloRoutes: ServerRoute[] = [
  {
    method: "GET",
    path: "/hello",
    handler: sayHello
  },
  {
    method: "GET",
    path: "/hello/{name}",
    handler: sayHello
  }
];

```

Okay, this one has a bunch more types we haven’t seen before. Ignoring the `Request` type we met last time, we’ve just met:

- [`ResponseToolkit`](https://hapi.dev/api/?v=20.1.0#response-toolkit) - if you’re not using [Vision](https://github.com/hapijs/vision) to render templates, the toolkit is the thing you’ll usually use to send your response down. You can generate a response as seen above,
- [`ResponseObject`](https://hapi.dev/api/?v=20.1.0#response-object) is what the `ResponseToolkit` produces - seems reasonable, right? A lot of the stuff in there you can probably leave alone; you might need things like [`response.code`](https://hapi.dev/api/?v=20.1.0#-responsecodestatuscode) to explicitly set a status code.
- [`ServerRoute`](https://hapi.dev/api/?v=20.1.0#route-options) is exactly what it sounds like, a route defined on the server. The routes above are about as simple as you get - the HTTP method, the path, and the function to handle it.

In the route definitions, `/hello/{name}` tells hapi to capture the path component after `/hello/` and place it in the `request.params` object.

That’s all you need to do, and here you start to see some of the differences between hapi and Express - body/request parsing is already included and handled, batteries are included, no plugins required. It makes it simple to use the same function to handle both routes.

Important note - in real life, **do not** simply take user parameters and echo them back. Use something like [Hoek’s escapeHtml()](https://hapi.dev/module/hoek/api/?v=9.1.1#escapehtmlstring).

### Server

Plugging these routes into the server is simple. Import the route array:

`src/server.ts`:

```ts
import { helloRoutes } from "./hello";

```

Add it to the server:

```ts
server.route(helloRoutes);

```

And that’s it, we should be done. Of course we have to know…

```bash
$ yarn test
yarn run v1.22.10
$ NODE_ENV=test mocha -r ts-node/register test/**/*.test.ts

  server greets people
    ✓ says hello world
    ✓ says hello to a person

  smoke test
    ✓ index responds

  3 passing (63ms)

✨ Done in 3.05s.

```

Perfect. :-)