github.com/goldeneggg/goa@v1.3.1/README.md (about) 1 # <img src="http://goa.design/img/goa-logo.svg"> 2 3 goa is a framework for building micro-services and REST APIs in Go using a 4 unique design-first approach. 5 6 [![Build Status](https://travis-ci.org/goadesign/goa.svg?branch=master)](https://travis-ci.org/goadesign/goa) 7 [![Windows Build status](https://ci.appveyor.com/api/projects/status/vixp37loj5i6qmaf/branch/master?svg=true)](https://ci.appveyor.com/project/RaphaelSimon/goa-oqtis/branch/master) 8 [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/goadesign/goa/blob/master/LICENSE) 9 [![Godoc](https://godoc.org/github.com/goadesign/goa?status.svg)](http://godoc.org/github.com/goadesign/goa) 10 [![Slack](https://img.shields.io/badge/slack-gophers-orange.svg?style=flat)](https://gophers.slack.com/messages/goa/) 11 12 ## Why goa? 13 14 goa takes a different approach to building micro-services. Instead of focusing 15 solely on helping with implementation, goa makes it possible to describe the 16 *design* of an API using a simple DSL. goa then uses that description to provide 17 specialized helper code to the implementation and to generate documentation, API 18 clients, tests, even custom artifacts. 19 20 If DSLs are not your thing then consider this: you need to document your APIs so 21 that clients (be it internal e.g. other services or external e.g. UIs) may 22 consume them. Typically this requires maintaining a completely separate document 23 (for example an OpenAPI specification). Making sure that the document stays 24 up-to-date takes a lot of effort and at the end of the day you have to write 25 that document - why not use a simple and clear Go DSL to do that instead? 26 27 Another aspect to consider is the need for properly designing APIs and making 28 sure that the design choices remain consistent across the endpoints or even 29 across multiple APIs. If the source code is the only place where design 30 decisions are kept then not only is it impossible to maintain consistency it's 31 also difficult to think about the design in the first place. The goa DSL makes 32 it possible to think about the design explicitly and - since it's code - to 33 re-use design elements for consistency. 34 35 The goa DSL allows writing self-explanatory code that describes the resources 36 exposed by the API and for each resource the properties and actions. goa comes 37 with the `goagen` tool which runs the DSL and generates various types of 38 artifacts from the resulting data structures. 39 40 One of the `goagen` output is glue code that binds your code with the underlying 41 HTTP server. This code is specific to your API so that for example there is no 42 need to cast or "bind" any handler argument prior to using them. Each generated 43 handler has a signature that is specific to the corresponding resource action. 44 It's not just the parameters though, each handler also has access to specific 45 helper methods that generate the possible responses for that action. The DSL can 46 also define validations in which case the generated code takes care of 47 validating the incoming request parameters and payload prior to invoking the 48 handler. 49 50 The end result is controller code that is terse and clean, the boilerplate is 51 all gone. Another big benefit is the clean separation of concern between design 52 and implementation: on bigger projects it's often the case that API design 53 changes require careful review, being able to generate a new version of the 54 documentation without having to write a single line of implementation is a big 55 boon. 56 57 This idea of separating design and implementation is not new, the 58 excellent [Praxis](http://praxis-framework.io) framework from RightScale follows 59 the same pattern and was an inspiration to goa. 60 61 ## Installation 62 63 Assuming you have a working [Go](https://golang.org) setup: 64 ``` 65 go get github.com/goadesign/goa/... 66 ``` 67 68 ### Stable Versions 69 70 goa follows [Semantic Versioning](http://semver.org/) which is a fancy way of saying it publishes 71 releases with version numbers of the form `vX.Y.Z` and makes sure that your code can upgrade to new 72 versions with the same `X` component without having to make changes. 73 74 Releases are tagged with the corresponding version number. There is also a branch for each major 75 version (only `v1` at the moment). The recommended practice is to vendor the stable branch. 76 77 Current Release: `v1.3.1` 78 Stable Branch: `v1` 79 80 ## Teaser 81 82 ### 1. Design 83 84 Create the file `$GOPATH/src/goa-adder/design/design.go` with the following content: 85 ```go 86 package design 87 88 import ( 89 . "github.com/goadesign/goa/design" 90 . "github.com/goadesign/goa/design/apidsl" 91 ) 92 93 var _ = API("adder", func() { 94 Title("The adder API") 95 Description("A teaser for goa") 96 Host("localhost:8080") 97 Scheme("http") 98 }) 99 100 var _ = Resource("operands", func() { 101 Action("add", func() { 102 Routing(GET("add/:left/:right")) 103 Description("add returns the sum of the left and right parameters in the response body") 104 Params(func() { 105 Param("left", Integer, "Left operand") 106 Param("right", Integer, "Right operand") 107 }) 108 Response(OK, "text/plain") 109 }) 110 111 }) 112 ``` 113 This file contains the design for an `adder` API which accepts HTTP GET requests to `/add/:x/:y` 114 where `:x` and `:y` are placeholders for integer values. The API returns the sum of `x` and `y` in 115 its body. 116 117 ### 2. Implement 118 119 Now that the design is done, let's run `goagen` on the design package: 120 ``` 121 cd $GOPATH/src/goa-adder 122 goagen bootstrap -d goa-adder/design 123 ``` 124 This produces the following outputs: 125 126 * `main.go` and `operands.go` contain scaffolding code to help bootstrap the implementation. 127 running `goagen` again does not recreate them so that it's safe to edit their content. 128 * an `app` package which contains glue code that binds the low level HTTP server to your 129 implementation. 130 * a `client` package with a `Client` struct that implements a `AddOperands` function which calls 131 the API with the given arguments and returns the `http.Response`. 132 * a `tool` directory that contains the complete source for a client CLI tool. 133 * a `swagger` package with implements the `GET /swagger.json` API endpoint. The response contains 134 the full Swagger specificiation of the API. 135 136 ### 3. Run 137 138 First let's implement the API - edit the file `operands.go` and replace the content of the `Add` 139 function with: 140 ``` 141 // Add import for strconv 142 import "strconv" 143 144 // Add runs the add action. 145 func (c *OperandsController) Add(ctx *app.AddOperandsContext) error { 146 sum := ctx.Left + ctx.Right 147 return ctx.OK([]byte(strconv.Itoa(sum))) 148 } 149 ``` 150 Now let's compile and run the service: 151 ``` 152 cd $GOPATH/src/goa-adder 153 go build 154 ./goa-adder 155 2016/04/05 20:39:10 [INFO] mount ctrl=Operands action=Add route=GET /add/:left/:right 156 2016/04/05 20:39:10 [INFO] listen transport=http addr=:8080 157 ``` 158 Open a new console and compile the generated CLI tool: 159 ``` 160 cd $GOPATH/src/goa-adder/tool/adder-cli 161 go build 162 ``` 163 The tool includes contextual help: 164 ``` 165 ./adder-cli --help 166 CLI client for the adder service 167 168 Usage: 169 adder-cli [command] 170 171 Available Commands: 172 add add returns the sum of the left and right parameters in the response body 173 174 Flags: 175 --dump Dump HTTP request and response. 176 -H, --host string API hostname (default "localhost:8080") 177 -s, --scheme string Set the requests scheme 178 -t, --timeout duration Set the request timeout (default 20s) 179 180 Use "adder-cli [command] --help" for more information about a command. 181 ``` 182 To get information on how to call a specific API use: 183 ``` 184 ./adder-cli add operands --help 185 Usage: 186 adder-cli add operands [/add/LEFT/RIGHT] [flags] 187 188 Flags: 189 --left int Left operand 190 --pp Pretty print response body 191 --right int Right operand 192 193 Global Flags: 194 --dump Dump HTTP request and response. 195 -H, --host string API hostname (default "localhost:8080") 196 -s, --scheme string Set the requests scheme 197 -t, --timeout duration Set the request timeout (default 20s) 198 ``` 199 Now let's run it: 200 ``` 201 ./adder-cli add operands /add/1/2 202 2016/04/05 20:43:18 [INFO] started id=HffVaGiH GET=http://localhost:8080/add/1/2 203 2016/04/05 20:43:18 [INFO] completed id=HffVaGiH status=200 time=1.028827ms 204 3⏎ 205 ``` 206 This also works: 207 ``` 208 $ ./adder-cli add operands --left=1 --right=2 209 2016/04/25 00:08:59 [INFO] started id=ouKmwdWp GET=http://localhost:8080/add/1/2 210 2016/04/25 00:08:59 [INFO] completed id=ouKmwdWp status=200 time=1.097749ms 211 3⏎ 212 ``` 213 The console running the service shows the request that was just handled: 214 ``` 215 2016/06/06 10:23:03 [INFO] started req_id=rLAtsSThLD-1 GET=/add/1/2 from=::1 ctrl=OperandsController action=Add 216 2016/06/06 10:23:03 [INFO] params req_id=rLAtsSThLD-1 right=2 left=1 217 2016/06/06 10:23:03 [INFO] completed req_id=rLAtsSThLD-1 status=200 bytes=1 time=66.25µs 218 ``` 219 Now let's see how robust our service is and try to use non integer values: 220 ``` 221 ./adder-cli add operands add/1/d 222 2016/06/06 10:24:22 [INFO] started id=Q2u/lPUc GET=http://localhost:8080/add/1/d 223 2016/06/06 10:24:22 [INFO] completed id=Q2u/lPUc status=400 time=1.301083ms 224 error: 400: {"code":"invalid_request","status":400,"detail":"invalid value \"d\" for parameter \"right\", must be a integer"} 225 ``` 226 As you can see the generated code validated the incoming request against the types defined in the 227 design. 228 229 ### 4. Document 230 231 The `swagger` directory contains the API Swagger (OpenAPI) specification in both 232 YAML and JSON format. 233 234 For open source projects hosted on 235 github [swagger.goa.design](http://swagger.goa.design) provides a free service 236 that renders the Swagger representation dynamically from goa design packages. 237 Simply set the `url` query string with the import path to the design package. 238 For example displaying the docs for `github.com/goadesign/goa-cellar/design` is 239 done by browsing to: 240 241 http://swagger.goa.design/?url=goadesign%2Fgoa-cellar%2Fdesign 242 243 Note that the above generates the swagger spec dynamically and does not require it to be present in 244 the Github repo. 245 246 The Swagger JSON can also easily be served from the documented service itself using a simple 247 [Files](http://goa.design/reference/goa/design/apidsl/#func-files-a-name-apidsl-files-a) 248 definition in the design. Edit the file `design/design.go` and add: 249 250 ```go 251 var _ = Resource("swagger", func() { 252 Origin("*", func() { 253 Methods("GET") // Allow all origins to retrieve the Swagger JSON (CORS) 254 }) 255 Files("/swagger.json", "swagger/swagger.json") 256 }) 257 ``` 258 259 Re-run `goagen bootstrap -d goa-adder/design` and note the new file 260 `swagger.go` containing the implementation for a controller that serves the 261 `swagger.json` file. 262 263 Mount the newly generated controller by adding the following two lines to the `main` function in 264 `main.go`: 265 266 ```go 267 cs := NewSwaggerController(service) 268 app.MountSwaggerController(service, cs) 269 ``` 270 271 Recompile and restart the service: 272 273 ``` 274 ^C 275 go build 276 ./goa-adder 277 2016/06/06 10:31:14 [INFO] mount ctrl=Operands action=Add route=GET /add/:left/:right 278 2016/06/06 10:31:14 [INFO] mount ctrl=Swagger files=swagger/swagger.json route=GET /swagger.json 279 2016/06/06 10:31:14 [INFO] listen transport=http addr=:8080 280 ``` 281 282 Note the new route `/swagger.json`. Requests made to it return the Swagger specification. The 283 generated controller also takes care of adding the proper CORS headers so that the JSON may be 284 retrieved from browsers using JavaScript served from a different origin (e.g. via Swagger UI). The 285 client also has a new `download` action: 286 287 ``` 288 cd tool/adder-cli 289 go build 290 ./adder-cli download --help 291 Download file with given path 292 293 Usage: 294 adder-cli download [PATH] [flags] 295 296 Flags: 297 --out string Output file 298 299 Global Flags: 300 --dump Dump HTTP request and response. 301 -H, --host string API hostname (default "localhost:8080") 302 -s, --scheme string Set the requests scheme 303 -t, --timeout duration Set the request timeout (default 20s) 304 ``` 305 306 Which can be used like this to download the file `swagger.json` in the current directory: 307 308 ``` 309 ./adder-cli download swagger.json 310 2016/06/06 10:36:24 [INFO] started file=swagger.json id=ciHL2VLt GET=http://localhost:8080/swagger.json 311 2016/06/06 10:36:24 [INFO] completed file=swagger.json id=ciHL2VLt status=200 time=1.013307ms 312 ``` 313 314 We now have a self-documenting API and best of all the documentation is automatically updated as the 315 API design changes. 316 317 ## Resources 318 319 Consult the following resources to learn more about goa. 320 321 ### goa.design 322 323 [goa.design](https://goa.design) contains further information on goa including a getting 324 started guide, detailed DSL documentation as well as information on how to implement a goa service. 325 326 ### Examples 327 328 The [examples](https://github.com/goadesign/examples) repo contains simple examples illustrating 329 basic concepts. 330 331 The [goa-cellar](https://github.com/goadesign/goa-cellar) repo contains the implementation for a 332 goa service which demonstrates many aspects of the design language. It is kept up-to-date and 333 provides a reference for testing functionality. 334 335 ## Contributing 336 337 Did you fix a bug? write docs or additional tests? or implement some new awesome functionality? 338 You're a rock star!! Just make sure that `make` succeeds (or that TravisCI is green) and send a PR 339 over.