IntelliJ IDEAのHTTP Client プラグインの使い方メモ

# 概要

IntelliJ IDEA Ultimate Editionにデフォルトでバンドルされている[HTTP Client] (https://plugins.jetbrains.com/plugin/13121-http-client)プラグインの使い方をまとめたメモです。
HTTP Clientを利用するとIntelliJ IDEAのコードエディターの機能を使ってHTTPリクエストを記述し、そのまま実行することができます。

※VSCodeにもRest Clientという拡張機能がありますが、それと似たような機能です。

**環境**

* Windows 10 Professional 20H2
* IntelliJ IDEA 2020.1.2 Ultimate Edition

**参考**

* [HTTP client in IntelliJ IDEA code editor] (https://www.jetbrains.com/help/idea/http-client-in-product-code-editor.html)
* [IntelliJ's text based HTTP client] (https://www.mscharhag.com/intellij/http-client)

# はじめかた

### Http Clientプラグインのインストール

HTTP Clientプラグインは、すでにインストールされているのですぐに使い始めることができます。
ただし、Community Editionでは利用できません。
![Screenshot_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/de444f58-30a0-c121-1c35-6c85b3091dcb.png)

## HTTPリクエストファイルの作成

最初にHTTPリクエストファイルの作成を行いますが、このファイルにはスクラッチなHTTPリクエストファイルと、そうでない（通常の）HTTPリクエストファイルの2種類あります。
どちらもHTTPリクエストの書き方に違いはありませんが、それぞれ下記の特徴があります。

### スクラッチなHTTPリクエストファイルの作成

※オフィシャルなドキュメントでは`Create an HTTP request scratch file﻿`と記述されているので、この記事では”スクラッチなファイル” や ”スクラッチファイル”と表記しました。

スクラッチなファイルは開発中のAPIをテストするためのものでプロジェクト外に作成され、プロジェクトとは別に管理されます。（なのでプロジェクトがバージョン管理されていてもスクラッチファイルは管理外です。）

もう1つの特徴として、HTTPリクエストを実行するとレスポンスファイルへのリンクがスクラッチファイルに追記され、実行結果（レスポンス）を後から確認できます。（詳しくは後述します）

**スクラッチファイルの作成**

スクラッチファイルの作成は、メニューバーの`File` → `New` → `Scratch File`を選択するか、<kbd>Ctrl + Shift + Alt + Insert</kbd>を押下します。
![Screenshot_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/1f68fb9e-b22b-69aa-2c8f-b631b8675f53.png)

httpと入力してメニューの絞り込みを行い`HTTP Request`を選択します。
![Screenshot_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/6dc744b0-4919-a04b-a09e-7527726d0218.png)

スクラッチファイルを作成する場所は選べず、図の場所にscratch.httpという名前のファイルが作成されます。
ファイルはいくつでも作成できますが、2つ目以降はscratch_1.httpのように枝番が付きます。
![Screenshot_8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/435234c6-add3-74d4-d318-827a6c372f47.png)

### HTTPリクエストファイルの作成

※オフィシャルなドキュメントでは`Create a physical HTTP request file`と記述されています。

HTTPリクエストファイルはプロジェクト内に作成されるので、プロジェクトをバージョン管理している場合はこのファイルも管理対象（除外していなければ）になります。
このファイルは主にAPIの文書化（仕様や使用例）を目的としているようです。

スクラッチファイルではAPIテストでHTTPリクエストを実行するとレスポンスファイルへのリンクが追記されましたが、このファイルでは追記は行われません。

**ファイルの作成**

ファイルの作成は、プロジェクトを（作成したいディレクトリがあればそのディレクトリを）フォーカスした状態で、メニューバーの`File` → `New` → `HTTP Request`を選択します。
![Screenshot_9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/6db9d1bb-255e-b1e8-38de-23b7cf33bd35.png)

ファイルの名前を入力します。この例ではapi-specとしました。
![Screenshot_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/9437ee4c-bd50-10fb-2480-0d802421e503.png)

選択した場所にファイルが作成されます。
![Screenshot_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/60054548-ca1f-44d1-75e4-36a433c01aa4.png)


## HTTPリクエストの記述と実行

### HTTPリクエストの構文

HTTPリクエストの一般的な構文は下記の通りです。

```text
Method Request-URI HTTP-Version
Header-field: Header-value

Request-Body
```

この中で必須のパートは`Request-URI`で、その他はHTTPリクエストによって省略できる場合があります。
たとえば下記のGETリクエストの場合

```
GET http://localhost:8080/memo/1 HTTP/1.1
```

`Method`と`HTTP-Version`は省略できるので

```
http://localhost:8080/memo/1
```

と記述することができます。

POSTする場合は`Method`は省略できないので

```
POST http://localhost:8080/memo
```

のようになります。

### 記述

コードエディターで直接HTTPリクエストを記述する方法の他に、エディターパネルの上部にある`Add Request`というリンクをクリックしてテンプレートから展開することもできます。
テンプレートの種類は図の通りです。
![Screenshot_12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/e407e985-b3ab-2e74-1e1a-8e886a55ac9d.png)

図がGET Requestのテンプレートを展開した結果です。
![Screenshot_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/59c1ac31-32e9-e225-9c37-185444598637.png)

テストするAPIにあわせてHTTPリクエストの記述を修正します。
この例では以下のように書き直しました。

```text
###
GET http://localhost:8080/memo/1
Accept: application/json

###
```

**コメント行**

HTTPリクエストファイルにコメント行を記述できます。
`//` または `#`で始まる行がコメントとして扱われます。

```
// コメント行

# コメント行
```

**複数のHTTPリクエストを記述する**

1つのファイルに複数のHTTPリクエストを記述する場合、`###`で始まる行でセパレートします。
セパレートには下記のようにコメントも記述できます。

```text
### Get memo
GET http://localhost:8080/memo/1
Accept: application/json

### Get multiple memos
GET http://localhost:8080/memo/ids/1,2,3
Accept: application/json

```

### コード補完

HTTPリクエストの記述ではコード補完が利用できます。
例えば図のように途中まで入力し、<kbd>Ctrl + Space</kbd>を押下すると候補が表示されます。
![Screenshot_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/27c6b16f-05fd-c141-3239-8bf7f8bac3c4.png)

### HTTPリクエストの実行

実行は行番号の右側にある緑色のRunアイコンをクリックします。
![Screenshot_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/7ce1fa96-4f52-d5ff-6a06-8eca79fffde0.png)

レスポンスが画面下部のウィンドウに表示されます。レスポンスはレスポンスファイルという別のファイルに記録されていて、後述する方法でいつでも確認することができます。
![Screenshot_15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/357b2d93-cb0f-5e18-fd07-4436a28c9f61.png)

スクラッチファイルの場合は、HTTPリクエストを実行すると図のようにレスポンスファイルへのリンクが書きこまれます。この行にカーソルを置いて<kbd>Ctrl + B</kbd>を押下するか、<kbd>Ctrl</kbd>を押しながらクリックすると、そのレスポンスファイルを確認することができます。
![Screenshot_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/7395dedc-0603-f9c1-c09f-3153be3fc287.png)

実行するたびにレスポンスファイルへのリンクがスクラッチファイルに書きこまれていきますが、書き込みが2件以上あると図のように行番号の右にコンペアアイコンが表示され
![Screenshot_16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/a77f6121-c695-6bd1-05e0-9f6a203e38a9.png)

クリックするとレスポンスファイルをコンペアすることができます。(どれとコンペアするか選択します）
![Screenshot_17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/0cf21f95-7314-ec22-68c4-467c6a8023e0.png)

図がコンペア結果の画面ですが、この例はAPIがレスポンスしたJSONデータになります。
![Screenshot_18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/16083877-3074-c01d-4734-f826a0867d6f.png)

### レスポンスファイルの確認

レスポンスファイルはプロジェクトの`.idea/httpRequests/`ディレクトリ下に作成されています。
![Screenshot_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/32a79b07-6e6a-3107-2060-85569cd4d0e7.png)

スクラッチファイルでは、HTTPリクエストを実行するとレスポンスファイルへのリンクがスクラッチファイルに追記されますが、そのリンク先はここにあるレスポンスファイルになります。

なお、制限として直近50件分のレスポンスファイルしか保存されません。

### curl記法のコンバート

もう1つの便利な機能としてcurlの記法を変換する`Convert cURL requests`というリンクがあります。
クリックするとcurl記法のHTTPリクエストを入力するダイアログが表示されるので、図のように入力し`convert`ボタンをクリックするとHTTPリクエストに変換されます。
![Screenshot_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/01a634e6-112b-4234-82d9-58353a327b96.png)

なお、curlのすべてのオプションをサポートはしていないので注意が必要です。（サポートしているオプションは [Convert cURL requests] (https://www.jetbrains.com/help/idea/http-client-in-product-code-editor.html#converting-curl-requests) で確認できます）

**curl記法のHTTPリクエスト**

```
curl -v -H "Content-Type:application/json" -d @memo_1.json -X POST "http://localhost:8080/memo"
```

**変換されたHTTPリクエスト**

```
# curl -v -H "Content-Type:application/json" -d @memo_1.json -X POST "http://localhost:8080/memo"
POST http://localhost:8080/memo
Content-Type: application/json

< memo_1.json
```


## 環境変数

環境変数を登録することができます。環境変数を管理するファイルはエディターパネルの上部にある`Add Environment File`というリンクをクリックして作成します。
図の通り環境変数ファイルには`Regular`と`Private`の2種類あります。
![Screenshot_19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/ebfcd4e5-2a6a-b73a-0763-915641ce87be.png)

**Regular**

> for common variables such as host or query parameters.
> \---------------------------------------------
> ホストやクエリパラメータなどの一般的な変数用

Regularな環境変数ファイルを作成するとプロジェクトルートに`http-client.env.json`というファイルが作成されます。上記に引用したようにホスト名やクエリパラメータなど一般的な変数を記述します。

下記は一例ですが、"dev"や"prod"が環境名でその1階層下に定義されているのが環境毎の環境変数です。

```json
{
  "dev": {
    "baseUrl": "localhost:8080/memo"
  },
  "prod": {
    "baseUrl": "www.example.com/memo"
  }
}
```

**Private**

> for sensitive data such as passwords or tokens.
> \---------------------------------------------
> パスワードやトークンなどの機密データ用

Privateな環境変数ファイルを作成するとプロジェクトルートに`http-client.private.env.json`というファイルが作成されます。上記に引用したようにパスワードやトークンなどを記述します。
なお、こちらのファイルをバージョン管理したくない場合、例えばGitだと.gitignoreファイルに記述する必要があります。

```json
{
  "dev": {
    "api-token": "jgl6H%&S0"
  },
  "prod": {
    "api-token": "Hem3k%:Q0"
  }
}
```

### 環境変数を使う

環境変数ファイルに定義した環境変数をHTTPリクエストファイル内で利用するには`{{ }}`というプレースフォルダを使います。

例えば、下記の書き方を

```
GET http://localhost:8080/memo/1
```

環境変数を使って書くと

```
GET http://{{baseUrl}}/1
```

となります。`{{baseUrl}}`の部分が環境変数になります。

### 実行する

環境変数ファイルが作成されていると、実行時に環境変数を選択します。
![Screenshot_21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/b95e689c-e917-aca0-1080-8cbf63adaeac.png)

### 動的な変数を使う

事前定義済みの実行時に値が変わる動的な変数が3つあります。

|name       |description |
|:----------|:--------------------------------------------|
|$uuid      |UUID v4で一意な値を生成します                  |
|$timestamp |現在のUNIX timestampを生成します               |
|$randomInt |0から1000の間でランダムなintegerを生成します    |

```text
GET http://localhost:8080/memo/{{$randomInt}}
```


# その他の利用例

## Cookie

### Cookieの受信

HTTPリクエストを実行しレスポンスでCookieを受信した場合、レスポンス結果にメッセージが表示されます。
![Screenshot_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/f4c07b1d-b4dd-7706-d3a4-ef4f067495a6.png)

このメッセージの通り、受信したCookieはプロジェクトの`.idea/httpRequests/http-client.cookies`というファイルに保存されています。（300件まで保存できます）
このファイルの保存されたCookieは、指定されたドメインとパスに一致するURLのHTTPリクエストに自動的に含まれます。

### Cookieの送信

任意のCookieを送信するようにHTTPリクエストファイルに記述するには、下記のように構文`Header-field`に`Cookie:`を使用します。

```
Cookie: key1=cookie-value-1
Cookie: key2=cookie-value-2
```

## JSONデータをPOSTする

### JSONデータを直接記述する

HTTPリクエストファイルの中にPOSTするJSONデータを記述する方法です。
下記のように構文の`Request-Body`部分にJSONフォーマットの文字列を記述します。

```
POST http://localhost:8080/memo
Content-Type: application/json

{
  "title": "new memo title",
  "description": "new memo description",
  "done": false
}
```

### JSONファイルをPOSTする

JSONデータが書かれたファイルをPOSTすることもできます。
下記のようにPOSTしたいファイルを`<`記号の後に続けて指定します。

```
POST http://localhost:8080/memo
Content-Type: application/json

// specify json file
< ./json/new_memo.json
```

上記の例では相対パスでJSONファイルを指定していますが、パスはプロジェクトルートからの相対パスになります。

## 画像をアップロードする

画像ファイルのPOST（アップロード）は下記のように記述します。

```
POST localhost:8080/upload
Content-Type: multipart/form-data; boundary=WebAppBoundary

--WebAppBoundary
Content-Disposition: form-data; name="file"; filename="demo.jpg"

< ./images/demo.jpg
--WebAppBoundary--
```

## Response handler scriptsでレスポンスを検証する

response handler scriptsという機能があり、HTTPリクエストファイルにレスポンスを検証するJavaScriptコードを記述することができます。

スクリプトは下記のように`>`記号で始め、本体を`{% ... %}` に記述します。

```
GET http://localhost:8080/memo/1
Accept: application/json

> {%
// Response Handler Script
...
%}
```

なお、スクリプトは JavaScript ECMAScript 5.1で記述する必要があるので`const`や`let`といったキーワードは使用できません。

### HTTP Response Handler library

* 参考: [HTTP Response handling API reference] (https://www.jetbrains.com/help/idea/http-response-handling-api-reference.html)

スクリプトでは`client`と`response`という2つのライブラリが利用できます。

**レスポンスの検証**

レスポンスの検証には`client.test`および`client.assert`を利用します。

```
client.test("Request executed successfully", function() {
    client.assert(response.status === 201, "Response status is not 201");
});
```

assertが失敗するとTestsウィンドウにメッセージが出力されます。
![Screenshot_8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/c7ce0974-5c12-09bb-911e-c991bc45e857.png)

**レスポンスデータ**

レスポンスデータは`response.body`でアクセスできます。
content-typeが`application/json`の場合、`response.body`にはJSONオブジェクトが格納されています。

例えば、下記のようなjsonがレスポンスされたとき`response.body.id`や`response.body.title`のようにアクセスできます。

```json
{
  "id": 15,
  "title": "new Memo Title",
  "description": "new Memo Description",
  "done": false,
  "createAt": "2020-07-13T12:34:13.1830192",
  "updateAt": null
}
```

**ログ出力**

`client.log`を利用するとResponse Handlerウィンドウにログを出力することができます。

```
client.log("ログ出力");
```

![Screenshot_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22772/6cf5d487-b7be-0588-67ef-6efd0a7b5209.png)

### レスポンスからグローバル変数をセットする

`client.global`というグローバル変数を保存できるストレージがあります。グローバル変数に保存した値はHTTPリクエストの中で`{{varialble_name}}`というプレースフォルダで利用できます。

例えば、次のような使い方ができます。

**1) 新しいデータをPOSTし、そのレスポンスデータのIDをグルーバル変数に保存**

このHTTPリクエストで実行するスクリプトで、レスポンスデータのIDをグローバル変数`newId`にセットします。
ここでセットしたグローバル変数は、以降のHTTPリクエスト中で利用できます。（IntellIJ IDEAを終了するまで保存されます。）

```
POST http://localhost:8080/memo
Content-Type: application/json

{
  "title": "new Memo Title",
  "description": "new Memo Description",
  "done": false
}

> {%
    var newId = response.body.id;
    client.global.set("newId", newId);
%}
```

**2) 次のHTTPリクエストでグローバル変数を利用**

1)でセットしたグローバル変数`newId`を、このHTTPリクエストで利用します。

```
GET http://localhost:8080/memo/{{newId}}
Content-Type: application/json
```