CLOVER🍀

That was when it all began.

TypeScriptでExpress

これは、なにをしたくて書いたもの?

TypeScriptでExpressを使ってみようかなと。

簡単なGET、POST、それからテストを書いてみたいと思います。

環境

今回の環境は、こちらです。

$ node --version
v16.13.0


$ npm --version
8.1.0

準備

まずは、TypeScriptとJestを使う準備までしておきます。

$ npm init -y
$ npm i -D typescript
$ npm i -D -E prettier
$ npm i -D jest @types/jest ts-jest
$ npx ts-jest config:init
$ mkdir src test

tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "commonjs",
    "baseUrl": "./src",
    "outDir": "dist",
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "noImplicitOverride": true,
    "noImplicitReturns": true,
    "noPropertyAccessFromIndexSignature": true,
    "esModuleInterop": true
  },
  "include": [
    "src"
  ]
}

.prettierrc.json

{
  "singleQuote": true
}

Expressをインストールする

Node.js上なので、@types/nodeをインストール。

$ npm i -D @types/node

それから、Expressとtypesをインストール。

$ npm i express
$ npm i -D @types/express

現時点での依存関係は、こんな感じ。

  "devDependencies": {
    "@types/express": "^4.17.13",
    "@types/jest": "^27.0.3",
    "@types/node": "^16.11.9",
    "jest": "^27.3.1",
    "prettier": "2.4.1",
    "ts-jest": "^27.0.7",
    "typescript": "^4.5.2"
  },
  "dependencies": {
    "express": "^4.17.1"
  }

ソースコードを書く

それでは、TypeScript+Expressでソースコードを書いてみます。

こちらを見ながら

Express "Hello World" example

こんな感じで作成。

src/app.ts

import express from 'express';
import bodyParser from 'body-parser';

export const app = express();
app.use(bodyParser.json());

app.get('/echo', (req, res) => {
  const message = req.query['message'];

  res.send(`Hello ${message}!!`);
});

app.post('/echo', (req, res) => {
  const message = req.body['message'];

  res.send({ message: `Hello ${message}!!` });
});

GETならQueryString、POSTならBodyからメッセージを受け取って返すアプリケーションです。

今後のテストのために、起動部分は切り離しておきます。

src/server.ts

import { app } from './app';

const port = 3000;

app.listen(port, () =>
  console.log(`[${new Date().toISOString()}] start server[${port}]`)
);

では、ビルド。

$ npx tsc

動作確認してみます。

起動。

$ node dist/server.js
[2021-11-20T09:27:47.527Z] start server[3000]

確認。

## GET

$ curl localhost:3000/echo?message=Express
Hello Express!!


## POST

$ curl -H 'Content-Type: application/json' localhost:3000/echo -d '{"message": "Express"}'
{"message":"Hello Express!!"}

OKですね。

テストを書く

続いては、テストを書いてみます。

Jest+Expressでテストを書くにはどうしたら?と思ったのですが、Jestのページにヒントが書いてありました。

Testing Web Frameworks / Express.js

How to test Express.js with Jest and Supertest | Through the binary

SuperTestというものを使うみたいです。

GitHub - visionmedia/supertest: 🕷 Super-agent driven library for testing node.js HTTP servers using a fluent API.

SuperTestは、SuperAgentを利用したHTTPのアサーションライブラリです。

SuperAgentは、Node.jsやブラウザで使えるHTTPクライアントです。

SuperAgent — elegant API for AJAX in Node and browsers

というわけで、SuperTest、SuperAgentおよび型宣言をインストール。

$ npm i -D supertest superagent @types/supertest @types/superagent

SuperTestの依存関係にSuperAgentはついてくるんですけどね。

バージョン。

    "@types/superagent": "^4.1.13",
    "@types/supertest": "^2.0.11",


    "superagent": "^6.1.0",
    "supertest": "^6.1.6",

テストコードは、こんな感じに。

test/app.test.ts

import request from 'supertest';
import { app } from '../src/app';

test('get /echo', () => {
  return request(app)
    .get('/echo?message=Express')
    .then((response) => {
      expect(response.status).toEqual(200);
      expect(response.text).toEqual('Hello Express!!');
    });
});

test('post /echo', () => {
  return request(app)
    .post('/echo')
    .set('Content-Type', 'application/json')
    .send({ message: 'Express' })
    .then((response) => {
      expect(response.status).toEqual(200);
      expect(response.body).toEqual({ message: 'Hello Express!!' });
    });
});

SuperTestのrequestに、appインスタンスを渡します。

最初にソースコードを書いた時に、app#listenを呼び出す部分を別ファイルにしたのはこれが理由ですね。

では、テストを実行します。

$ npx jest

結果。

 PASS  test/app.test.ts
  ✓ get /echo (28 ms)
  ✓ post /echo (20 ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        4.035 s, estimated 7 s
Ran all test suites.

OKですね。

まとめ

TypeScriptでExpressを使い、テストも含めて書いてみました。

TypeScript+Expressの環境をどうやって作るのかがExpress側にはないので、いろいろ情報を探してみましたが
だいたいこんな感じで良さそうかなと思います。

まだまだTypeScriptに慣れていない感じなので、頑張っていきましょう…。