Skip to content

Commit a5b7d60

Browse files
authored
feat: Add type SchemaType to use in Return calls allowing for specification of a raw type value and format (#118)
* feat: Add type SchemaType to use in Return calls allowing for specification of a raw type value and format * fix: revert automatic reordering of imports * feat: handle Reads / Writes as well. Test pulled from #119
1 parent c4931e5 commit a5b7d60

File tree

2 files changed

+165
-0
lines changed

2 files changed

+165
-0
lines changed

build_path.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ const (
2424
definitionRoot = "#/definitions/"
2525
)
2626

27+
// SchemaType is used to wrap any raw types
28+
// For example, to return a "schema": "file" one can use
29+
// Returns(http.StatusOK, http.StatusText(http.StatusOK), SchemaType{RawType: "file"})
30+
type SchemaType struct {
31+
RawType string
32+
Format string
33+
}
34+
2735
func buildPaths(ws *restful.WebService, cfg Config) spec.Paths {
2836
p := spec.Paths{Paths: map[string]spec.PathItem{}}
2937
for _, each := range ws.Routes() {
@@ -243,6 +251,9 @@ func buildParameter(r restful.Route, restfulParam *restful.Parameter, pattern st
243251
} else {
244252
p.Schema.Items.Schema.Ref = spec.MustCreateRef(definitionRoot + dataTypeName)
245253
}
254+
} else if schemaType, ok := r.ReadSample.(SchemaType); ok {
255+
p.Schema.Type = []string{schemaType.RawType}
256+
p.Schema.Format = schemaType.Format
246257
} else {
247258
dataTypeName := keyFrom(st, cfg)
248259
p.Schema.Ref = spec.MustCreateRef(definitionRoot + dataTypeName)
@@ -295,6 +306,8 @@ func buildResponse(e restful.ResponseError, cfg Config) (r spec.Response) {
295306
// If the response is a primitive type, then don't reference any definitions.
296307
// Instead, set the schema's "type" to the model name.
297308
r.Schema.AddType(modelName, "")
309+
} else if schemaType, ok := e.Model.(SchemaType); ok {
310+
r.Schema.AddType(schemaType.RawType, schemaType.Format)
298311
} else {
299312
modelName := keyFrom(st, cfg)
300313
r.Schema.Ref = spec.MustCreateRef(definitionRoot + modelName)

build_path_test.go

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,3 +390,155 @@ func TestWritesPrimitive(t *testing.T) {
390390
}
391391
}
392392
}
393+
394+
// TestWritesRawSchema ensures that if an operation returns a raw schema value, then it
395+
// is used as such (and not a ref to a definition).
396+
func TestWritesRawSchema(t *testing.T) {
397+
ws := new(restful.WebService)
398+
ws.Path("/tests/returns")
399+
ws.Consumes(restful.MIME_JSON)
400+
ws.Produces(restful.MIME_JSON)
401+
402+
ws.Route(ws.GET("/raw").To(dummy).
403+
Doc("get that returns a file").
404+
Returns(200, "raw schema type", SchemaType{RawType: "file"}).
405+
Writes(SchemaType{RawType: "file"}))
406+
407+
p := buildPaths(ws, Config{})
408+
t.Log(asJSON(p))
409+
410+
// Make sure that the operation that returns a raw schema type is correct.
411+
if pathInfo, okay := p.Paths["/tests/returns/raw"]; !okay {
412+
t.Errorf("Could not find path")
413+
} else {
414+
getInfo := pathInfo.Get
415+
416+
if getInfo == nil {
417+
t.Errorf("operation was not present")
418+
}
419+
if getInfo.Summary != "get that returns a file" {
420+
t.Errorf("GET description incorrect")
421+
}
422+
response := getInfo.Responses.StatusCodeResponses[200]
423+
if response.Schema.Ref.String() != "" {
424+
t.Errorf("Expected no ref; got: %s", response.Schema.Ref.String())
425+
}
426+
if len(response.Schema.Type) != 1 {
427+
t.Errorf("Expected exactly one type; got: %d", len(response.Schema.Type))
428+
}
429+
if response.Schema.Type[0] != "file" {
430+
t.Errorf("Expected a type of file; got: %s", response.Schema.Type[0])
431+
}
432+
}
433+
}
434+
435+
// TestWritesRawSchemaWithFormat ensures that if an operation returns a raw schema value with the specified format, then it
436+
// is used as such (and not a ref to a definition).
437+
func TestWritesRawSchemaWithFormat(t *testing.T) {
438+
ws := new(restful.WebService)
439+
ws.Path("/tests/returns")
440+
ws.Consumes(restful.MIME_JSON)
441+
ws.Produces(restful.MIME_JSON)
442+
443+
ws.Route(ws.GET("/raw_formatted").To(dummy).
444+
Doc("get that returns a file").
445+
Returns(200, "raw schema type", SchemaType{RawType: "string", Format: "binary"}).
446+
Writes(SchemaType{RawType: "string", Format: "binary"}))
447+
448+
p := buildPaths(ws, Config{})
449+
t.Log(asJSON(p))
450+
451+
// Make sure that the operation that returns a raw schema type is correct.
452+
if pathInfo, okay := p.Paths["/tests/returns/raw_formatted"]; !okay {
453+
t.Errorf("Could not find path")
454+
} else {
455+
getInfo := pathInfo.Get
456+
457+
if getInfo == nil {
458+
t.Errorf("operation was not present")
459+
}
460+
if getInfo.Summary != "get that returns a file" {
461+
t.Errorf("GET description incorrect")
462+
}
463+
response := getInfo.Responses.StatusCodeResponses[200]
464+
if response.Schema.Ref.String() != "" {
465+
t.Errorf("Expected no ref; got: %s", response.Schema.Ref.String())
466+
}
467+
if len(response.Schema.Type) != 1 {
468+
t.Errorf("Expected exactly one type; got: %d", len(response.Schema.Type))
469+
}
470+
if response.Schema.Type[0] != "string" {
471+
t.Errorf("Expected a type of string; got: %s", response.Schema.Type[0])
472+
}
473+
if response.Schema.Format != "binary" {
474+
t.Errorf("Expected a format of binary; got: %s", response.Schema.Format)
475+
}
476+
}
477+
}
478+
479+
// TestReadAndWriteArrayBytesInBody ensures that if an operation reads []byte in body or returns []byte,
480+
// then it is represented as "string" with "binary" format.
481+
func TestReadAndWriteArrayBytesInBody(t *testing.T) {
482+
ws := new(restful.WebService)
483+
ws.Path("/tests/a")
484+
ws.Consumes(restful.MIME_JSON)
485+
ws.Produces(restful.MIME_XML)
486+
487+
binaryType := SchemaType{RawType: "string", Format: "binary"}
488+
ws.Route(ws.POST("/a/b").To(dummy).
489+
Doc("post a b test with array of bytes in body").
490+
Returns(200, "list of a b tests", binaryType).
491+
Returns(500, "internal server error", binaryType).
492+
Reads(binaryType).
493+
Writes(binaryType))
494+
495+
p := buildPaths(ws, Config{})
496+
t.Log(asJSON(p))
497+
498+
postInfo := p.Paths["/tests/a/a/b"].Post
499+
500+
if postInfo.Summary != "post a b test with array of bytes in body" {
501+
t.Errorf("POST description incorrect")
502+
}
503+
postBody := postInfo.Parameters[0]
504+
505+
if got, want := postBody.Schema.Type[0], "string"; got != want {
506+
t.Errorf("got %v want %v", got, want)
507+
}
508+
if got, want := postBody.Schema.Format, "binary"; got != want {
509+
t.Errorf("got %v want %v", got, want)
510+
}
511+
if postBody.Schema.Ref.String() != "" {
512+
t.Errorf("you shouldn't have body Ref setting when using array in body!")
513+
}
514+
if postBody.Format != "" || postBody.Type != "" || postBody.Default != nil {
515+
t.Errorf("Invalid parameter property is set on body property")
516+
}
517+
518+
if _, exists := postInfo.Responses.StatusCodeResponses[200]; !exists {
519+
t.Errorf("Response code 200 not added to spec.")
520+
}
521+
sch := postInfo.Responses.StatusCodeResponses[200].Schema
522+
if sch == nil {
523+
t.Errorf("Schema for Response code 200 not added to spec.")
524+
}
525+
if got, want := sch.Type[0], "string"; got != want {
526+
t.Errorf("got %v want %v", got, want)
527+
}
528+
if got, want := sch.Format, "binary"; got != want {
529+
t.Errorf("got %v want %v", got, want)
530+
}
531+
if _, exists := postInfo.Responses.StatusCodeResponses[500]; !exists {
532+
t.Errorf("Response code 500 not added to spec.")
533+
}
534+
sch = postInfo.Responses.StatusCodeResponses[500].Schema
535+
if sch == nil {
536+
t.Errorf("Schema for Response code 500 not added to spec.")
537+
}
538+
if got, want := sch.Type[0], "string"; got != want {
539+
t.Errorf("got %v want %v", got, want)
540+
}
541+
if got, want := sch.Format, "binary"; got != want {
542+
t.Errorf("got %v want %v", got, want)
543+
}
544+
}

0 commit comments

Comments
 (0)