Skip to content

echoでREST APIを実装

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

サンプルコード

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

ディレクトリ構成

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

プロジェクト作成

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

実装

internal/handler/

  • user_handler.go
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
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
go
package router

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

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

const basePath string = "/api/v1"
  • user_router.go
go
package router

import (
	"easyapp/internal/handler"

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

type userRouter struct {
	userHandler handler.UserHandler
}

func NewUserRouter(userHandler handler.UserHandler) Router {
	return &userRouter{userHandler: userHandler}
}

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

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

internal/app/

  • server.go
go
package app

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

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

func NewServer() *echo.Echo {

	e := echo.New()

	router.NewUserRouter(handler.NewUserHandler(usecase.NewUserUsecase())).SetRouting(e)

	return e
}

cmd/

  • main.go
go
package main

import (
	"easyapp/internal/app"
)

func main() {

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

起動

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

shell
go run cmd/main.go

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

shell
# /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を参照ください。ほとんど標準ライブラリ利用時のそれと変わりません。