echoで簡単なAPI実装してみる

2023/04/09に公開

背景

今までPHPとJavaしか実務で触ってこなかったのだが、今後、Goに触れる機会が出てきそうなので、試しに動かしてみたい。

echoとは

Goのフレームワーク。
人気なようだが、同じくGoのフレームワークであるGinの方が人気というか、シェアは多そうな印象。

軽量かつシンプルなwebアプリケーションが開発できる。
公式ドキュメント読めば使い方はちゃんとわかりそう。

公式ドキュメントは↓
https://echo.labstack.com/

試しに実装してみる

環境

M1 Mac
docker desktop 4.17.0

まずはインストール

公式ドキュメントのクイックスタートを参考にインストール

go mod init echo-practice
go get github.com/labstack/echo/v4

今回のファイル構成はこんなかんじ

.
├── Dockerfile
├── README.md
├── docker-compose.yml
├── go.mod
├── go.sum
├── server.go
├── tmp
│   └── main
└── user
    └── user.go

メイン処理実装

・server.go

package main

import (
	"echo-practice/user"
	"net/http"

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

func main() {
	e := echo.New()
	e.GET("/", func(c echo.Context) error {
		return c.String(http.StatusOK, "Hello, World!")
	})

	u := user.New(1, "testUser", 20)

	e.GET("/user", u.Get)
	e.POST("/user", user.Post)

	e.Logger.Fatal(e.Start(":1323"))
}

・user.go
とりあえず、GETは固定の値を返すのみ。POSTは受け取ったデータをログに出してメッセージ返すのみ。

package user

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

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

type User struct {
	Id       int64  `json:"id"`
	UserName string `json:"userName"`
	Age      int64  `json:"age"`
}

func New(id int64, userName string, age int64) *User {
	return &User{id, userName, age}
}

func (u *User) Get(c echo.Context) error {
	return c.JSON(http.StatusOK, u)
}

func Post(c echo.Context) error {
	var user User
	err := c.Bind(&user)
	if err != nil {
		return echo.NewHTTPError(400, "failed to bind request")
	}

	userData, err := json.Marshal(user)
	if err != nil {
		return echo.NewHTTPError(400, "failed to bind request")
	}

	log.Printf("User:%s", string(userData))

	jsonData, _ := json.Marshal(struct {
		Message string `json:"message"`
	}{
		Message: "ok",
	})
	return c.String(http.StatusCreated, string(jsonData))
}


コンテナ化

あとで使いやすいようにコンテナ化する。
ホットリロードできるようにairというライブラリも入れておく。
・Dockerfile

FROM golang:1.19-alpine as dev

ENV ROOT=/go/src/app
ENV CGO_ENABLED 0
WORKDIR ${ROOT}

RUN apk update && apk add git
RUN go install github.com/cosmtrek/air@latest
RUN apk add curl
CMD ["air", "-c", ".air.toml"]

・docker-compose.yml

version: '3.8'
services:
  app:
    build:
      context: .
      target: dev
      dockerfile: Dockerfile
    tty: true
    container_name: echo-practice
    volumes:
      - ./:/go/src/app
    ports:
      - 1323:1323

・.air.toml

# Config file for [Air](https://github.com/cosmtrek/air) in TOML format

# Working directory
# . or absolute path, please note that the directories following must be under root.
root = "."
tmp_dir = "tmp"

[build]
# Just plain old shell command. You could use `make` as well.
cmd = "go build -o ./tmp/main ."
# Binary file yields from `cmd`.
# bin = "tmp/main"
bin = "main"
# Customize binary, can setup environment variables when run your app.
full_bin = "APP_ENV=dev APP_USER=air ./tmp/main"
# Watch these filename extensions.
include_ext = ["go", "tpl", "tmpl", "html"]
# Ignore these filename extensions or directories.
exclude_dir = ["assets", "tmp", "vendor", "frontend/node_modules"]
# Watch these directories if you specified.
include_dir = []
# Watch these files.
include_file = []
# Exclude files.
exclude_file = []
# Exclude specific regular expressions.
exclude_regex = ["_test\\.go"]
# Exclude unchanged files.
exclude_unchanged = true
# Follow symlink for directories
follow_symlink = true
# This log file places in your tmp_dir.
log = "air.log"
# It's not necessary to trigger build each time file changes if it's too frequent.
delay = 0 # ms
# Stop running old binary when build errors occur.
stop_on_error = true
# Send Interrupt signal before killing process (windows does not support this feature)
send_interrupt = false
# Delay after sending Interrupt signal
kill_delay = 500 # ms
# Rerun binary or not
rerun = false
# Delay after each executions
rerun_delay = 500
# Add additional arguments when running binary (bin/full_bin). Will run './tmp/main hello world'.
# args_bin = ["hello", "world"]
args_bin = []

[log]
# Show log time
time = false
# Only show main log (silences watcher, build, runner)
main_only = false

[color]
# Customize each part's color. If no color found, use the raw app log.
main = "magenta"
watcher = "cyan"
build = "yellow"
runner = "green"

[misc]
# Delete tmp directory on exit
clean_on_exit = true

・コンテナ起動

docker-compose up -d

動作確認

ちゃんとレスポンスは返ってくる。

感想

とりあえず、echoで簡単なAPIをつくることはできた。
DB接続や外部APIとの通信は未実装なので、そのあたりも今後、実装してみたい。
あとはテストとかも。

Discussion