LoopBack4の概要 & Examples validation-appを動かしてみる

最近LoopBack4を使ってAPIを作っているので、LoopBack4の概要をお伝えしたいです。

## LoopBack4の概要

Node.js TypeScript/ES2017で実装された主にAPI向けのWEBフレームワークです。
IBMが買収したStrongLoopの開発しているOSSで、MITライセンスで公開されています。

TypeScriptのDecorator(アノテーション)でDependency Injectionの定義を行ったり、Modelのプロパティに付与することでOpenAPIのドキュメントを生成することが可能です。

self-hostedのREST API Explorerがあり、Modelを書いたらすぐに参照できるので、コードとドキュメントが必ず一致します。

また、CLIが用意されており、基本的なコードを生成したり、Exampleをインストールすることが可能です。

https://loopback.io/index.html
https://github.com/strongloop/loopback-next

## 環境の前提条件

- macOS Catalina 10.15.5
- Node.js v14.1.0
- npm v6.14.5

## LoopBack4 CLIのインストール

```bash
$ npm i -g @loopback/cli
```

## Examplesのvalidation-app

Modelに定義した@property Decoratorや、Interceptorを利用したValidationのサンプルプロジェクトです。

https://github.com/strongloop/loopback-next/tree/master/examples/validation-app

### インストール

```bash
$ lb4 example validation-app
```

### 起動

```bash
$ cd loopback4-example-validation-app
$ npm runn start

> @loopback/example-validation-app@1.5.0 prestart /Users/tomiyan/dev/loopback4-example-validation-app
> npm run build


> @loopback/example-validation-app@1.5.0 build /Users/tomiyan/dev/loopback4-example-validation-app
> lb-tsc


> @loopback/example-validation-app@1.5.0 start /Users/tomiyan/dev/loopback4-example-validation-app
> node -r source-map-support/register .

Server is running at http://[::1]:3000
```

### REST API Explorer

ブラウザで
http://localhost:3000/explorer/
を開いてみてください。
下記のようなREST API Explorerが閲覧可能できるはずです。

これは、[Controller](https://github.com/strongloop/loopback-next/blob/ae09629e28202e0a09bd66fe92c41328d97b7a2f/examples/validation-app/src/controllers/coffee-shop.controller.ts)の`@get`、`@post`、`@patch`、`@put`、`@del`、`@param`、`@requestBody`や[Model](https://github.com/strongloop/loopback-next/blob/ae09629e28202e0a09bd66fe92c41328d97b7a2f/examples/validation-app/src/models/coffee-shop.model.ts)の`@property`を元に自動的に生成されます。

![スクリーンショット 2020-06-03 16.52.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45760/b88dc882-424c-cd8d-3193-bbf69dc2a97b.png)

### Validationの動作確認

POST /coffee-shopsのValidationを試してみましょう

[Controller](https://github.com/strongloop/loopback-next/blob/ae09629e28202e0a09bd66fe92c41328d97b7a2f/examples/validation-app/src/controllers/coffee-shop.controller.ts#L39-L46)の`@post`でModelのSchemaを参照するように定義されています。

また、[Controller](https://github.com/strongloop/loopback-next/blob/ae09629e28202e0a09bd66fe92c41328d97b7a2f/examples/validation-app/src/controllers/coffee-shop.controller.ts#L32)の`@intercept`でinterceptorが実行されるように定義されています。

[Model](https://github.com/strongloop/loopback-next/blob/ae09629e28202e0a09bd66fe92c41328d97b7a2f/examples/validation-app/src/models/coffee-shop.model.ts#L17-L50)では`@property`で下記のような`jsonSchema`が定義されています。

- city `string`
  - maxLength `10`
  - minLength `1`
- phoneNum `string`
  - pattern `\\d{3}-\\d{3}-\\d{4}`
- capacity `number`
 - maximum `100`
 - minimum `1`

[Interceptor](https://github.com/strongloop/loopback-next/blob/ae09629e28202e0a09bd66fe92c41328d97b7a2f/examples/validation-app/src/interceptors/validate-phone-num.interceptor.ts)では、`city`が'toronto'の場合、`phoneNum`のprefixが'416'か'647'でなければならないという実装がされています。

#### 正常系

```json:RequestBody
{
  "city": "tokyo",
  "phoneNum": "031-234-5678",
  "capacity": 1
}
```

Status Codeは200が返ってきます。

```json:ResponseBody
{
  "shopId": "1",
  "city": "tokyo",
  "phoneNum": "031-234-5678",
  "capacity": 1
}
```

※shopIdはインメモリデータベースで連番が振られます

![スクリーンショット 2020-06-03 17.45.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/45760/2010ae17-b34b-1043-511b-b9df44614e8a.png)

#### cityのmaxLengthを超えてみる


```json:RequestBody
{
  "city": "kasumigaura",
  "phoneNum": "031-234-5678",
  "capacity": 1
}
```

Status Codeは422が返ってきます。

```json:ResponseBody
{
  "statusCode": 422,
  "message": "My customized validation error message",
  "resolution": "Contact your admin for troubleshooting.",
  "code": "VALIDATION_FAILED"
}
```

#### cityがtorontoでphoneNumのprefixを'416'か'647'以外にしてみる


```json:RequestBody
{
  "city": "toronto",
  "phoneNum": "031-234-5678",
  "capacity": 1
}
```

Status Codeは400が返ってきます。

```json:ResponseBody
{
  "error": {
    "statusCode": 400,
    "name": "Error",
    "message": "Area code and city do not match"
  }
}
```

## まとめ

LoopBack4でのOpenAPIの定義やValidationの動きなどのさわりについて説明しました。
その他にも、Dependency InjectionやORMが備わっているフレームワークになっています。
興味がある方はそのへんも調べてみてはいかがでしょうか。

## 参考資料
- [@loopback/example-validation-app](https://github.com/strongloop/loopback-next/tree/master/examples/validation-app)