ラベル Tide の投稿を表示しています。 すべての投稿を表示
ラベル Tide の投稿を表示しています。 すべての投稿を表示

2020年8月31日月曜日

Rustを学ぶ(2.5) : RustでAPIサーバー (Responseを返す)

はじめに

前回は、GETとPOSTができるようになりました。

ただし、誤ったリクエストを送った時に、その誤りの理由までは教えてくれません。

また、任意のステータスコードを返せるようになったら、連携するアプリケーション側で考慮するステータスコードを絞れます。

今回は、以下の2つを実装します。

  1. GETとPOSTで/system/error にアクセスすると404が返り、「wrong resource access.」を返す
  2. POSTで/system/pingに'{"wrong":"error"}' でアクセスすると400が返り、「wrong request.」を返す


実装する前に

そもそも現在はどういうステータスコードが返るのでしょうか?

まずは1のGETをしてみます。

% curl localhost:8080/system/error -v
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 8080 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /system/error HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 404 Not Found
< content-length: 0
< date: Sun, 30 Aug 2020 00:16:52 GMT
<
* Connection #0 to host localhost left intact
* Closing connection 0

404が返ります。1のPOSTもしてみます。

% curl -XPOST localhost:8080/system/error -v
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 8080 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /system/error HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 404 Not Found
< content-length: 0
< date: Sun, 30 Aug 2020 14:21:27 GMT
<
* Connection #0 to host localhost left intact
* Closing connection 0

こちらも404です。理由は特に書かれていません。

2もやってみます。


% curl -XPOST localhost:8080/system/ping -d '{"wrong":"error"}'  -v
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 8080 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /system/ping HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
> Content-Length: 17
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 17 out of 17 bytes
< HTTP/1.1 422 Unprocessable Entity
< content-length: 0
< date: Sun, 30 Aug 2020 14:24:20 GMT
<
* Connection #0 to host localhost left intact
* Closing connection

422 (Unprocessable Entity)が返っています。これは正しそうな挙動ですが、アプリケーション側で422を考慮するコードを書く必要が出てきます。今のところ私しか使う人もいないですし、ここは400 (Bad Request)でいいと考えています。もし必要ならコードを読めばいいのです。

余談ですが、curlに"Note: Unnecessary use of -X or --request, POST is already inferred."と出ています。初めて知りましたが、実はXPOSTを付けなくても-dのPOSTデータがあれば、curlはPOSTで送ることを推測してくれるみたいです。


「GETとPOSTで/system/error にアクセスすると404が返り、「wrong resource access.」を返す」を実装する


1を実装します。

9~18行目までにtide::utils::Afterを使って、外にResponseを出す前に返すレスポンス処理を加えます。

curlでGETしてみます。


% curl localhost:8080/system/error -v
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 8080 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /system/error HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 404 Not Found
< content-length: 30
< date: Sun, 30 Aug 2020 15:25:11 GMT
< content-type: text/plain;charset=utf-8
<
Error: wrong resource access.
* Connection #0 to host localhost left intact
* Closing connection 0

POSTもしてみます。


 % curl localhost:8080/system/error -d '{"wrong":"error"}' -v
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 8080 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /system/error HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
> Content-Length: 17
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 17 out of 17 bytes
< HTTP/1.1 404 Not Found
< content-length: 30
< date: Sun, 30 Aug 2020 15:26:14 GMT
< content-type: text/plain;charset=utf-8
<
Error: wrong resource access.
* Connection #0 to host localhost left intact
* Closing connection 0

できているようです。


「POSTで/system/pingに'{"wrong":"error"}' でアクセスすると400が返り、「wrong request.」を返す」を実装する


2を実装していきます。

先ほどと同じように実装を追加していきます。16~20行目に追記しました。

curlしてみます。


% curl localhost:8080/system/ping -d '{"wrong":"error"}' -v
*   Trying ::1...
* TCP_NODELAY set
* Connection failed
* connect to ::1 port 8080 failed: Connection refused
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /system/ping HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
> Content-Length: 17
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 17 out of 17 bytes
< HTTP/1.1 400 Bad Request
< content-length: 22
< date: Sun, 30 Aug 2020 15:33:26 GMT
< content-type: text/plain;charset=utf-8
<
Error: wrong request.
* Connection #0 to host localhost left intact
* Closing connection 0

できてる!


おわりに

今回はResponseを任意のステータスコードで、任意のメッセージを返す実装をしました。

次回はDBへの疎通確認をしたいと思います。


参考文献

先輩と覚える HTTP ステータスコード


2020年8月24日月曜日

Rustを学ぶ(2) : RustでAPIサーバー (GETとPOST)

はじめに

前回、Rustの環境構築をしたので今回はサーバーを実装します。

単純なAPIサーバーとして以下の実装をしていきます。

  1. GET /system/pingでpongを返す
  2. POST /system/pingで{"ping" : "value"}を送ると、{"pong" : "value"}を返す

WebサーバーはTideを使います。Warpのような立ち位置にあり、簡単なWebサーバーを作ることができます。ちなみに、Tideはv0.13.0からProductionで使えるようになったようです。

Tideの起動


Tideを動かしてみます。

任意の場所でプロジェクトを作ります。

% cargo new example-tide
% cd example-tide

Cargo.tomlのdependenciesに以下を追記します。

[dependencies]
tide = "0.13.0"
async-std = { version = "1.6.0", features = ["attributes"] }

main.rsを以下に変更します。


ここまでできたらcargo runします。
試しにcurlしてみましょう。

% curl localhost:8080
Hello, world!

Webサーバーの起動に成功しました。

「GET /system/pingでpongを返す」を実装


以下のように5行目を変更します。


curlしてみましょう。

% curl localhost:8080/system/ping
pong

できましたが、APIサーバーとしては扱いやすいようにjsonで返したいです。

Rustでjsonといえばserde_jsonですが、Tideはすでにjson macroを持っています。
ですので、serde_jsonを使わずともjsonを返すことが可能です。
以下のように5行目を変更します。


curlしてみましょう。

% curl localhost:8080/system/ping
{"ok":"pong"}

jsonで返すことができました。

「POST /system/pingで{"ping" : "value"}を送ると、{"pong" : "value"}を返す」を実装する


6行目にPOSTを受け付ける記述を追記します。(この時点ではPOSTパラメータを無視しています)


curlしてみましょう。

% curl -XPOST localhost:8080/system/ping -d '{"ping":"value"}'
{"ok":"pong"}

やった!POSTで受付に成功しています。

それではPOSTパラメータを受け取り、値を返すようにします。
まずはserdeとserde_jsonをdependenciesに追加します。

[dependencies]
tide = "0.13.0"
async-std = { version = "1.6.0", features = ["attributes"] }
serde = "1.0.114"
serde_json = "1.0"

serdeは構造体をSerialize、Deserializeする時に使います。これで構造体を簡単にjsonにすることができます。(ここはもしかしたらTideがやってくれる...?)

以下のようにmainを修正します。


curlしてみましょう。

% curl -XPOST localhost:8080/system/ping -d '{"ping":"value"}'
{"pong":"value"}

できました!

おわりに


今回はTideでルーティング、GETとPOSTができるようになりました。

次回は、ちゃんとResponseを返す(ステータスコードなど)ところまでやりたいと思います。