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