├── README.txt ├── goa-post-example ├── app ├── user_types.go ├── hrefs.go ├── controllers.go ├── contexts.go └── media_types.go ├── client ├── bottle.go ├── winecellar-cli │ ├── commands.go │ └── main.go └── client.go ├── bottle.go ├── main.go ├── swagger ├── swagger.json └── swagger.go └── design └── design.go /README.txt: -------------------------------------------------------------------------------- 1 | Example for "goa: Untangling Middleware" blog post. 2 | -------------------------------------------------------------------------------- /goa-post-example: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/raphael/goa-post-example/master/goa-post-example -------------------------------------------------------------------------------- /app/user_types.go: -------------------------------------------------------------------------------- 1 | //************************************************************************// 2 | // winecellar: Application User Types 3 | // 4 | // Generated with goagen v0.0.1, command line: 5 | // $ goagen 6 | // --out=$(GOPATH)/src/github.com/raphael/goa-post-example 7 | // --design=github.com/raphael/goa-post-example/design 8 | // --pkg=app 9 | // 10 | // The content of this file is auto-generated, DO NOT MODIFY 11 | //************************************************************************// 12 | 13 | package app 14 | -------------------------------------------------------------------------------- /client/bottle.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "io" 5 | "net/http" 6 | "net/url" 7 | ) 8 | 9 | // Retrieve bottle with given ID 10 | func (c *Client) ShowBottle(path string) (*http.Response, error) { 11 | var body io.Reader 12 | u := url.URL{Host: c.Host, Scheme: c.Scheme, Path: path} 13 | req, err := http.NewRequest("GET", u.String(), body) 14 | if err != nil { 15 | return nil, err 16 | } 17 | header := req.Header 18 | header.Set("Content-Type", "application/json") 19 | return c.Client.Do(req) 20 | } 21 | -------------------------------------------------------------------------------- /bottle.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/raphael/goa" 5 | "github.com/raphael/goa-post-example/app" 6 | ) 7 | 8 | // BottleController implements the Bottle resource. 9 | type BottleController struct { 10 | goa.Controller 11 | } 12 | 13 | // NewBottleController creates a Bottle controller. 14 | func NewBottleController(service goa.Service) app.BottleController { 15 | return &BottleController{Controller: service.NewController("BottleController")} 16 | } 17 | 18 | // Show runs the show action. 19 | func (c *BottleController) Show(ctx *app.ShowBottleContext) error { 20 | res := &app.Bottle{} 21 | return ctx.OK(res) 22 | } 23 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/raphael/goa" 5 | "github.com/raphael/goa-post-example/app" 6 | "github.com/raphael/goa-post-example/swagger" 7 | ) 8 | 9 | func main() { 10 | // Create service 11 | service := goa.New("API") 12 | 13 | // Setup middleware 14 | service.Use(goa.RequestID()) 15 | service.Use(goa.LogRequest()) 16 | service.Use(goa.Recover()) 17 | 18 | // Mount "Bottle" controller 19 | c := NewBottleController(service) 20 | app.MountBottleController(service, c) 21 | 22 | // Mount Swagger spec provider controller 23 | swagger.MountController(service) 24 | 25 | // Start service, listen on port 8080 26 | service.ListenAndServe(":8080") 27 | } 28 | -------------------------------------------------------------------------------- /app/hrefs.go: -------------------------------------------------------------------------------- 1 | //************************************************************************// 2 | // winecellar: Application Resource Href Factories 3 | // 4 | // Generated with goagen v0.0.1, command line: 5 | // $ goagen 6 | // --out=$(GOPATH)/src/github.com/raphael/goa-post-example 7 | // --design=github.com/raphael/goa-post-example/design 8 | // --pkg=app 9 | // 10 | // The content of this file is auto-generated, DO NOT MODIFY 11 | //************************************************************************// 12 | 13 | package app 14 | 15 | import "fmt" 16 | 17 | // BottleHref returns the resource href. 18 | func BottleHref(bottleID interface{}) string { 19 | return fmt.Sprintf("/cellar/bottles/%v", bottleID) 20 | } 21 | -------------------------------------------------------------------------------- /client/winecellar-cli/commands.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/raphael/goa-post-example/client" 7 | "gopkg.in/alecthomas/kingpin.v2" 8 | ) 9 | 10 | type ( 11 | // ShowBottleCommand is the command line data structure for the show action of Bottle 12 | ShowBottleCommand struct { 13 | // Path is the HTTP request path. 14 | Path string 15 | } 16 | ) 17 | 18 | // Run makes the HTTP request corresponding to the ShowBottleCommand command. 19 | func (cmd *ShowBottleCommand) Run(c *client.Client) (*http.Response, error) { 20 | return c.ShowBottle(cmd.Path) 21 | } 22 | 23 | // RegisterFlags registers the command flags with the command line. 24 | func (cmd *ShowBottleCommand) RegisterFlags(cc *kingpin.CmdClause) { 25 | cc.Arg("path", `Request path, format is /cellar/bottles/:bottleID`).Required().StringVar(&cmd.Path) 26 | } 27 | -------------------------------------------------------------------------------- /client/client.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "net/http" 5 | 6 | "github.com/raphael/goa" 7 | "gopkg.in/alecthomas/kingpin.v2" 8 | ) 9 | 10 | type ( 11 | // Client is the winecellar service client. 12 | Client struct { 13 | *goa.Client 14 | } 15 | 16 | // ActionCommand represents a single action command as defined on the command line. 17 | // Each command is associated with a generated client method and contains the logic to 18 | // call the method passing in arguments computed from the command line. 19 | ActionCommand interface { 20 | // Run makes the HTTP request and returns the response. 21 | Run(c *Client) (*http.Response, error) 22 | // RegisterFlags defines the command flags. 23 | RegisterFlags(*kingpin.CmdClause) 24 | } 25 | ) 26 | 27 | // New instantiates the client. 28 | func New() *Client { 29 | return &Client{Client: goa.NewClient()} 30 | } 31 | -------------------------------------------------------------------------------- /swagger/swagger.json: -------------------------------------------------------------------------------- 1 | {"swagger":"2.0","info":{"description":"The winecellar service API","version":""},"host":"cellar.goa.design","basePath":"/cellar","schemes":["http","https"],"consumes":["application/json"],"produces":["application/json"],"paths":{"/bottles/{bottleID}":{"get":{"description":"Retrieve bottle with given ID","operationId":"Bottle#show","consumes":["application/json"],"produces":["application/json"],"parameters":[{"name":"bottleID","in":"path","description":"The name of the bottle to retrieve","required":true,"type":"integer"}],"responses":{"200":{"description":"","schema":{"$ref":"#/definitions/Bottle"}},"404":{"description":""}},"schemes":["https"]}}},"definitions":{"Bottle":{"title":"Mediatype identifier: application/vnd.goa.example.bottle+json","type":"object","properties":{"color":{"type":"string","enum":["red","white","rose","yellow","sparkling"]},"href":{"type":"string"},"id":{"type":"integer","description":"ID of bottle"},"name":{"type":"string","description":"The bottle name","minLength":1,"maxLength":255},"sweetness":{"type":"integer","minimum":1,"maximum":5}},"description":"A bottle of wine"}}} -------------------------------------------------------------------------------- /app/controllers.go: -------------------------------------------------------------------------------- 1 | //************************************************************************// 2 | // winecellar: Application Controllers 3 | // 4 | // Generated with goagen v0.0.1, command line: 5 | // $ goagen 6 | // --out=$(GOPATH)/src/github.com/raphael/goa-post-example 7 | // --design=github.com/raphael/goa-post-example/design 8 | // --pkg=app 9 | // 10 | // The content of this file is auto-generated, DO NOT MODIFY 11 | //************************************************************************// 12 | 13 | package app 14 | 15 | import ( 16 | "github.com/julienschmidt/httprouter" 17 | "github.com/raphael/goa" 18 | ) 19 | 20 | // BottleController is the controller interface for the Bottle actions. 21 | type BottleController interface { 22 | goa.Controller 23 | Show(*ShowBottleContext) error 24 | } 25 | 26 | // MountBottleController "mounts" a Bottle resource controller on the given service. 27 | func MountBottleController(service goa.Service, ctrl BottleController) { 28 | router := service.HTTPHandler().(*httprouter.Router) 29 | var h goa.Handler 30 | h = func(c *goa.Context) error { 31 | ctx, err := NewShowBottleContext(c) 32 | if err != nil { 33 | return goa.NewBadRequestError(err) 34 | } 35 | return ctrl.Show(ctx) 36 | } 37 | router.Handle("GET", "/cellar/bottles/:bottleID", ctrl.NewHTTPRouterHandle("Show", h)) 38 | service.Info("mount", "ctrl", "Bottle", "action", "Show", "route", "GET /cellar/bottles/:bottleID") 39 | } 40 | -------------------------------------------------------------------------------- /app/contexts.go: -------------------------------------------------------------------------------- 1 | //************************************************************************// 2 | // winecellar: Application Contexts 3 | // 4 | // Generated with goagen v0.0.1, command line: 5 | // $ goagen 6 | // --out=$(GOPATH)/src/github.com/raphael/goa-post-example 7 | // --design=github.com/raphael/goa-post-example/design 8 | // --pkg=app 9 | // 10 | // The content of this file is auto-generated, DO NOT MODIFY 11 | //************************************************************************// 12 | 13 | package app 14 | 15 | import ( 16 | "fmt" 17 | "strconv" 18 | 19 | "github.com/raphael/goa" 20 | ) 21 | 22 | // ShowBottleContext provides the Bottle show action context. 23 | type ShowBottleContext struct { 24 | *goa.Context 25 | BottleID int 26 | } 27 | 28 | // NewShowBottleContext parses the incoming request URL and body, performs validations and creates the 29 | // context used by the Bottle controller show action. 30 | func NewShowBottleContext(c *goa.Context) (*ShowBottleContext, error) { 31 | var err error 32 | ctx := ShowBottleContext{Context: c} 33 | rawBottleID, ok := c.Get("bottleID") 34 | if ok { 35 | if bottleID, err2 := strconv.Atoi(rawBottleID); err2 == nil { 36 | ctx.BottleID = int(bottleID) 37 | } else { 38 | err = goa.InvalidParamTypeError("bottleID", rawBottleID, "integer", err) 39 | } 40 | } 41 | return &ctx, err 42 | } 43 | 44 | // NotFound sends a HTTP response with status code 404. 45 | func (ctx *ShowBottleContext) NotFound() error { 46 | return ctx.Respond(404, nil) 47 | } 48 | 49 | // OK sends a HTTP response with status code 200. 50 | func (ctx *ShowBottleContext) OK(resp *Bottle) error { 51 | r, err := resp.Dump() 52 | if err != nil { 53 | return fmt.Errorf("invalid response: %s", err) 54 | } 55 | ctx.Header().Set("Content-Type", "application/vnd.goa.example.bottle+json; charset=utf-8") 56 | return ctx.JSON(200, r) 57 | } 58 | -------------------------------------------------------------------------------- /swagger/swagger.go: -------------------------------------------------------------------------------- 1 | //************************************************************************// 2 | // winecellar Swagger Spec 3 | // 4 | // Generated with goagen v0.0.1, command line: 5 | // $ goagen 6 | // --out=$(GOPATH)/src/github.com/raphael/goa-post-example 7 | // --design=github.com/raphael/goa-post-example/design 8 | // 9 | // The content of this file is auto-generated, DO NOT MODIFY 10 | //************************************************************************// 11 | 12 | package swagger 13 | 14 | import ( 15 | "github.com/julienschmidt/httprouter" 16 | "github.com/raphael/goa" 17 | ) 18 | 19 | // MountController mounts the swagger spec controller under "/swagger.json". 20 | func MountController(service goa.Service) { 21 | ctrl := service.NewController("Swagger") 22 | service.Info("mount", "ctrl", "Swagger", "action", "Show", "route", "GET /swagger.json") 23 | h := ctrl.NewHTTPRouterHandle("Show", getSwagger) 24 | service.HTTPHandler().(*httprouter.Router).Handle("GET", "/swagger.json", h) 25 | } 26 | 27 | // getSwagger is the httprouter handle that returns the Swagger spec. 28 | // func getSwagger(w http.ResponseWriter, r *http.Request, p httprouter.Params) { 29 | func getSwagger(ctx *goa.Context) error { 30 | ctx.Header().Set("Content-Type", "application/swagger+json") 31 | ctx.Header().Set("Cache-Control", "public, max-age=3600") 32 | return ctx.Respond(200, []byte(spec)) 33 | } 34 | 35 | // Generated spec 36 | const spec = `{"swagger":"2.0","info":{"description":"The winecellar service API","version":""},"host":"cellar.goa.design","basePath":"/cellar","schemes":["http","https"],"consumes":["application/json"],"produces":["application/json"],"paths":{"/bottles/{bottleID}":{"get":{"description":"Retrieve bottle with given ID","operationId":"Bottle#show","consumes":["application/json"],"produces":["application/json"],"parameters":[{"name":"bottleID","in":"path","description":"The name of the bottle to retrieve","required":true,"type":"integer"}],"responses":{"200":{"description":"","schema":{"$ref":"#/definitions/Bottle"}},"404":{"description":""}},"schemes":["https"]}}},"definitions":{"Bottle":{"title":"Mediatype identifier: application/vnd.goa.example.bottle+json","type":"object","properties":{"color":{"type":"string","enum":["red","white","rose","yellow","sparkling"]},"href":{"type":"string"},"id":{"type":"integer","description":"ID of bottle"},"name":{"type":"string","description":"The bottle name","minLength":1,"maxLength":255},"sweetness":{"type":"integer","minimum":1,"maximum":5}},"description":"A bottle of wine"}}} ` 37 | -------------------------------------------------------------------------------- /client/winecellar-cli/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | 9 | "github.com/raphael/goa-post-example/client" 10 | "gopkg.in/alecthomas/kingpin.v2" 11 | ) 12 | 13 | // PrettyPrint is true if the tool output should be formatted for human consumption. 14 | var PrettyPrint bool 15 | 16 | func main() { 17 | // Create command line parser 18 | app := kingpin.New("winecellar-cli", "CLI client for the winecellar service") 19 | c := client.New() 20 | c.UserAgent = "winecellar-cli/1.0" 21 | app.Flag("scheme", "Set the requests scheme").Short('s').Default("http").StringVar(&c.Scheme) 22 | app.Flag("host", "API hostname").Short('h').Default("cellar.goa.design").StringVar(&c.Host) 23 | app.Flag("timeout", "Set the request timeout, defaults to 20s").Short('t').Default("20s").DurationVar(&c.Timeout) 24 | app.Flag("dump", "Dump HTTP request and response.").BoolVar(&c.Dump) 25 | app.Flag("pp", "Pretty print response body").BoolVar(&PrettyPrint) 26 | commands := RegisterCommands(app) 27 | // Make "client-cli [] --help" equivalent to 28 | // "client-cli help []" 29 | if os.Args[len(os.Args)-1] == "--help" { 30 | args := append([]string{os.Args[0], "help"}, os.Args[1:len(os.Args)-1]...) 31 | os.Args = args 32 | } 33 | cmdName, err := app.Parse(os.Args[1:]) 34 | if err != nil { 35 | kingpin.Fatalf(err.Error()) 36 | } 37 | cmd, ok := commands[cmdName] 38 | if !ok { 39 | kingpin.Fatalf("unknown command %s", cmdName) 40 | } 41 | resp, err := cmd.Run(c) 42 | if err != nil { 43 | kingpin.Fatalf("request failed: %s", err) 44 | } 45 | defer resp.Body.Close() 46 | body, err := ioutil.ReadAll(resp.Body) 47 | if err != nil { 48 | kingpin.Fatalf("failed to read body: %s", err) 49 | } 50 | if resp.StatusCode < 200 || resp.StatusCode > 299 { 51 | // Let user know if something went wrong 52 | var sbody string 53 | if len(body) > 0 { 54 | sbody = ": " + string(body) 55 | } 56 | fmt.Printf("error: %d%s", resp.StatusCode, sbody) 57 | } else if !c.Dump && len(body) > 0 { 58 | var out string 59 | if PrettyPrint { 60 | var jbody interface{} 61 | err = json.Unmarshal(body, &jbody) 62 | if err != nil { 63 | out = string(body) 64 | } else { 65 | var b []byte 66 | b, err = json.MarshalIndent(jbody, "", " ") 67 | if err == nil { 68 | out = string(b) 69 | } else { 70 | out = string(body) 71 | } 72 | } 73 | } else { 74 | out = string(body) 75 | } 76 | fmt.Print(out) 77 | } 78 | 79 | // Figure out exit code 80 | exitStatus := 0 81 | switch { 82 | case resp.StatusCode == 401: 83 | exitStatus = 1 84 | case resp.StatusCode == 403: 85 | exitStatus = 3 86 | case resp.StatusCode == 404: 87 | exitStatus = 4 88 | case resp.StatusCode > 399 && resp.StatusCode < 500: 89 | exitStatus = 2 90 | case resp.StatusCode > 499: 91 | exitStatus = 5 92 | } 93 | os.Exit(exitStatus) 94 | } 95 | 96 | // RegisterCommands all the resource action subcommands to the application command line. 97 | func RegisterCommands(app *kingpin.Application) map[string]client.ActionCommand { 98 | res := make(map[string]client.ActionCommand) 99 | var command, sub *kingpin.CmdClause 100 | command = app.Command("show", "Retrieve bottle with given ID") 101 | tmp1 := new(ShowBottleCommand) 102 | sub = command.Command("Bottle", "Retrieve bottle with given ID") 103 | tmp1.RegisterFlags(sub) 104 | res["show Bottle"] = tmp1 105 | 106 | return res 107 | } 108 | -------------------------------------------------------------------------------- /design/design.go: -------------------------------------------------------------------------------- 1 | package design 2 | 3 | import ( 4 | . "github.com/raphael/goa/design" // "dot" imports make the DSL easier to read. 5 | . "github.com/raphael/goa/design/dsl" 6 | ) 7 | 8 | var _ = API("winecellar", func() { // The API function defines an API given its name. 9 | Title("goa: Untangling Microservices example") 10 | Description("The winecellar service API") 11 | BasePath("/cellar") // Base path or prefix to all requests. 12 | // Can be overridden in action definitions using an 13 | // absolute path starting with //. 14 | Host("cellar.goa.design") // Default API host used by clients and Swagger. 15 | Scheme("http") // Supported API URL scheme used by clients and Swagger. 16 | Scheme("https") // Scheme("http", "https") works too 17 | }) 18 | 19 | var _ = Resource("Bottle", func() { // Define the Bottle resource 20 | DefaultMedia(BottleMedia) // Default media type used to render the bottle resources 21 | BasePath("/bottles") // Gets appended to the API base path 22 | 23 | Action("show", func() { // Define the show action on the Bottle resource 24 | Routing(GET("/:bottleID")) // The relative path to the show endpoint. The full path is 25 | // built concatenating the API and resource base paths with it. 26 | // Uses a wildcard to capture the requested bottle ID. 27 | // Wildcards can start with : to capture a single path segment 28 | // or with * to capture the rest of the path. 29 | Description("Retrieve bottle with given ID") 30 | Params(func() { // Define the request parameters found in the URI (wildcards) 31 | // and the query string. 32 | Param( // Define a single parameter 33 | "bottleID", // Here it corresponds to the path segment captured by :bottleID 34 | Integer, // The JSON type of the parameter 35 | "The name of the bottle to retrieve", // An optional description 36 | ) 37 | }) 38 | Response(OK) // Define a potential response 39 | Response(NotFound) // An action may define any number of responses. 40 | // Their content is defined through ResponseTemplates (not shown 41 | // in this simplistic example). Here we use the default response 42 | // templates defined in goa. 43 | }) 44 | }) 45 | 46 | var BottleMedia = MediaType("application/vnd.goa.example.bottle+json", func() { 47 | Description("A bottle of wine") 48 | Attributes(func() { 49 | Attribute("id", Integer, "ID of bottle") // Attribute defines a single field in 50 | // the media type data structure given its 51 | // name, type and description. 52 | Attribute("href") // The default type for attributes is String. 53 | Attribute("name", String, "The bottle name", func() { // Like with API, Resource and Action an attribute 54 | // definition may use an anonymous function as 55 | // last argument to define additional properties. 56 | MinLength(1) // Here we define validation rules specifying a 57 | MaxLength(255) // minimum and maximum number of characters in a bottle 58 | // name. 59 | }) 60 | Attribute("color", func() { // Descriptions are optional. 61 | Enum("red", "white", "rose", "yellow", "sparkling") // Possible field values 62 | }) 63 | Attribute("sweetness", Integer, func() { 64 | Minimum(1) // Minimum and maximum int field values. 65 | Maximum(5) 66 | }) 67 | 68 | View("default", func() { // Views are used to render a media type. 69 | Attribute("id") // A media type can have one or more views 70 | Attribute("href") // and must define the "default" view. 71 | Attribute("name") // The view simply lists the fields to render. 72 | Attribute("color") // It can also specify the view to use to render 73 | Attribute("sweetness") // fields whose type is itself a media type 74 | // (the "default" view by default). Not used here. 75 | }) 76 | }) 77 | }) 78 | -------------------------------------------------------------------------------- /app/media_types.go: -------------------------------------------------------------------------------- 1 | //************************************************************************// 2 | // winecellar: Application Media Types 3 | // 4 | // Generated with goagen v0.0.1, command line: 5 | // $ goagen 6 | // --out=$(GOPATH)/src/github.com/raphael/goa-post-example 7 | // --design=github.com/raphael/goa-post-example/design 8 | // --pkg=app 9 | // 10 | // The content of this file is auto-generated, DO NOT MODIFY 11 | //************************************************************************// 12 | 13 | package app 14 | 15 | import "github.com/raphael/goa" 16 | 17 | // A bottle of wine 18 | // Identifier: application/vnd.goa.example.bottle+json 19 | type Bottle struct { 20 | Color string 21 | Href string 22 | // ID of bottle 23 | ID int 24 | // The bottle name 25 | Name string 26 | Sweetness int 27 | } 28 | 29 | // LoadBottle loads raw data into an instance of Bottle running all the 30 | // validations. Raw data is defined by data that the JSON unmarshaler would create when unmarshaling 31 | // into a variable of type interface{}. See https://golang.org/pkg/encoding/json/#Unmarshal for the 32 | // complete list of supported data types. 33 | func LoadBottle(raw interface{}) (*Bottle, error) { 34 | var err error 35 | var res *Bottle 36 | if val, ok := raw.(map[string]interface{}); ok { 37 | res = new(Bottle) 38 | if v, ok := val["color"]; ok { 39 | var tmp1 string 40 | if val, ok := v.(string); ok { 41 | tmp1 = val 42 | } else { 43 | err = goa.InvalidAttributeTypeError(`.Color`, v, "string", err) 44 | } 45 | if err == nil { 46 | if tmp1 != "" { 47 | if !(tmp1 == "red" || tmp1 == "white" || tmp1 == "rose" || tmp1 == "yellow" || tmp1 == "sparkling") { 48 | err = goa.InvalidEnumValueError(`.Color`, tmp1, []interface{}{"red", "white", "rose", "yellow", "sparkling"}, err) 49 | } 50 | } 51 | } 52 | res.Color = tmp1 53 | } 54 | if v, ok := val["href"]; ok { 55 | var tmp2 string 56 | if val, ok := v.(string); ok { 57 | tmp2 = val 58 | } else { 59 | err = goa.InvalidAttributeTypeError(`.Href`, v, "string", err) 60 | } 61 | res.Href = tmp2 62 | } 63 | if v, ok := val["id"]; ok { 64 | var tmp3 int 65 | if f, ok := v.(float64); ok { 66 | tmp3 = int(f) 67 | } else { 68 | err = goa.InvalidAttributeTypeError(`.ID`, v, "int", err) 69 | } 70 | res.ID = tmp3 71 | } 72 | if v, ok := val["name"]; ok { 73 | var tmp4 string 74 | if val, ok := v.(string); ok { 75 | tmp4 = val 76 | } else { 77 | err = goa.InvalidAttributeTypeError(`.Name`, v, "string", err) 78 | } 79 | if err == nil { 80 | if len(tmp4) < 1 { 81 | err = goa.InvalidLengthError(`.Name`, tmp4, 1, true, err) 82 | } 83 | if len(tmp4) > 255 { 84 | err = goa.InvalidLengthError(`.Name`, tmp4, 255, false, err) 85 | } 86 | } 87 | res.Name = tmp4 88 | } 89 | if v, ok := val["sweetness"]; ok { 90 | var tmp5 int 91 | if f, ok := v.(float64); ok { 92 | tmp5 = int(f) 93 | } else { 94 | err = goa.InvalidAttributeTypeError(`.Sweetness`, v, "int", err) 95 | } 96 | if err == nil { 97 | if tmp5 < 1 { 98 | err = goa.InvalidRangeError(`.Sweetness`, tmp5, 1, true, err) 99 | } 100 | if tmp5 > 5 { 101 | err = goa.InvalidRangeError(`.Sweetness`, tmp5, 5, false, err) 102 | } 103 | } 104 | res.Sweetness = tmp5 105 | } 106 | } else { 107 | err = goa.InvalidAttributeTypeError(``, raw, "dictionary", err) 108 | } 109 | return res, err 110 | } 111 | 112 | // Dump produces raw data from an instance of Bottle running all the 113 | // validations. See LoadBottle for the definition of raw data. 114 | func (mt *Bottle) Dump() (map[string]interface{}, error) { 115 | var err error 116 | var res map[string]interface{} 117 | if mt.Color != "" { 118 | if !(mt.Color == "red" || mt.Color == "white" || mt.Color == "rose" || mt.Color == "yellow" || mt.Color == "sparkling") { 119 | err = goa.InvalidEnumValueError(`default view.color`, mt.Color, []interface{}{"red", "white", "rose", "yellow", "sparkling"}, err) 120 | } 121 | } 122 | if len(mt.Name) < 1 { 123 | err = goa.InvalidLengthError(`default view.name`, mt.Name, 1, true, err) 124 | } 125 | if len(mt.Name) > 255 { 126 | err = goa.InvalidLengthError(`default view.name`, mt.Name, 255, false, err) 127 | } 128 | if mt.Sweetness < 1 { 129 | err = goa.InvalidRangeError(`default view.sweetness`, mt.Sweetness, 1, true, err) 130 | } 131 | if mt.Sweetness > 5 { 132 | err = goa.InvalidRangeError(`default view.sweetness`, mt.Sweetness, 5, false, err) 133 | } 134 | tmp6 := map[string]interface{}{ 135 | "color": mt.Color, 136 | "href": mt.Href, 137 | "id": mt.ID, 138 | "name": mt.Name, 139 | "sweetness": mt.Sweetness, 140 | } 141 | res = tmp6 142 | return res, err 143 | } 144 | 145 | // Validate validates the media type instance. 146 | func (mt *Bottle) Validate() (err error) { 147 | if mt.Color != "" { 148 | if !(mt.Color == "red" || mt.Color == "white" || mt.Color == "rose" || mt.Color == "yellow" || mt.Color == "sparkling") { 149 | err = goa.InvalidEnumValueError(`response.color`, mt.Color, []interface{}{"red", "white", "rose", "yellow", "sparkling"}, err) 150 | } 151 | } 152 | if len(mt.Name) < 1 { 153 | err = goa.InvalidLengthError(`response.name`, mt.Name, 1, true, err) 154 | } 155 | if len(mt.Name) > 255 { 156 | err = goa.InvalidLengthError(`response.name`, mt.Name, 255, false, err) 157 | } 158 | if mt.Sweetness < 1 { 159 | err = goa.InvalidRangeError(`response.sweetness`, mt.Sweetness, 1, true, err) 160 | } 161 | if mt.Sweetness > 5 { 162 | err = goa.InvalidRangeError(`response.sweetness`, mt.Sweetness, 5, false, err) 163 | } 164 | return 165 | } 166 | --------------------------------------------------------------------------------