Skip to content

echoでREST APIを実装

cf. https://echo.labstack.com/docs

サンプルコード

echoを使って簡易的なGETメソッドおよびPOSTメソッドを実装します。usecase配下はフレームワークに依存しないので省略します。

ディレクトリ構成

.
├── cmd
│   └── main.go
└── internal
    └── handler
        ├── user_handler.go
        ├── user_handler_test.go
        ├── model
           └── user_model.go
        └── router
            ├── user_router.go
            └── base.go

プロジェクト作成

  • 下記コマンドでGoモジュールを初期化します。
go mod init easyapp
  • echoをインストールします。
go get github.com/labstack/echo/v5

実装

internal/handler/

  • user_handler.go
package handler

import (
    "easyapp/internal/handler/model"
    "easyapp/internal/usecase"
    "easyapp/internal/usecase/params"
    "net/http"

    "github.com/labstack/echo/v5"
)

// 認証のhandlerインターフェースです。
type UserHandler interface {

    // 認証処理を呼び出します。
    Login(c *echo.Context) error

    // ユーザ情報取得処理を呼び出します。
    Me(c *echo.Context) error
}

type userHandler struct {
    userUsecase usecase.UserUsecase
}

func NewUserHandler(userUsecase usecase.UserUsecase) UserHandler {
    return &userHandler{userUsecase: userUsecase}
}

func (h *userHandler) Login(c *echo.Context) error {

    // jsonパースエラー発生時はStatus400を返す
    req, err := model.NewLoginReq(c)
    if err != nil {
        return c.JSON(
            http.StatusBadRequest,
            echo.NewHTTPError(
                http.StatusBadRequest,
                "Bad request",
            ),
        )
    }

    // usecase呼び出し
    out := h.userUsecase.Login(c.Request().Context(), params.NewLoginIn(req.Name, req.Password))

    return c.JSON(http.StatusOK, model.NewLoginRes(out.Valid()))
}

func (h *userHandler) Me(c *echo.Context) error {

    // クエリパラメータ取得
    req := model.NewMeReq(c)

    // usecase呼び出し 業務エラー発生時はStatus500を返す
    out, err := h.userUsecase.Me(c.Request().Context(), params.NewMeIn(req.Name))
    if err != nil {
        return c.JSON(
            http.StatusInternalServerError,
            echo.NewHTTPError(
                http.StatusInternalServerError,
                "Internal server error",
            ),
        )
    }

    return c.JSON(http.StatusOK, model.NewMeRes(out.Name(), out.Age()))
}

internal/handler/model/

  • user_model.go
package model

import (
    "errors"

    "github.com/labstack/echo/v5"
)

// 認証向けのリクエストモデルです。
type LoginReq struct {
    Name     string `json:"name"`     // ユーザ名
    Password string `json:"password"` // パスワード
}

func NewLoginReq(c *echo.Context) (LoginReq, error) {

    req := new(LoginReq)
    if err := c.Bind(req); err != nil {
        return LoginReq{}, errors.New("不正なリクエストです。")
    }

    return *req, nil
}

// 認証向けのレスポンスモデルです。
type LoginRes struct {
    Valid bool `json:"valid"` // 認証可否
}

func NewLoginRes(valid bool) LoginRes {
    return LoginRes{Valid: valid}
}

// ユーザ情報取得向けのリクエストモデルです。
type MeReq struct {
    Name string `json:"name"` // ユーザ名
}

func NewMeReq(c *echo.Context) MeReq {
    return MeReq{Name: c.QueryParam("name")}
}

// ユーザ情報取得向けのレスポンスモデルです。
type MeRes struct {
    Name string `json:"name"` // ユーザ名
    Age  int    `json:"age"`  // 年齢
}

func NewMeRes(name string, age int) MeRes {
    return MeRes{Name: name, Age: age}
}

internal/handler/router/

  • base.go
package router

import (
    "github.com/labstack/echo/v5"
)

type Router interface {
    SetRouting(e *echo.Echo)
}

const basePath string = "/api/v1"

func Routing() *echo.Echo {

    e := echo.New()

    NewUserRouter().SetRouting(e)

    return e
}
  • user_router.go
package router

import (
    "easyapp/internal/handler"
    "easyapp/internal/usecase"

    "github.com/labstack/echo/v5"
)

type userRouter struct{}

func NewUserRouter() Router {
    return &userRouter{}
}

func (r *userRouter) SetRouting(e *echo.Echo) {

    h := handler.NewUserHandler(usecase.NewUserUsecase())

    e.POST(basePath+"/login", h.Login)
    e.GET(basePath+"/me", h.Me)
}

cmd/

  • main.go
package main

import "easyapp/internal/handler/router"

func main() {

    e := router.Routing()
    if err := e.Start(":8080"); err != nil {
        e.Logger.Error("failed to start server", "error", err)
    }
}

起動

下記コマンドでアプリを起動します。

go run cmd/main.go

下記コマンドでAPIを打鍵できます。

# /login
curl -X POST -H 'Content-Type: application/json' -d '{"name": "nob", "password": "passwd"}' localhost:8080/api/v1/login
# /me
curl -X GET localhost:8080/api/v1/me?name=nob

APIドキュメントについて

APIドキュメントの記法についてはecho-swaggerを参照ください。ほとんど標準ライブラリ利用時のそれと変わりません。