Calc Service
This example provides a basic overview of goa v2. It helps in understanding
the fundamental design principles behind goa v2 and generating server and
client code that supports HTTP and gRPC transports.
Design
The calc
service provides a single method add
which takes the integer
operands as the payload and returns the integer sum as the result.
// design/design.go
var _ = Service("calc", func() {
Method("add", func() {
Payload(func() {
Attribute("a", Int, "Left operand", func() {
Meta("rpc:tag", "1")
})
Field(2, "b", Int, "Right operand")
Required("a", "b")
})
Result(Int)
...
})
The design then describes how the add
method must be served via HTTP and gRPC
transports.
// HTTP describes the HTTP tranport mapping.
HTTP(func() {
GET("/add/{a}/{b}")
Response(StatusOK)
})
// GRPC describes the gRPC transport mapping.
GRPC(func() {
Response(CodeOK)
})
The design also describes an endpoint that serves the auto-generated open API
specification using the HTTP file server.
Files("/swagger.json", "../../gen/http/openapi.json")
Generating Code
goa gen
command generates the boilerplate code needed to serve the add
method via HTTP and gRPC transports.
$ goa gen goa.design/examples/basic/design -o $GOPATH/src/goa.design/examples/basic
The above command creates a gen
folder inside the directory $GOPATH/src/goa.design/examples/basic
with the following layout
├── design
│ └── design.go
└── gen
├── calc
│ ├── client.go
│ ├── endpoints.go
│ └── service.go
├── grpc
│ ├── calc
│ │ ├── client
│ │ │ ├── client.go
│ │ │ ├── cli.go
│ │ │ ├── encode_decode.go
│ │ │ └── types.go
│ │ ├── pb
│ │ │ ├── calc.pb.go
│ │ │ └── calc.proto
│ │ └── server
│ │ ├── encode_decode.go
│ │ ├── server.go
│ │ └── types.go
│ └── cli
│ └── calc
│ └── cli.go
└── http
├── calc
│ ├── client
│ │ ├── client.go
│ │ ├── cli.go
│ │ ├── encode_decode.go
│ │ ├── paths.go
│ │ └── types.go
│ └── server
│ ├── encode_decode.go
│ ├── paths.go
│ ├── server.go
│ └── types.go
├── cli
│ └── calc
│ └── cli.go
├── openapi.json
└── openapi.yaml
gen/calc
contains the transport-independent logic that exposes the business
logic to the HTTP and gRPC transports via goa endpoints.
gen/http
and gen/grpc
contain the HTTP and gRPC transport server and
client code respectively.
Users MUST NOT edit the code generated by goa gen
command.
goa example
command creates an example service implementation along with the
example server code to spin up both HTTP and gRPC servers and their client
counterparts. Users can edit the code generated by goa example
.
$ goa example goa.design/examples/basic/design -o $GOPATH/src/goa.design/examples/basic
├── calc.go
├── cmd
│ ├── calc
│ │ ├── grpc.go
│ │ ├── http.go
│ │ └── main.go
│ └── calc-cli
│ ├── grpc.go
│ ├── http.go
│ └── main.go
├── design
└── gen
calc.go
contains the service implementation where users add the business
logic.
func (s *calcSvc) Add(ctx context.Context, p *calcsvc.AddPayload) (int, error) {
return p.A + p.B, nil
}
- The directories in the
cmd
correspond to the optional Server
DSL
described in the design. A directory is created for each Server
DSL.
Building and Running the Generated Server and Client
The generated example server and client can be built and run as follows
$ go build ./cmd/calc && go build ./cmd/calc-cli
# Run the server
$ ./calc
[calc] 12:27:57 HTTP "Add" mounted on GET /add/{a}/{b}
[calc] 12:27:57 HTTP "../../gen/http/openapi.json" mounted on GET /swagger.json
[calc] 12:27:57 serving gRPC method calc.Calc/Add
[calc] 12:27:57 HTTP server listening on "localhost:8000"
[calc] 12:27:57 gRPC server listening on "localhost:8080"
# Run the client
# Contact HTTP server
$ ./calc-cli --url="http://localhost:8000" calc add --a 1 --b 2
3
# Contact gRPC server
$ ./calc-cli --url="grpc://localhost:8080" calc add --message '{"a": 1, "b": 2}'
3
-h/--help
provides more information on using the server and client
executables.
Viewing Open API Docs
goa v2 generates Open API v2.0 specifications for every service that defines
HTTP transport. Users can view the generated docs using their choice of swagger
documentation viewer.