HTTP.jlで簡単なWebAPIを作る

JuliaでWebAPIサーバの作り方を勉強しているので、備忘録も兼ねて書き連ねていきます。

HTTP.jlを使うと簡単にWebサーバを建てることができます。 Genie.jlというJulia製のWebフレームワークがありますが、今回は使用しません。 なお、Genie.jlもHTTP.jlをベースに書かれているそうです。

まずは、インデックスルート"/"に対する簡単なHTTPサーバ構成を示します。

using HTTP

# ルータを用意
const ROUTER = HTTP.Router()

# ハンドラーを定義
function index(req::HTTP.Request)
    @show req
    return HTTP.Response(200, ["Content-Type" => "text/plain"], "hello, world")
end

# ルータにハンドラを登録する
HTTP.register!(ROUTER, "GET", "/", index)


# ローカルアドレス
address = Sockets.localhost
# ポート番号
port = 8080
# HTTPサーバ起動
HTTP.serve(ROUTER, address, port)
  • http://localhost:8080/にアクセスするとhello, worldが返ってきます。
  • ctrl + cで停止できます。

上記の例ではインデックスパス"/"に対してGETメソッドを受けたときのハンドラとしてindex関数を登録しています。 ハンドラ関数には引数HTTP.Request型を取る関数で、戻り値にはHTTP.Response型を返します。

こんな感じで、HTTP.jlを使うと簡単にWebサーバを建てることができます。

続いてこれをリクエストボディにJSONを返すAPIに書き換えていきます。

using JSON3

# indexを書き換える
function index(req::HTTP.Request)
    body = Dict{Symbol,String}(:message => "hello, world")
 # ヘッダーにJSONを返すことを示す
    headers = ["Content-Type" => "application/json"]
    return HTTP.Response(200, headers, JSON3.write(body))
end

# 再登録
HTTP.register!(ROUTER, "GET", "/", index)

# 再起動
HTTP.serve(ROUTER, address, port)

これで、http://localhost:8080/にアクセスすると{"message": "hello, world"}というJSONを返すようになります。 まず、JSON3パッケージを使うとJuliaのオブジェクトをJSONシリアライズすることができます。

# Julia -> JSON文字列
json = JSON3.write(Dict(:message => "message", :data => "data"))

# JSON文字列からJuliaオブジェクト
JSON3.read(json)
println(json.message)
println(json.data)

おまけ

ここで、JSON3.readが返すオブジェクトは汎用的なオブジェクトで、Juliaのユーザ定義型(構造体)にデシリアライズするためにはStructTypes.jlというパッケージを使うと実現できます。※Juliaの構造体に明示的にparseすることで、エラーチェックなどもついでに行うことができます。

using StructTypes

# ユーザ型を定義
struct RequestBody
    name::String
    email::String
end
# StructTypeに型を登録する
StructTypes.StructType(::Type{RequestBody}) = StructTypes.Struct()

body = """{
    "name": "taro",
    "email": "taro@example.com"
}"""
obj = JSON3.read(body, RequestBody)
println(obj) # RequestBody("taro", "taro@example.com")