#goadesigntokyo
2016/09/06
@tchssk (Taichi Sasaki)
Engineer at Ebisol, Inc.
An existing service is using Goji.
The World’s Most Popular Framework for APIs.
I decided to use goa.
Let me repeat it.
.
├── app
├── client
├── controllers # 3. Implement controllers
├── db
├── design # 1. Write design
├── models
├── swagger
└── tool
I put controllers into controllers
directory.
design
Directory├── design
│ ├── api_definition.go # apidsl.API()
│ ├── media_types.go # apidsl.MediaType()
│ ├── models.go # dsl.StorageGroup()
│ ├── resources.go # apidsl.Resource()
│ ├── security.go # apidsl.JWTSecurity()
│ └── user_types.go # apidsl.Type()
design
is separated by each top level DSL.
Storage generation plugin for Goa.
https://github.com/goadesign/gorma
var sg = StorageGroup("MyStorageGroup", func() {
Store("mysql", gorma.MySQL, func() {
Model("Location", func() {
RendersTo(Location) // This will generate a helper.
Field("name", gorma.String)
Field("latitude", gorma.Decimal)
Field("longitude", gorma.Decimal)
})
})
})
$ goagen gen \
--design=github.com/tchssk/go-study/design \
--pkg-path=github.com/goadesign/gorma
goagen generates following code for Gorm
// Location Relational Model
type Location struct {
ID int `gorm:"primary_key"` // This is added by default.
CreatedAt time.Time // This is added by default.
DeletedAt *time.Time // This is added by default.
Latitude float32
Longitude float32
Name string
UpdatedAt time.Time // This is added by default.
}
and some helpers.
func (c *LocationController) Show(
ctx *app.ShowLocationContext
) error {
ldb := models.NewLocationDB(db) // db is the instance of Gorm.
location, err := ldb.OneLocation(ctx) // Helper.
if err != nil {
return ctx.NotFound()
}
return ctx.OK(location.LocationToLocation) // Helper.
}
These are useful helper methods generated by Gorma.
models.NewLocationDB()
// It creates a new storage type.
ldb.OneLocation()
// It gets one location from database.
location.LocationToLocation()
// It converts location to response media type.
// This is generated from RendersTo().
The open-source application container engine.
https://github.com/docker/docker
Maybe you are more familiar than me.
Creating a contaier of MySQL for
Dockertest library provides easy to use commands for spinning up Docker containers and using them for your tests.
https://github.com/ory-am/dockertest
In TestMain()
,
func TestMain(m *testing.M) {
c, err := dockertest.ConnectToMySQL(15, time.Second,
func(url string) bool {
SetDB(database.GetWithURL(url)) // Open DB connection.
return true
},
)
if err != nil {
log.Fatalf("Could not connect to database: %s", err)
} // 1. Start a continer.
CreateFixtures() // 2. Create fixtures.
result := m.Run() // 3. Execute tests.
db.Close() // 4. Close DB connection.
c.KillRemove() // 4. Clean up the container.
os.Exit(result)
}
$ export DOCKERTEST_MYSQL_IMAGE_NAME=mysql:5.6
$ go test ./...
Dockertest provides some envioronment variables.
https://github.com/ory-am/dockertest#i-need-to-use-a-specific-container-version-for-xyz
Project is built and tested on CircleCI.
Below is circle.yml
.
machine:
environment:
DOCKERTEST_BIND_LOCALHOST: true
DOCKERTEST_MYSQL_IMAGE_NAME: mysql:5.6
services:
- docker
Swagger UI is a dependency-free collection of HTML, Javascript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.
https://github.com/swagger-api/swagger-ui
dist
directory of Swagger UI into swagger
directory of my repository.index.html
to use ./swagger.json
by default.Update design to serve the files.
var _ = apidsl.Resource("swagger", func() {
apidsl.Origin("*", func() {
apidsl.Methods("GET")
})
apidsl.Files("/swagger.json", "swagger/swagger.json")
apidsl.Files("/*filepath", "swagger")
})
OpenAPI/Swagger-generated API Reference Documentation.
https://github.com/Rebilly/ReDoc
API Console feature · Issue #53 · Rebilly/ReDoc
Coming soon?
I find some typo or bugs
Then I dive into goa and explore that.
Would you like to use goa?
and contribute to that?