Giter Site home page Giter Site logo

goadesign / goa Goto Github PK

View Code? Open in Web Editor NEW
5.5K 155.0 550.0 35.32 MB

🌟 Goa: Elevate Go API development! πŸš€ Streamlined design, automatic code generation, and seamless HTTP/gRPC support. ✨

Home Page: https://goa.design

License: MIT License

Makefile 0.19% Go 94.35% Smarty 5.47%
go goa microservices rest api code-generation swagger openapi golang

goa's People

Contributors

abourget avatar arangamani avatar aslakknutsen avatar bits01 avatar bketelsen avatar cquinn avatar cubic3d avatar deepsource-autofix[bot] avatar dependabot[bot] avatar derekperkins avatar dominicm avatar douglaswth avatar ernesto-jimenez avatar ikawaha avatar kitagry avatar maleck13 avatar michaelurman avatar moorereason avatar nii236 avatar nikolaas avatar nitinmohan87 avatar on99 avatar psschroeter avatar raphael avatar sevein avatar slatteryjim avatar smessier avatar tchssk avatar tmcladam avatar townewgokgok avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

goa's Issues

Rendering Media Type with nullable primitive attribute

Hi,

As discussed on Slack#goa, I'm summing up problem with optional/nullable Media Type attributes.

All primitive attributes generated by Goa are being generated with the type stated in the design. Such generation however doesn't allow these primitive types be nullable and forces producer of Media Type instance to set (keep) a default value instead.

This problem is not present for Attributes having custom Media Type (Qux), which are being generated with type of pointer to the Media Type (Qux *Qux) - pointer is nullable.

Hence I'm missing a possibility to state in the Media Type Attribute design that the Attribute is nullable, so it would be generated with pointer type. Something like this:

Baz := MediaType("Baz", func() {
    Attributes(func() {
        Attribute("Count", Integer)
    }
}
MyMediaType := MediaType("MyMediaType", func() {
    Attributes(func() {
        Attribute("Foo", Integer, Nullable) // missing
        Attribute("Bar", Integer) // already present
        Attribute("Baz", Baz) // already present
    }
}

Would generate following:

struct MyMediaType {
    Foo *int, // missing
    Bar int, // already present
    Baz *Baz, // already present
}

ArrayOf(A) + MinLength generates invalid code

Using the attached design file, goagen app generates invalid code. The exact errors at compile time are:

app/contexts.go:73: cannot use tmp1 (type []string) as type string in argument to goa.InvalidLengthError
app/media_types.go:46: cannot use mt.Strings (type []string) as type string in argument to goa.InvalidLengthError
app/media_types.go:67: cannot use source.Strings (type []string) as type string in argument to goa.InvalidLengthError
app/media_types.go:104: cannot use tmp7 (type []string) as type string in argument to goa.InvalidLengthError

If there's something I'm doing wrong here, I'd love to know what it is. Otherwise, this looks like a bug?


package test

import (
    . "github.com/raphael/goa/design"
    . "github.com/raphael/goa/design/dsl"
)

func init() {
    API("test", func() {
        Title("reproduce a bug, maybe")
    })

    test := MediaType("application/vnd.test+json", func() {
        attrs := func() {
            Attribute("strings", ArrayOf(String), func() { MinLength(1) })

            Required("strings")
        }

        Attributes(attrs)
        View("default", attrs)
    })

    Resource("test", func() {
        Action("create", func() {
            Routing(POST("/"))

            Payload(test)

            Response(Created, func() { Media(test) })
        })
    })
}

Code generation error when using DSL Minimum(0)

The generated validation code for Minimum(0) will be something like:

if v > <no value> {
...
}

which is invalid.

The template for generating this is https://github.com/raphael/goa/blob/master/goagen/codegen/validation.go#L242. It use the value of the key min of the map data to determine whether the template is dealing with Minimum() or Maximum().

From the document of text/template, {{if pipeline}} is checking against the empty value of pipeline, where the empty value is defined as:

The empty values are false, 0, any nil pointer or interface value, and any array, slice, map, or string of length zero.

So for Minimum(0), the template will actually think it is dealing with Maximum(), but the corresponding key max is missing from data, thus the generated text will be > <no value>.

I think MinLength() also has this problem, but no one will use MinLength(0), so it's fine.

One solution for this, I think, would be to abuse the data map to store the actual validation type in it, and check against that in the template.

Error response clarification

I love the error responses, but "kind" with an integer is confusing. "error_number" or something similar would be more clear.

CORS for Swagger UI is broken

Hi,

I am struggle on this. Let's see if anybody can help me.

Since I have pulled the last version, my auto-generated swagger/swagger.go looks like:

func MountController(service goa.Service) {
    service.ServeFiles("/swagger.json", "swagger/swagger.json")
}

This makes sense since swagger.json is a static file.

However, before it looked like:

// MountController mounts the swagger spec controller under "/swagger.json".
func MountController(service goa.Service) {
    ctrl := service.NewController("Swagger")
    service.Info("mount", "ctrl", "Swagger", "action", "Show", "route", "GET /swagger.json")
    h := ctrl.NewHTTPRouterHandle("Show", getSwagger)
    service.HTTPHandler().(*httprouter.Router).Handle("GET", "/swagger.json", h)
}

// getSwagger is the httprouter handle that returns the Swagger spec.
// func getSwagger(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
func getSwagger(ctx *goa.Context) error {
    ctx.Header().Set("Content-Type", "application/swagger+json")
    ctx.Header().Set("Cache-Control", "public, max-age=3600")
    return ctx.Respond(200, []byte(spec))
}

// Generated spec
const spec = `{...} `

If I understood, this old version sets a handler for the given path to serve the swagger spec.

Now, once we set up CORS using the new goa-middleware/cors the library parses handlers adding required headers.

However, now the controller does not tie path to handler, therefore, the request serves the file but does not change any header to allow CORS.

Any tip to solve this?

Thanks!

goagen fails to find the design package when GOPATH is colon-separated list of locations

STRs

  1. Set GOPATH to colon separated list of locations and run goagen
    Notice it fails
goagen app -d github.com/rightscale/acl/design 
cannot find design package at path
"/Users/avinash/.gvm/pkgsets/go1.5/acl:/Users/avinash/go:/Users/avinash/.gvm/pkgsets/go1.5/global/src/github.com/rightscale/acl/design"
make: *** [acl] Error 1
localhost:acl avinash$ pwd
/Users/avinash/go/src/github.com/rightscale/acl
localhost:acl avinash$ echo $GOPATH
/Users/avinash/.gvm/pkgsets/go1.5/acl:/Users/avinash/go:/Users/avinash/.gvm/pkgsets/go1.5/global
  1. Change the GOPATH to the go workspace ~/go
    Notice the goagen succeeds

Looking at the code the problems seems to be here
https://github.com/raphael/goa/blob/v5/codegen/meta/generator.go#L63-L70

Missing dependency packages

There are several dependencies missing in makefile so make cannot pass, fix it by

Add missing packages to makefile

or

vendor godep

Support for type "File"

The swagger spec allows for something like:

name: avatar
in: formData
description: The avatar of the user
required: true
type: file

with type: file and in: formData .. I've also seen in: body over here

I've crawling the docs and I can't see a way to currently handle a file upload.

Have you guys needed to do such thing? Do you simply use a String field and base64 encode everything, and write it as text in the description of your service ?

`Unmarshal(Marshal(userType))` fails with []string field

Trying to validate an object by Marshalling it and then Unmarshalling it, but getting this error:

{
   "id":    3,
   "title": "invalid attribute type",
   "msg":   "type of load.Database.Global.ReadHosts must be array but got value []string{\"localhost\"}"
}

There seems to be an asymmetry in the generated code with handling a []string field:

Perhaps UnmarshalConfig() could handle both []interface or []string?

Support Security specs

In a swagger file, you can specify:

securityDefinitions:
  jwtAuth:
    type: apiKey
    name: Authorization
    in: header
security:
  - jwtAuth: []

and the Sagger edito and other things will help you authenticate. It also specifies to the user which authentication mechanism you want to use.

Also, it seems possible to list the security per action or resources..

It seems that would be a great addition to the DSL, having some sort of SecurityDefinition(func() {} and Security("method") somewhere, wouldn't it ?

Refs: http://swagger.io/specification/#securityDefinitionsObject

Using ArrayOf(HashOf(String, Any)) causes issues when building the project

package design

import (
    . "github.com/raphael/goa/design"
    . "github.com/raphael/goa/design/dsl"
)

var _ = API("goa_is_awesome", func() {
    Title("Goa is awesome")
})

var _ = Resource("foo", func() {
    Action("create", func() {
        Routing(
            POST("/foo"),
        )
        Payload(CreatePayload)
        Response(OK)
    })
})

var CreatePayload = Type("input", func() {
    Attribute("details", ArrayOf(HashOf(String, Any)), "The details")
})

causes the following issue when building the project after code generation:

# git.arangamani.net/arangamani/playground/goa-issue/app
app/user_types.go:38: cannot use tmp4 (type map[interface {}]interface {}) as type map[string]interface {} in assignment

Here is the block of generated code that causes the issue

func MarshalInput(source *Input, inErr error) (target map[string]interface{}, err error) {
    err = inErr
    tmp2 := map[string]interface{}{}
    if source.Details != nil {
        tmp3 := make([]map[string]interface{}, len(source.Details))
        for i, r := range source.Details {
            tmp4 := make(map[interface{}]interface{}, len(r))
            for k, v := range r {
                var mk interface{}
                mk = k
                var mv interface{}
                mv = v
                tmp4[mk] = mv
            }
            tmp3[i] = tmp4
        }
        tmp2["details"] = tmp3
    }
    target = tmp2
    return
}

To be specific: the statement tmp3[i] = tmp4 is the one causing the error.

Nested View marshal default instead of View("tiny")

I want to embed a nested collection of X media type with tiny view instead of default. How can we do that.

Example of what I need.

package design

import (
    . "github.com/raphael/goa/design"
    . "github.com/raphael/goa/design/dsl"
)

var _ = API("test", func() {
    Title("Nested View test API")
    Host("localhost:8080")
    Scheme("http")
})

var _ = Resource("event", func() {
    BasePath("/events")
    DefaultMedia(Event)
    Action("list", func() {
        Routing(GET(""))
        Description("List all event with tiny embeded prices")
        Response(OK, func() {
            Media(CollectionOf(Event, func() {
                View("default")
                View("tiny")
            }))
        })
        Response(NotFound)
    })
    Action("show", func() {
        Description("Retrieve event with given id")
        Routing(GET("/:eventID"))
        Params(func() {
            Param("eventID", String, "Event ID")
        })
        Response(OK)
        Response(NotFound)
    })
})

// Event media type
var Event = MediaType("application/vnd.event+json", func() {
    Description("A event information")
    Attributes(func() {
        Attribute("id", String, "Unique event ID")
        Attribute("href", String, "API href of event")
        Attribute("title", String, "Title")
        Attribute("prices", ArrayOf(Price), "Price collection for this event")

        Required("id", "title")
    })
    View("default", func() {
        Attribute("id")
        Attribute("href")
        Attribute("title")
        // ... more attributes here
        Attribute("prices", func() {
            View("default")
        })
    })
    View("tiny", func() {
        Attribute("id")
        Attribute("title")
        Attribute("href")
        Attribute("prices", func() {
            View("tiny")
        })
    })

})

var _ = Resource("price", func() {
    Parent("event")
    BasePath("prices")
    DefaultMedia(Price)
    Action("list", func() {
        Routing(GET(""))
        Description("List all price price in event")
        Response(OK, func() {
            Media(CollectionOf(Price, func() {
                View("default")
            }))
        })
        Response(NotFound)
    })
    Action("show", func() {
        Description("Retrieve price with given id")
        Routing(GET("/:priceID"))
        Params(func() {
            Param("priceID", String, "Price ID")
        })
        Response(OK)
        Response(NotFound)
    })
})

// Price price media type
var Price = MediaType("application/vnd.price+json", func() {
    Description("Price")
    Attributes(func() {
        Attribute("id", String, "Unique price ID")
        Attribute("name", String, "general name to use for ticket")
        Attribute("order", Integer, "ascending order of tickets as shown on event page")
        Attribute("price", Number, "the value of the ticket, 0.00 when free")

        Required("id", "name")
    })

    View("default", func() {
        Attribute("id")
        Attribute("name")
        Attribute("order")
        Attribute("price")
    })

    View("tiny", func() {
        Attribute("id")
        Attribute("price")
    })

    View("link", func() {
        Attribute("id")
        Attribute("price")
    })
})

generated code will look like

// MarshalEventTiny validates and renders an instance of Event into a interface{}
// using view "tiny".
func MarshalEventTiny(source *Event, inErr error) (target map[string]interface{}, err error) {
    ...
    if source.Prices != nil {
        ...
            tmp6[tmp7], err = MarshalPrice(tmp8, err)
        ...
    }
    ...
}

Should be tmp6[tmp7], err = MarshalPriceTiny(tmp8, err)

Defining a Parent in the design does not create parent parameters for swagger specs

Hi,

I think there is an issue with the swagger.json generated through design.

Let's say you have something like:

  var _ = Resource("parent", func() {
    //...
    BasePath("parents")
    Action("show", func() {
        Routing(GET("/:parentID"))
        Params(func() {
            Param("parentID", String, "Parent ID")
        })
                //...
    })
    //...
  }

  //...

  var _ = Resource("child", func() {
    //...
    BasePath("children")
    Parent("parent")
    Action("show", func() {
        Routing(GET("/:childID"))
        Params(func() {
            Param("childID", String, "Child ID")
        })
                //...
    })
    //...
  }

Then, you have following endpoints open:

GET /parents/{ParentID}
GET /parents/{ParentID}/children/{ChildrenID}

If you use the auto-generated swagger.json with the official swagger-UI, for the case of GET parent, everything works fine.

But for the case of GET children, the UI does not offer the parameter parentID. However it does, correctly, the parameter childID.

Running the action, takes you to a failure, since you cannot supply the parentID, any how.

Therefore, my assumption is that, in design, when you state Parent('parent') in design and auto-generate the code, the parent parameters are not checked to properly generate the swagger.json file, for the children case.

Not sure if the explanation is clear.

Any tip on this?

Thanks in advance!

Handle cyclic Type dependencies

The following:

package design

import (
    . "github.com/raphael/goa/design"
    . "github.com/raphael/goa/design/dsl"
)

var Account = MediaType("application/vnd.example.account", func() {
    Attributes(func() {
        Attribute("bottles", CollectionOf("application/vnd.example.bottle"))
    })
    View("default", func() {
        Attribute("bottles")
    })
})

var Bottle = MediaType("application/vnd.example.bottle", func() {
    Attributes(func() {
        Attribute("account", Account)
    })
    View("default", func() {
        Attribute("account")
    })
})

causes goagen to hang as the rendering code does not handle the cyclic dependency properly and loops indefinitely. Add code to detect this situation.

API Version and Schemes

I create a test description:

package design

import (
    . "github.com/raphael/goa/design"
    . "github.com/raphael/goa/design/dsl"
)

var _ = API("I_love_goa", func() {
    Title("Test of API")
    Host("localhost:8080")
    Scheme("http")
    BasePath("/api/v1")
})

var _ = Resource("test", func() {
    BasePath("/test")
    DefaultMedia(TestMedia)
    Action("list", func() {
        Routing(
            GET(""),
        )
        Response(OK)
    })
})

var TestMedia = MediaType("application/vnd.test+json", func() {
    Attributes(func() {
        Attribute("id", String, "ID of object")
    })
    View("default", func() {
        Attribute("id")
        Required("id")
    })
})

and generate swagger.json file:

{  
   "swagger":"2.0",
   "info":{  
      "title":"Test of API",
      "version":""
   },
   "host":"localhost:8080",
   "basePath":"/api/v1",
   "schemes":[  
      "http"
   ],
   "consumes":[  
      "application/json"
   ],
   "produces":[  
      "application/json"
   ],
   "paths":{  
      "/test":{  
         "get":{  
            "operationId":"test#list",
            "consumes":[  
               "application/json"
            ],
            "produces":[  
               "application/json"
            ],
            "responses":{  
               "200":{  
                  "description":"",
                  "schema":{  
                     "$ref":"#/definitions/Test"
                  }
               }
            },
            "schemes":[  
               "https"
            ]
         }
      }
   },
   "definitions":{  
      "Test":{  
         "title":"Mediatype identifier: application/vnd.test+json",
         "type":"object",
         "properties":{  
            "id":{  
               "type":"string",
               "description":"ID of place"
            }
         }
      }
   }
}
  • How I can set a info.version in definition?
  • In schemes defined only http, but in resource definition I have https.
  • Is consumes and produces always only application/json?
  • Empty description in responses.

Generated error - cannot build

I try generating code from your examples/cellar/design and get some error from generated code.

./account.go:16: cannot use AccountController literal (type *AccountController) as type AccountController in return argument
./bottle.go:16: cannot use BottleController literal (type *BottleController) as type BottleController in return argument
./main.go:20: not enough arguments in call to NewAccountController
./main.go:21: cannot use c (type AccountController) as type app.AccountController in argument to app.MountAccountController:
    AccountController does not implement app.AccountController (Create method has pointer receiver)
./main.go:23: not enough arguments in call to NewBottleController
./main.go:24: cannot use c2 (type BottleController) as type app.BottleController in argument to app.MountBottleController:
    BottleController does not implement app.BottleController (Create method has pointer receiver)

Here what I get from generated code https://github.com/MathieuDoyon/goa-test

goagen command help output no longer displays subcommands

goagen --help
usage: codegen help [...]

Show help.

Flags:
--help Show context-sensitive help (also try --help-long and --help-man).
--version Show application version.
-o, --out="/home/bketelsen" output directory
-d, --design=DESIGN design package path
--debug enable debug mode

Args:
[] Show help on command.

Subcommands:
{END of output from help command}

Make it possible to use the media type identifier with `CollectionOf`

So that it's possible to do:

var Account = MediaType("application/vnd.example.account", func() {
  Attributes(func() {
    Attribute("bottles", CollectionOf("application.vnd.example.bottle"))
  })
})

var Bottle = MediaType("application/vnd.example.bottle", func() {
  Attributes(func() {
    Attribute("account", Account)
  })
})

Since using Bottle instead of "application.vnd.example.bottle" in the first definition would cause a compilation error (Initialization loop).

ResponseTemplates, allow multiple of the same HTTP code ?

I'm wondering why it wouldn't be possible to have multiple ResponseTemplates for BadRequest (or other codes), provided the signature of the func() is not the same.

This forces me to use:

        Response(BadRequest, "Branch or build not found")

when I defined:

    ResponseTemplate(BadRequest, func(reason string) {
        msg := "Bad Request"
        if reason != "" {
            msg = fmt.Sprintf("%s: %s", msg, reason)
        }
        Description(msg)
        Status(400)
        Media(ErrorModel)
    })

because of the reason. Not specifying a reason seems to fallback on some internal definitions.. but I really do want any BadRequest to use the ErrorModel media.

I tried to add:

    ResponseTemplate(BadRequest, func() {
        Description("Bad Request")
        Status(400)
        Media(ErrorModel)
    })

to also support:

        Response(BadRequest)

but I got an error message saying it was already defined. It's true.. but not the exact same signature!

btw, thanks for the awesome framework !

Documentation issue - installation

Hi,

I started from http://goa.design/getting-started.html
I installed following instructions from : http://goa.design/goagen.html

Neither one mentions use/dependency on goimports so initially I hadn't installed it.

The code gen completes successfully but the resulting code doesn't build due to incorrect imports - took me a while to stumble on the requirement for goimports.

I suggest you make the code gen step fail if goimports isn't installed. Can you also update the docs on the web page we reference to it.

Finally, the example on the getting started needs updating, app.Bottle isn't valid, needs changing to app.GoaExampleBottle.

Thanks,
Alan

Support `Consumes()` and `Produces()` DSL

The idea is to support mimetypes other than application/json, which is hard-coded right now (at least in the swagger generation).

application/json could be the default, but specifying Consumes() at the API() or Action() level could override the fallback value, and you could add one or more of those mime types.

When generating the app, we could do all the magic and validation when application/json is present,
but otherwise leave the user free to do all the unmarshalling / reading the body if it's not application/json..

What do you think ?

import of `fmt` missing and/or imported but not used

Generated files for app import fmt but do not use it. Prevents building with those generated files.

I am using gb for dependency management, but this does not appear to be related to that.

Using go version go1.5.1 darwin/amd64

package design

import (
    . "github.com/raphael/goa/design"
    . "github.com/raphael/goa/design/dsl"
)

var _ = API("example", func() {
    Title("The API")
    Description("An API")
    Scheme("http")
    Host("localhost:8080")
})

var _ = Resource("story", func() {
    BasePath("/stories")
    DefaultMedia(StoryMedia)
    Action("show", func() {
        Description("Get a Story with a given ID")
        Routing(GET("/:storyID"))
        Params(func() {
            Param("storyID", Integer, "Story ID")
        })
        Response(OK)
        Response(NotFound)
    })
})

var StoryMedia = MediaType("application/vnd.goa.example.story+json", func() {
    Description("A Story")
    Attributes(func() {
        Attribute("id", Integer, "Unique Story ID")
        Attribute("title", String, "Title of Story")
    })

    View("default", func() {
        Attribute("id")
        Attribute("title")
    })
})

Running the following command to build app package:

./bin/goagen -d project/design app -o src/project

And this to build:

gb build project

Output (truncated):

contexts.go:50: undefined: fmt in fmt.Errorf
hrefs.go:17: undefined: fmt in fmt.Sprintf
media_types.go:17: imported and not used: "fmt"
FATAL: command "build" failed: exit status 2

JWT middleware usage example

Would it be possible to have example of how to use JWT middleware ?
CORS was quite easy and there are docs on the site but I can't get my head around how you use JWT

HTTP response is Golang specific

Tiny issue with a confusing error message.. When POSTing no data to an action that has required parameters, I get this 400 Bad Request response:

[
    {
        "kind": 3, 
        "msg": "type of payload must be map[string]interface{} but got value <nil>", 
        "title": "invalid attribute type"
    }
]

The msg was a little confusing since it talks in Golang terms: map[string]interface{}. It really just wants me to submit some valid JSON, like at least {}.

question: DSL: Require nested attribute in payload

Hi,

how would one mark a nested attribute as required in a payload?

For example:

var DataType = Type("DataType", func() {
    Attribute("id", Integer)
})

var TestPayload = Type("TestPayload", func() {
    Attribute("test", String)
    Attribute("data", DataType)
})

....

Payload(TestPayload, func() {
    Required("test")
})

How would one mark the test DataType id attribute as required in the Payload?

"bare" value support

My use case: wrap K/V stores with a type interface (github.com/asteris-llc/gestalt, functionality is currently in the feature/web fork).

I'd like to use interface{} as a payload/return type (the value in a K/V store), instead of having to marshal/unmarshal that myself. In addition, it'd be super if I could use Hash(String, Any) as a media type directly (for a hash of values)

Trying to use Teaser example and it fails.

This is likely a simple noob question. I was trying to use goa. As an initial example I was trying the teaser app on the main page of the repo. I executed the exact steps specified and I get the following error.

panic: template: main:13: function "targetPkg" not defined

goroutine 1 [running]:
github.com/raphael/goa/goagen/codegen.(_SourceFile).ExecuteTemplate(0xc208152260, 0x4fdf20, 0x4, 0x60c4b0, 0x453, 0x0, 0x49ae00, 0xc2080c04d0, 0x0, 0x0)
/Users/ChrisRobinson/go2/src/github.com/raphael/goa/goagen/codegen/workspace.go:263 +0x14c
github.com/raphael/goa/goagen/gen_main.funcΒ·005(0xc2080c04d0, 0x0, 0x0)
/Users/ChrisRobinson/go2/src/github.com/raphael/goa/goagen/gen_main/generator.go:146 +0x471
github.com/raphael/goa/design.(_APIDefinition).IterateResources(0xc2080ebef0, 0xc20814fe30, 0x0, 0x0)
/Users/ChrisRobinson/go2/src/github.com/raphael/goa/design/api.go:355 +0x267
github.com/raphael/goa/goagen/gen_main.(*Generator).Generate(0xc20810eb00, 0xc2080ebef0, 0x0, 0x0, 0x0, 0x0, 0x0)
/Users/ChrisRobinson/go2/src/github.com/raphael/goa/goagen/gen_main/generator.go:155 +0x15e6
github.com/raphael/goa/goagen/gen_main.Generate(0xc2080ebef0, 0x0, 0x0, 0x0, 0x0, 0x0)
/Users/ChrisRobinson/go2/src/github.com/raphael/goa/goagen/gen_main/generator.go:31 +0xa7
main.main()
/var/folders/wq/hw1k0rbs56d7_lp7ln6v30j00000gn/T/goagen068784337/src/design/main.go:26 +0x5b

goroutine 5 [syscall]:
os/signal.loop()
/usr/local/go/src/os/signal/signal_unix.go:21 +0x1f
created by os/signal.initΒ·1
/usr/local/go/src/os/signal/signal_unix.go:27 +0x35

goroutine 26 [chan receive]:
github.com/raphael/goa/goagen/utils.Catch(0x7a6c60, 0x6, 0x6, 0xc2080f1750)
/Users/ChrisRobinson/go2/src/github.com/raphael/goa/goagen/utils/signal.go:15 +0xb1
created by github.com/raphael/goa/goagen/gen_main.(*Generator).Generate
/Users/ChrisRobinson/go2/src/github.com/raphael/goa/goagen/gen_main/generator.go:63 +0x149

goroutine 29 [chan send]:
text/template/parse.lexRightDelim(0xc208114200, 0x5fb5b8)
/usr/local/go/src/text/template/parse/lex.go:263 +0xb7
text/template/parse.(*lexer).run(0xc208114200)
/usr/local/go/src/text/template/parse/lex.go:198 +0x5d
created by text/template/parse.lex
/usr/local/go/src/text/template/parse/lex.go:191 +0x1ac

I'm running this on go 1.4, any ideas why this failure is occurring? I was trying to track it down. This failure is consistent for me, I tried in two different separate go path's that I had. Same issue. Am I missing a setting or was there a change that requires a change in the dsl to get this to work?

Response Templates defined but not referenced in Swagger output

Given the following API snippet:

const (
    // For Response Templates
    Deleted = "Deleted"
    Updated = "Updated"
)

var _ = API("test", func() {
    Title("Test API")
    Description("A Test API")

    Scheme("http")
    Host("localhost:8080")

    ResponseTemplate(Created, func(pattern string) {
        Description("Resource created")
        Status(201)
        Headers(func() {
            Header("Location", String, "href to created resource", func() {
                Pattern(pattern)
            })
        })
    })

    ResponseTemplate(Deleted, func() {
        Description("Resource deleted")
        Status(204)
    })

    ResponseTemplate(Updated, func() {
        Description("Resource updated")
        Status(204)
    })
})

var _ = Resource("organization", func() {
    BasePath("orgs")
    DefaultMedia(OrganizationMedia)

    Action("create", func() {
        Description("Create new organization")
        Routing(POST(""))
        Payload(func() {
            Member("name")
            Required("name")
        })
        Response(Created, "^/orgs/[0-9]+")
    })

    Action("delete", func() {
        Description("Delete an organization")
        Routing(DELETE("/:organizationId"))
        Params(func() {
            Param("organizationId", Integer, "Organization ID")
        })
        Response(Deleted)
    })

    Action("update", func() {
        Description("Update an organization")
        Routing(PUT("/:organizationId"))
        Params(func() {
            Param("organizationId", Integer, "Organization ID")
        })
        Payload(func() {
            Member("name")
            Required("name")
        })
        Response(Updated)
    })
})

var OrganizationMedia = MediaType("application/vnd.test.organization+json", func() {
    Description("An organization")
    Attributes(func() {
        Attribute("organization_id", Integer, "Unique organization ID")
        Attribute("name", String, "Organization Name")
    })
    View("default", func() {
        Attribute("organization_id")
        Attribute("name")
    })
})

The Swagger JSON output renders the responses as such:

"responses":{
  "201":{
    "description":"Resource created",
    "headers":{
      "Location":{
        "description":"href to created resource",
        "type":"string",
        "pattern":"^/orgs/[0-9]+"
      }
    }
  }
},
...
"responses":{"204":{"description":"Resource deleted"}},
...
"responses":{"204":{"description":"Resource updated"}},
...
// End of the JSON file contains these response definitions:
"responses":{
  "Deleted":{
    "description":"Resource deleted"
  },
  "Updated":{
    "description":"Resource updated"
  }
}

Loading the generated swagger.json into the Swagger Editor, the editor displays these warnings:

  • ⚠️ Definition is not used: #/responses/Deleted
  • ⚠️ Definition is not used: #/responses/Updated

Migrate core middleware to goa-middleware

I think that all the middleware should exist in one place, either here in the main goa repo or over in github.com/raphael/goa-middleware. As is, there are a few "blessed" middleware that are a part of the main package.

The most compelling reason I can think of to include middleware in goa is if there is any need to share types through an internal package.

Collections are not rendered in Swagger responses

Given the following API snippet:

var _ = Resource("organization", func() {
    Action("list", func() {
        Description("Retrieve list of organizations")
        Routing(GET(""))
        Response(OK, func() {
            Media(CollectionOf(OrganizationMedia, func() {
                View("default")
            }))
        })
    })
})

var OrganizationMedia = MediaType("application/vnd.test.organization+json", func() {
    Description("An organization")
    Attributes(func() {
        Attribute("organization_id", Integer, "Unique organization ID")
        Attribute("name", String, "Organization Name")
    })
    View("default", func() {
        Attribute("organization_id")
        Attribute("name")
    })
})

The generated swagger output only contains the following for the response:

"responses": {
  "200": {
    "description": ""
  }
}

I would expect goa to generate something like this:

"responses": {
  "200": {
    "description": "",
    "schema": {
      "type": "array",
      "items": {
        "$ref": "#/definitions/TestOrganization"
      }
    }
  }
}

It looks like genswagger.responseFromDefinition is where it's falling apart. A collection response has a MediaType like application/vnd.test.organization+json; type=collection instead of application/vnd.test.organization.

Got compilation errors running the basic example

I'm trying to set up the basic example but I'm getting some errors due some bad imports.

package design

import (
        . "github.com/raphael/goa/design"
        . "github.com/raphael/goa/design/dsl"
)

var _ = API("cellar", func() {
        Title("The virtual wine cellar")
        Description("A basic example of an API implemented with goa")
        Scheme("http")
        Host("localhost:8080")
})

var _ = Resource("bottle", func() {
        BasePath("/bottles")
        DefaultMedia(BottleMedia)
        Action("show", func() {
                Description("Retrieve bottle with given id")
                Routing(GET("/:bottleID"))
                Params(func() {
                        Param("bottleID", Integer, "Bottle ID")
                })
                Response(OK)
                Response(NotFound)
        })
})

var BottleMedia = MediaType("application/vnd.goa.example.bottle+json", func() {
        Description("A bottle of wine")
        Attributes(func() {
                Attribute("id", Integer, "Unique bottle ID")
                Attribute("href", String, "API href for making requests on the bottle")
                Attribute("name", String, "Name of wine")
        })
        View("default", func() {
                Attribute("id")
                Attribute("href")
                Attribute("name")
        })
})
schema/schema.go:25: undefined: httprouter in httprouter.Router
app/contexts.go:73: undefined: fmt in fmt.Errorf
app/contexts.go:112: undefined: fmt in fmt.Errorf
app/media_types.go:17: imported and not used: "fmt"

In the scheme file, it's missing a httprouter import.

package schema

import (
    "github.com/raphael/goa"
)


// MountController mounts the API JSON schema controller under "/schema.json".
func MountController(service goa.Service) {
    ctrl := service.NewController("Schema")
    service.Info("mount", "ctrl", "Schema", "action", "Show", "route", "GET /schema.json")
    h := ctrl.NewHTTPRouterHandle("Show", getSchema)
    service.HTTPHandler().(*httprouter.Router).Handle("GET", "/schema.json", h)
}

In the contexts.go file it's missing the fmt import.

import (
    "github.com/raphael/goa"
    "strconv"
)
.
.
// OK sends a HTTP response with status code 200.
    func (ctx *ShowBottleContext) OK(resp *GoaExampleBottle) error {
    r, err := resp.Dump()
    if err != nil {
        return fmt.Errorf("invalid response: %s", err)
    }
    ctx.Header().Set("Content-Type", "application/vnd.goa.example.bottle+json; charset=utf-8")
    return ctx.JSON(200, r)
}

In the media_types.go the fmt package is not needed.

import (
    "github.com/raphael/goa"
    "fmt"
)

It seems to me that I misunderstood something. Does anyone know what I'm doing bad?

Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.