[開発者必読]REST Clientを使って、HTTPリクエストを送る方法

API

VS Codeに「REST Client」という拡張機能があるのはご存知でしょうか?
Rest Clientを使うことで簡単にHTTPリクエストを投げられます。今回はGET、POST、POSTでCSVをアップロードするリクエストを作って試しています。

概要

REST ClientはVS Codeの拡張機能で、上記のアイコンをインストールすれば使用できます。「~.http」のファイルを作成して、HTTPリクエストを投げられます。
PostManで十分ですが、例えばdocker上でしかAPIの通信ができない場合、docker上にPostManを動かすのは難しいと思います。REST Clientだと、VS CodeでDockerにSSHして、そこでRest Clientを実行できるので便利です。

実例

REST Clientを試せるリポジトリを作りましたので、こちらを元に説明をしていきます。HTTPサーバーはGoで動くようになっています。

GitHub - SND1231/rest-client
Contribute to SND1231/rest-client development by creating an account on GitHub.

REST Clientを実行するファイル

REST Clientは拡張子が「.http」か「.rest」のファイルで実行できます。
リクエストを区切る時は「###」を使用して、隣にどのようなリクエストかをコメントしてます。
リクエスト共有で同じ値を使用できるように変数を定義できます。@auth = ok_tokenでauthという変数を定義していて、変数を使用する時は「{{ 変数 }}」と定義する。authの使い道は後述で説明するHTTPサーバーの認証で使用されます。
注意として、CSVをアップロードする処理はUTF-8で出力しているので、UTF-8で出力すると文字化けが起きる環境だとCSVアップロードの処理は失敗する。MacでShift-JISのCSVファイルを使おうとすると失敗します。

@auth = ok_token

### get
GET http://localhost:8080/test?id=3


### post
Post http://localhost:8080/test
Authorization: {{auth}}

{
    "id": 3,
    "name": "test"
}

### csv
Post http://localhost:8080/csv
Authorization: {{auth}}
Content-Type: multipart/form-data; boundary=boundary

--boundary
Content-Disposition: form-data; name="file"; filename="test.csv"
Content-Type: text/csv

< ./test.csv

--boundary
Content-Disposition: form-data; name="mode"

diff
--boundary--

HTTPサーバー

REST Clientを試すためのHTTPサーバーをGoで書いたもの。
「go run main.go」で実行ができる。
POSTとCSVのアップロード処理については、リクエストヘッダーのAuthorizationに「ok_token」が入っているかをチェックするミドルウェアを設定している。

package main

import (
	"encoding/csv"
	"encoding/json"
	"io"
	"log"
	"net/http"

	"github.com/go-chi/chi"
)

func main() {
	r := getRouter()
	err := http.ListenAndServe(":8080", r)
	if err != nil {
		log.Fatal(err)
	}
}

func getRouter() chi.Router {
	r := chi.NewRouter()
	r.Get("/test", get)
	// With(auth)で認証ミドルウェアを実行している
	r.With(auth).Post("/test", post)
	r.With(auth).Post("/csv", uploadCSV)
	return r
}

// 認証のミドルウェア
// ヘッダーのAuthorizationに「ok_token」が入ってない場合は401エラーで返す
func auth(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		auth := r.Header.Get("Authorization")
		if auth != "ok_token" {
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		next.ServeHTTP(w, r)
	})
}

// GETメソッド処理
// 受け取ったIDを返すだけ
func get(w http.ResponseWriter, r *http.Request) {
	log.Println("Get!!")
	id := r.FormValue("id")
	type response struct {
		ID string `json:"id"`
	}
	res := response{ID: id}
	http.Header.Add(w.Header(), "content-type", "application/json")
	http.Header.Add(w.Header(), "Access-Control-Allow-Origin", "*")
	v, err := json.Marshal(res)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Write(v)
}

// POSTメソッド処理
// 受け取ったID、名前を返すだけ
func post(w http.ResponseWriter, r *http.Request) {
	log.Println("Post!!")

	type response struct {
		ID   int    `json:"id"`
		Name string `json:"name"`
	}
	var res response

	err := json.NewDecoder(r.Body).Decode(&res)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	log.Println(res)
	http.Header.Add(w.Header(), "content-type", "application/json")
	http.Header.Add(w.Header(), "Access-Control-Allow-Origin", "*")
	v, err := json.Marshal(res)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Write(v)
}

// CSVのアップロード
// CSVの中身を出力している
func uploadCSV(w http.ResponseWriter, r *http.Request) {
	log.Println("CSV!!")
	file, _, err := r.FormFile("file")
	if err != nil {
		log.Println(err)
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	defer file.Close()

	csvReader := csv.NewReader(file)
	for i := 0; ; i++ {
		record, err := csvReader.Read()
		// 最後の行なので終了
		if err == io.EOF {
			log.Println("EOF")
			break
		}
		if err != nil {
			log.Println("error", err)
			break
		}
		log.Println(record)
	}
}

実行結果

GET

Goの出力

2024/06/15 15:18:08 Get!!

RestClientの出力

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Sat, 15 Jun 2024 06:18:08 GMT
Content-Length: 10
Connection: close

{
  "id": "3"
}

POST

Goの出力

2024/06/15 15:27:11 Post!!

RestClientの出力

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json
Date: Sat, 15 Jun 2024 06:27:11 GMT
Content-Length: 22
Connection: close

{
  "id": 3,
  "name": "test"
}

CSV

Goの出力

2024/06/15 15:28:18 CSV!!
2024/06/15 15:28:18 [ID 名前]
2024/06/15 15:28:18 [1 Taro]
2024/06/15 15:28:18 [2 Jiro]
2024/06/15 15:28:18 EOF

RestClientの出力

HTTP/1.1 200 OK
Date: Sat, 15 Jun 2024 06:28:18 GMT
Content-Length: 0
Connection: close

まとめ

今回はREST Clientについて解説をしてきました。
解説していきた内容を使えば、大体のAPIに対して対応ができるようになります。DELETEやPATCHなどは紹介しませんでしたが、POSTと同じように使えます。
他にもGoについて解説をした記事がありますので、興味がありましたら、そちらも見てもらえたらと思います。


【おすすめ記事のリンク】

コメント

タイトルとURLをコピーしました