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.