goadesign / goa Goto Github PK
View Code? Open in Web Editor NEWπ Goa: Elevate Go API development! π Streamlined design, automatic code generation, and seamless HTTP/gRPC support. β¨
Home Page: https://goa.design
License: MIT License
π Goa: Elevate Go API development! π Streamlined design, automatic code generation, and seamless HTTP/gRPC support. β¨
Home Page: https://goa.design
License: MIT License
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
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
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 !
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:
[]string
: https://github.com/rightscale/acl/blob/76ac08c2a53e949bb64b9262251a4d44680012d3/app/user_types.go#L73[]interface
: https://github.com/rightscale/acl/blob/76ac08c2a53e949bb64b9262251a4d44680012d3/app/user_types.go#L141Perhaps UnmarshalConfig() could handle both []interface
or []string
?
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}
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!
Attempts to go get on windows fails. This thread has a discussion on the problem : fvbock/endless#12
Thanks,
Alan
Swagger 2.0 supports tags: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md
would be great to have some annotation in the DSL for that!
On the page http://goa.design/swagger.html the text "cors package GoDoc" links to https://godoc.org/github.com/raphael/goa/cors. Also, to run the example, it would be helpful for the reader if the necessary import "github.com/raphael/goa-middleware/cors" was given in the example 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) })
})
})
}
to mention Metadata and possible uses
Panic occurs on response dsl Media()
call where in func Media(val interface{})
*design.MediaTypeDefinition
is nil
Expect: appropriate error.
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
.
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)
How to describe design for map[string]interface{} ?
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)
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
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?
This is a way too early micro-optimization, but it'd be cool if struct fields were optimized, similar to the checks by these tools.
https://github.com/opennota/check
https://github.com/mdempsky/maligned/
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"
}
}
}
}
}
info.version
in definition?schemes
defined only http
, but in resource definition I have https
.consumes
and produces
always only application/json
?description
in responses
.So that temporary files get cleaned up properly.
Just in case we forget.
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
}
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
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 ?
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.
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.
I love the error responses, but "kind" with an integer is confusing. "error_number" or something similar would be more clear.
Would be neat wouldn't it?
P.S.
Great project, keep it up π
Just in case we forget.
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 {}
.
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?
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:
#/responses/Deleted
#/responses/Updated
There are several dependencies missing in makefile so make cannot pass, fix it by
Add missing packages to makefile
or
vendor
godep
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.
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
).
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.
Any plans to introduce the ability to create DSL + API from JSON-Schema or Swagger (reverse of goagen)
For example; I want to be able to the a very comprehensive JSON Schemas like below and have the DSL/API being generated:
(http://www.popoloproject.com/specs/#json-schema)
Thanks for clarifying!
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
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 ?
Hello, how can i serve index.html?
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.
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!
STRs
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
Looking at the code the problems seems to be here
https://github.com/raphael/goa/blob/v5/codegen/meta/generator.go#L63-L70
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.