LoginSignup
2

More than 1 year has passed since last update.

【Go】BeegoでAPI構築してみる

Last updated at Posted at 2022-06-17

これはなに?

  • WebフレームワークBeegoを使ってAPIサーバを立ててみる記事
  • 本記事では、BeegoインストールからbeeコマンドによるAPI構築まで試す

環境

  • Go: 1.18.3
  • Beego: 2.0.1
  • Bee: 2.0.4

注意

2022年8月現在、beegoの公式Docsのドメインが以前の beego.me から beego.vip に変更になっているようなので注意。
以前のドメイン踏むと全く関係ないサイトに誘導されるので要注意。

v2.0.0以前のREADMEのCommunity欄 を見ると以前のドメインとなっている。
v2.0.3以降のREADMEのCommunity欄 では現在(2022年8月)のドメイン。

前準備

Docker環境整備

ディレクトリ構成
.
├── api
│   └── docker
│       └── Dockerfile
└── docker-compose.yml
Dockerfile
FROM golang:1.18.3-alpine3.16

ENV ROOT /go
ENV CGO_ENABLED 0

WORKDIR ${ROOT}

RUN apk update && apk add --no-cache git
docker-compose.yml
version: '3'
services:
  api:
    container_name: practice-beego-api
    build:
      context: .
      dockerfile: ./api/docker/Dockerfile
    ports:
      - 18080:8080
    env_file: ./api/.env
    working_dir: /go
    volumes:
      - ./api:/go
    command: >
      sh
    tty: true

コンテナ構築

# 構築
$ docker-compose up -d

# 確認
$ docker-compose ps
       Name          Command   State            Ports         
--------------------------------------------------------------
practice-beego-api   sh        Up      0.0.0.0:18080->8080/tcp

Beego導入

Beegoインストール

コンテナ入って作業開始

$ docker exec practice-beego-api

Beegoのインストール

# インストール
$ go install github.com/beego/bee/v2@latest

# 確認
$ bee version
2022/06/15 00:05:14.990 [D]  init global config instance failed. If you do not use this, just ignore it.  open conf/app.conf: no such file or directory
2022/06/15 00:05:15 INFO     ▶ 0001 Getting bee latest version...
2022/06/15 00:05:15 INFO     ▶ 0002 Your bee are up to date
______
| ___ \
| |_/ /  ___   ___
| ___ \ / _ \ / _ \
| |_/ /|  __/|  __/
\____/  \___| \___| v2.0.4

├── GoVersion : go1.18.3
├── GOOS      : linux
├── GOARCH    : amd64
├── NumCPU    : 6
├── GOPATH    : /go
├── GOROOT    : /usr/local/go
├── Compiler  : gc
└── Date      : Wednesday, 15 Jun 2022

API作成

下記ドキュメントに従ってAPI作成

$ bee api myapi
2022/06/15 00:11:13.922 [D]  init global config instance failed. If you do not use this, just ignore it.  open conf/app.conf: no such file or directory
______
| ___ \
| |_/ /  ___   ___
| ___ \ / _ \ / _ \
| |_/ /|  __/|  __/
\____/  \___| \___| v2.0.4
2022/06/15 00:11:13 INFO     ▶ 0001 Generate api project support go modules.
2022/06/15 00:11:13 INFO     ▶ 0002 Creating API...
        create   /go/myapi/go.mod
        create   /go/myapi
        create   /go/myapi/conf
        create   /go/myapi/controllers
        create   /go/myapi/tests
        create   /go/myapi/conf/app.conf
        create   /go/myapi/models
        create   /go/myapi/routers/
        create   /go/myapi/controllers/object.go
        create   /go/myapi/controllers/user.go
        create   /go/myapi/tests/default_test.go
        create   /go/myapi/routers/router.go
        create   /go/myapi/models/object.go
        create   /go/myapi/models/user.go
        create   /go/myapi/main.go
2022/06/15 00:11:14 SUCCESS  ▶ 0003 New API successfully created!

起動してみる

# ディレクトリ移動
$ cd myapi/
$ pwd
/go/myapi

# 起動
$ bee run
______
| ___ \
| |_/ /  ___   ___
| ___ \ / _ \ / _ \
| |_/ /|  __/|  __/
\____/  \___| \___| v2.0.4
2022/06/15 00:15:07 WARN     ▶ 0001 Running application outside of GOPATH
2022/06/15 00:15:07 INFO     ▶ 0002 Using 'myapi' as 'appname'
2022/06/15 00:15:07 INFO     ▶ 0003 Initializing watcher...
main.go:6:2: missing go.sum entry for module providing package github.com/beego/beego/v2/server/web (imported by myapi); to add:
        go get myapi
2022/06/15 00:15:07 ERROR    ▶ 0004 Failed to build the application: main.go:6:2: missing go.sum entry for module providing package github.com/beego/beego/v2/server/web (imported by myapi); to add:
        go get myapi

go.sum が存在しないと怒られた
エラー文見るとgo get myapiコマンドを実行すると必要がありそうなので、プロセス中断してコマンド実行

# 指定コマンド実行
$ go get myapi

# go.sumが生成されていること確認
$ ls
conf         go.mod       main.go      routers
controllers  go.sum       models       tests

再度起動

$ bee run
______
| ___ \
| |_/ /  ___   ___
| ___ \ / _ \ / _ \
| |_/ /|  __/|  __/
\____/  \___| \___| v2.0.4
2022/06/15 00:18:29 WARN     ▶ 0001 Running application outside of GOPATH
2022/06/15 00:18:29 INFO     ▶ 0002 Using 'myapi' as 'appname'
2022/06/15 00:18:29 INFO     ▶ 0003 Initializing watcher...
# (実行結果中略)
2022/06/15 00:18:56 SUCCESS  ▶ 0004 Built Successfully!
2022/06/15 00:18:56 INFO     ▶ 0005 Restarting 'myapi'...
2022/06/15 00:18:56 SUCCESS  ▶ 0006 './myapi' is running...
2022/06/15 00:19:00.944 [I] [parser.go:413]  generate router from comments

2022/06/15 00:19:00.953 [I] [server.go:241]  http server Running on http://:8080

良さそうなので、ブラウザで確認
ホスト側の18080ポート開放しているのでそこで確認

スクリーンショット 2022-06-15 0.21.32.png

良さそう
一応ログも確認

2022/06/15 00:21:11.733 [D] [router.go:955]  |     172.25.0.1| 404 |      419.1µs| nomatch| GET      /

404となっているので画面の表記と一致している
OK

少しコード覗いてみる

404画面は悲しいので200系統返ってこないか少し調査
まずはrouter見てみる

routers/router.go
package routers

import (
	"myapi/controllers"

	beego "github.com/beego/beego/v2/server/web"
)

func init() {
	ns := beego.NewNamespace("/v1",
		beego.NSNamespace("/object",
			beego.NSInclude(
				&controllers.ObjectController{},
			),
		),
		beego.NSNamespace("/user",
			beego.NSInclude(
				&controllers.UserController{},
			),
		),
	)
	beego.AddNamespace(ns)
}

おそらく /v1/object/v1/user のエンドポイントが用意されてそう
今回は /v1/user を深堀ってみる

routerからcontroller呼んでいるのでcontroller見てみる

controllers/user.go
package controllers

import (
	"myapi/models"
	"encoding/json"

	beego "github.com/beego/beego/v2/server/web"
)

// Operations about Users
type UserController struct {
	beego.Controller
}

// (略)

// @Title GetAll
// @Description get all Users
// @Success 200 {object} models.User
// @router / [get]
func (u *UserController) GetAll() {
	users := models.GetAllUsers()
	u.Data["json"] = users
	u.ServeJSON()
}

// (略)

@router / [get] とあるので、 /v1/user にGETリクエスト投げれば models.User が返されそう
modelも見てみる

models/user.go
package models

import (
	"errors"
	"strconv"
	"time"
)

var (
	UserList map[string]*User
)

func init() {
	UserList = make(map[string]*User)
	u := User{"user_11111", "astaxie", "11111", Profile{"male", 20, "Singapore", "astaxie@gmail.com"}}
	UserList["user_11111"] = &u
}

type User struct {
	Id       string
	Username string
	Password string
	Profile  Profile
}

type Profile struct {
	Gender  string
	Age     int
	Address string
	Email   string
}

// (略)

func GetAllUsers() map[string]*User {
	return UserList
}

// (略)

GetAllUsers() メソッド呼ぶと UserList が返されそう
init() 部分で UserList に初期値突っ込まれているので、その辺のデータが返されそう

ということで、 /v1/user にGETリクエスト送ってみる

GETリクエスト試したいのでシンプルに http://localhost:18080/v1/user にアクセスしてみる
下記内容が返されるので想定通り

スクリーンショット 2022-06-17 16.21.11.png

ログ↓

2022/06/17 16:18:58.652 [D] [router.go:955]  |   192.168.32.1| 200 |      231.6µs|   match| GET      /v1/user   r:/v1/user/

gitignore設定

起動するたびに?コードに変更が入るたびに?内容変わってgit管理下に含めなくて良さそうなファイルをgitignoreに追加しておく
api/myapi/lastupdate.tmpapi/myapi/myapiを不要と判断したが、公式ドキュメント確認できていないため自己責任で :bow:

.gitignore
.env
api/pkg

# beego
api/bin/myapi
api/myapi/lastupdate.tmp
api/myapi/myapi

Swagger導入

Swaggerも使えるようなので下記ドキュメントを参考に使える状態に持っていく

何も下準備してないのでたぶん見れないが、/swaggerでSwaggerドキュメント確認できるっぽいのでとりあえずアクセス

スクリーンショット 2022-06-15 0.29.43.png

しっかり404

2022/06/15 00:29:38.858 [D] [router.go:955]  |     172.25.0.1| 404 |     1.6767ms| nomatch| GET      /swagger/

ドキュメントを参考にコマンド実行してみる
bee runコマンドのオプションで-downdoc=true-gendoc=trueをつければ良さそう

$ bee run -downdoc=true -gendoc=true
______
| ___ \
| |_/ /  ___   ___
| ___ \ / _ \ / _ \
| |_/ /|  __/|  __/
\____/  \___| \___| v2.0.4
2022/06/15 00:33:49 WARN     ▶ 0001 Running application outside of GOPATH
2022/06/15 00:33:49 INFO     ▶ 0002 Using 'myapi' as 'appname'
2022/06/15 00:33:49 INFO     ▶ 0003 Downloading 'https://codeload.github.com/beego/swagger/zip/refs/tags/v4.6.1' to 'swagger.zip'...
2022/06/15 00:33:51 SUCCESS  ▶ 0004 3065067 bytes downloaded!
2022/06/15 00:33:51 INFO     ▶ 0005 Unzipping 'swagger.zip'...
2022/06/15 00:33:52 SUCCESS  ▶ 0006 Done! Deleting 'swagger.zip'...
2022/06/15 00:33:52 INFO     ▶ 0007 Initializing watcher...
2022/06/15 00:33:58 INFO     ▶ 0008 Generating the docs...
2022/06/15 00:34:03 SUCCESS  ▶ 0009 Docs generated!
2022/06/15 00:34:10 SUCCESS  ▶ 0010 Built Successfully!
2022/06/15 00:34:10 INFO     ▶ 0011 Restarting 'myapi'...
2022/06/15 00:34:10 SUCCESS  ▶ 0012 './myapi' is running...
2022/06/15 00:34:10.401 [I] [parser.go:85]  /go/myapi/controllers no changed

2022/06/15 00:34:10.401 [I] [server.go:241]  http server Running on http://:8080

確認してみる

スクリーンショット 2022-06-15 0.39.24.png

2022/06/15 00:39:13.542 [D] [router.go:955]  |     172.25.0.1| 200 |     5.6745ms|   match| GET      /swagger/

2022/06/15 00:39:13.562 [D] [router.go:955]  |     172.25.0.1| 200 |     9.7623ms|   match| GET      /swagger/swagger-ui.css

2022/06/15 00:39:13.574 [D] [router.go:955]  |     172.25.0.1| 200 |    15.9754ms|   match| GET      /swagger/swagger-ui-standalone-preset.js

2022/06/15 00:39:13.582 [D] [router.go:955]  |     172.25.0.1| 200 |    25.6023ms|   match| GET      /swagger/swagger-ui-bundle.js

2022/06/15 00:39:13.795 [D] [router.go:955]  |     172.25.0.1| 200 |     2.8292ms|   match| GET      /swagger/favicon-32x32.png

良さそう!

テスト確認

tests/default_test.goファイルが存在していたのでテスト実行してみる

go test -v ./...
# myapi/tests
tests/default_test.go:13:2: missing go.sum entry for module providing package github.com/smartystreets/goconvey/convey (imported by myapi/tests); to add:
        go get -t myapi/tests
FAIL    myapi/tests [setup failed]
?       myapi   [no test files]
?       myapi/controllers       [no test files]
?       myapi/models    [no test files]
?       myapi/routers   [no test files]
FAIL

失敗
どうやらgo get -t myapi/testsコマンドを実行する必要がありそうなので実行

$ go get -t myapi/tests

再度テスト実行

go test -v ./...
?       myapi   [no test files]
?       myapi/controllers       [no test files]
?       myapi/models    [no test files]
?       myapi/routers   [no test files]
2022/06/15 00:56:20.122 [W]  init global config instance failed. If you donot use this, just ignore it.  open conf/app.conf: no such file or directory

=== RUN   TestGet
2022/06/15 00:56:20.131 [I] [default_test.go:28]  testing TestGet Code[%d]
%s 200 {
  "hjkhsbnmn123": {
    "ObjectId": "hjkhsbnmn123",
    "Score": 100,
    "PlayerName": "astaxie"
  },
  "mjjkxsxsaa23": {
    "ObjectId": "mjjkxsxsaa23",
    "Score": 101,
    "PlayerName": "someone"
  }
}


  Subject: Test Station Endpoint
 
    Status Code Should Be 200 ✔
    The Result Should Not Be Empty ✔


2 total assertions

--- PASS: TestGet (0.00s)
PASS
ok      myapi/tests     0.018s

OK

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2