Table of Contents
Goaとは
デザインファーストなmicroserviceフレームワークです。
どういった点がデザインファーストかと言うと、最初にDSLでAPIサーバの仕様や扱うリソース、対応する機能を定義し、これを元にソースコードの大半が自動生成される点です。自動生成されたソースコード中に、リクエストを受け付けた時の処理を記述するだけでAPIサーバが出来上がるので、処理ロジックに集中して開発することができます。
JWT認証等のセキュリティ機能を追加したり、O/Rマッパーを使用することもできます。Go言語なのでコンパイル時の型チェックがあったり、golangのエコシステム(数多くのツールやライブラリ)を活用出来る点も嬉しいところです。
以下コマンドを実行することでGoaをインストールできます。
$ go get -u github.com/goadesign/goa/...
APIサーバを作ってみる
まずは、Workspace(今回は app
というディレクトリ)を作成し、 my_app/design/design.go
を作成・編集します。このファイルが、後に元にソースコードを自動生成する際のいわば設計図となります。
今回はシンプルに User
を取得するAPIサーバを作ることにしました。
package design
import (
. "github.com/goadesign/goa/design"
. "github.com/goadesign/goa/design/apidsl"
)
var \_ = API("MyApp", func() {
Title("My App")
Description("This is api server for my application.")
Scheme("http")
Host("localhost:8080")
BasePath("/api/v1")
})
var \_ = Resource("user", func() {
BasePath("/users")
DefaultMedia(UserMedia)
Action("list", func() {
Description("Get all users")
Routing(GET("/"))
Response(OK, func() {
Media(CollectionOf(UserMedia, func() {
View("default")
}))
})
Response(NotFound)
})
Action("show", func() {
Description("Get user by id")
Routing(GET("/:userID"))
Params(func() {
Param("userID", Integer, "User ID")
})
Response(OK)
Response(NotFound)
})
})
// UserMedia defines the media type used to render bottles.
var UserMedia = MediaType("application/vnd.goa.example.user+json", func() {
Description("A user of my application")
Attributes(func() {
Attribute("id", Integer, "Unique user ID")
Attribute("email", String, "User's email")
Attribute("last\_name", String, "User's last name")
Attribute("first\_name", String, "User's first name")
Required("id", "email", "last\_name", "first\_name")
})
View("default", func() {
Attribute("id")
Attribute("email")
Attribute("last\_name")
Attribute("first\_name")
})
})
コマンドを実行して、ソースコードを自動生成します。
$ goagen bootstrap -d github.com/yuuu/my\_app/design
自動生成された user.go
にリクエスト時の処理を記述します。
package main
import (
"github.com/goadesign/goa"
"github.com/yuuu/my\_app/app"
)
// UserController implements the user resource.
type UserController struct {
\*goa.Controller
}
// NewUserController creates a user controller.
func NewUserController(service \*goa.Service) \*UserController {
return &UserController{Controller: service.NewController("UserController")}
}
var users = []\*app.GoaExampleUser{
&app.GoaExampleUser{ID: 1, Email: "user1@example.com", LastName: "Fusic", FirstName: "Taro"},
&app.GoaExampleUser{ID: 2, Email: "user2@example.com", LastName: "Fusic", FirstName: "Jiro"},
}
// List runs the list action.
func (c \*UserController) List(ctx \*app.ListUserContext) error {
// UserController\_List: start\_implement
// Put your logic here
// 実際にはデータベース等から読み出す
res := users
//res := app.GoaExampleUserCollection{}
return ctx.OK(res)
// UserController\_List: end\_implement
}
// Show runs the show action.
func (c \*UserController) Show(ctx \*app.ShowUserContext) error {
// UserController\_Show: start\_implement
// Put your logic here
// 実際にはデータベース等から読み出す
res := users[ctx.UserID]
//res := &app.GoaExampleUser{}
return ctx.OK(res)
// UserController\_Show: end\_implement
}
APIサーバへリクエストしてみる
go run
してAPIサーバを起動します。
$ go run \*.go
curl
でリクエストすると、レスポンスに User
の情報がセットされていることがわかります。
$ curl localhost:8080/api/v1/users/
[{"email":"user1@example.com","first\_name":"Taro","id":1,"last\_name":"Fusic"},{"email":"user2@example.com","first\_name":"Jiro","id":2,"last\_name":"Fusic"}]
$ curl localhost:8080/api/v1/users/0
{"email":"user1@example.com","first\_name":"Taro","id":1,"last\_name":"Fusic"}
$ curl localhost:8080/api/v1/users/1
{"email":"user2@example.com","first\_name":"Jiro","id":2,"last\_name":"Fusic"}
今後の展望
今回はデータベース等を使用せずにAPIサーバの動作確認をしていますが、実際にはデータベースに対してCRUD操作する場合がほとんどなのでO/Rマッパーを使うよう設定する必要があります。また、認証機能(JWT等)を使えるようにする必要があります。
Vue.jsと組み合わせて使うことを想定すると、クロスオリジン要求に対応するよう設定することも必要です。
このあたりは、次回解説したいと思います。