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に慣れていない感じなので、頑張っていきましょう…。

Ubuntu Linux 20.04 LTSにOpenJDK 17をインストールする

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

OpenJDK 17が、2021年9月14日にリリースされました。

Oracle Releases Java 17

とはいえ、Ubuntu Linuxで使えるのはしばらく先だろうと思っていたのでそのままにしていたのですが。

気づくと使えるようになっていたので、インストールしておきます。

OpenJDK 17パッケージ

Ubuntu Linux 20.04 LTSでは9月末に使えるようになっていたみたいです。

openjdk-17 package : Ubuntu

こちらを今回インストールします。

環境

今回の環境はこちら。Ubuntu Linux 20.04 LTSです。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.3 LTS
Release:        20.04
Codename:       focal


$ uname -srvmpio
Linux 5.4.0-90-generic #101-Ubuntu SMP Fri Oct 15 20:00:55 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

OpenJDK 17をインストールする

まずは、openjdk-17-jdkの情報を見てみます。

$ apt show openjdk-17-jdk
Package: openjdk-17-jdk
Version: 17+35-1~20.04
Priority: optional
Section: universe/java
Source: openjdk-17
Origin: Ubuntu
Maintainer: OpenJDK Team <openjdk-17@packages.debian.org>
Bugs: https://bugs.launchpad.net/ubuntu/+filebug
Installed-Size: 55.3 kB
Provides: java-compiler, java-sdk, java10-sdk, java11-sdk, java12-sdk, java13-sdk, java14-sdk, java15-sdk, java16-sdk, java17-sdk, java2-sdk, java5-sdk, java6-sdk, java7-sdk, java8-sdk, java9-sdk
Depends: openjdk-17-jre (= 17+35-1~20.04), openjdk-17-jdk-headless (= 17+35-1~20.04), libc6 (>= 2.2.5)
Recommends: libxt-dev
Suggests: openjdk-17-demo, openjdk-17-source, visualvm
Homepage: https://openjdk.java.net/
Download-Size: 10.5 kB
APT-Sources: http://jp.archive.ubuntu.com/ubuntu focal-updates/universe amd64 Packages
Description: OpenJDK Development Kit (JDK)
 OpenJDK is a development environment for building applications,
 applets, and components using the Java programming language.

openjdk-17に関するパッケージは、これだけあるみたいです。

$ apt search openjdk-17
ソート中... 完了
全文検索... 完了
msopenjdk-17/focal 17.0.1+12-LTS-1 amd64
  OpenJDK Development Kit 17 (JDK) with Hotspot by Microsoft

openjdk-17-dbg/focal-updates 17+35-1~20.04 amd64
  Java runtime based on OpenJDK (debugging symbols)

openjdk-17-demo/focal-updates 17+35-1~20.04 amd64
  Java runtime based on OpenJDK (demos and examples)

openjdk-17-doc/focal-updates,focal-updates 17+35-1~20.04 all
  OpenJDK Development Kit (JDK) documentation

openjdk-17-jdk/focal-updates 17+35-1~20.04 amd64
  OpenJDK Development Kit (JDK)

openjdk-17-jdk-headless/focal-updates 17+35-1~20.04 amd64
  OpenJDK Development Kit (JDK) (headless)

openjdk-17-jre/focal-updates 17+35-1~20.04 amd64
  OpenJDK Java runtime, using Hotspot JIT

openjdk-17-jre-headless/focal-updates 17+35-1~20.04 amd64
  OpenJDK Java runtime, using Hotspot JIT (headless)

openjdk-17-jre-zero/focal-updates 17+35-1~20.04 amd64
  Alternative JVM for OpenJDK, using Zero

openjdk-17-source/focal-updates,focal-updates 17+35-1~20.04 all
  OpenJDK Development Kit (JDK) source files

現時点で自分の環境にインストールしているOpenJDK。

$ update-alternatives --list java
/usr/lib/jvm/java-11-openjdk-amd64/bin/java
/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java

ここに、OpenJDK 17を追加。

$ sudo apt install openjdk-17-jdk

OpenJDK 17が増えました。

$ update-alternatives --list java
/usr/lib/jvm/java-11-openjdk-amd64/bin/java
/usr/lib/jvm/java-17-openjdk-amd64/bin/java
/usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java

すでにデフォルトのJavaとして設定されているみたいです。

$ sudo update-alternatives --config java
alternative java (/usr/bin/java を提供) には 3 個の選択肢があります。

  選択肢    パス                                          優先度  状態
------------------------------------------------------------
* 0            /usr/lib/jvm/java-17-openjdk-amd64/bin/java      1711      自動モード
  1            /usr/lib/jvm/java-11-openjdk-amd64/bin/java      1111      手動モード
  2            /usr/lib/jvm/java-17-openjdk-amd64/bin/java      1711      手動モード
  3            /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java   1081      手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください:

確認。

$ java --version
openjdk 17 2021-09-14
OpenJDK Runtime Environment (build 17+35-Ubuntu-120.04)
OpenJDK 64-Bit Server VM (build 17+35-Ubuntu-120.04, mixed mode, sharing)

ちなみに、今回はjavaコマンドのみを対象にしていますが、その他javacなどのコマンドもひとつひとつ
update-alternatives --configで切り替えていく必要があります。

まあ、しばらくはOpenJDK 11かな…。

$ sudo update-alternatives --config java
alternative java (/usr/bin/java を提供) には 3 個の選択肢があります。

  選択肢    パス                                          優先度  状態
------------------------------------------------------------
* 0            /usr/lib/jvm/java-17-openjdk-amd64/bin/java      1711      自動モード
  1            /usr/lib/jvm/java-11-openjdk-amd64/bin/java      1111      手動モード
  2            /usr/lib/jvm/java-17-openjdk-amd64/bin/java      1711      手動モード
  3            /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java   1081      手動モード

現在の選択 [*] を保持するには <Enter>、さもなければ選択肢の番号のキーを押してください: 1
update-alternatives: /usr/bin/java (java) を提供するためにマニュアルモードで /usr/lib/jvm/java-11-openjdk-amd64/bin/java を使います