Merge pull request #5938 from nikhiljindal/swagger

Updating to the latest go-restful code and regenerating the swagger spec
This commit is contained in:
Clayton Coleman 2015-03-25 16:25:58 -04:00
commit c35593a717
25 changed files with 1557 additions and 503 deletions

4
Godeps/Godeps.json generated
View File

@ -170,8 +170,8 @@
},
{
"ImportPath": "github.com/emicklei/go-restful",
"Comment": "v1.1.3-10-g62dc65d",
"Rev": "62dc65d6e51525418cad2bb6f292d3cf7c5e9d0a"
"Comment": "v1.1.3-26-g977ac8f",
"Rev": "977ac8fcbcd2ee33319246f7c91d4b426402dc70"
},
{
"ImportPath": "github.com/evanphx/json-patch",

View File

@ -1,5 +1,19 @@
Change history of go-restful
=
2015-03-20
- add configurable logging
2015-03-18
- if not specified, the Operation is derived from the Route function
2015-03-17
- expose Parameter creation functions
- make trace logger an interface
- fix OPTIONSFilter
- customize rendering of ServiceError
- JSR311 router now handles wildcards
- add Notes to Route
2014-11-27
- (api add) PrettyPrint per response. (as proposed in #167)

View File

@ -53,6 +53,7 @@ func (u UserResource) findUser(request *restful.Request, response *restful.Respo
- API declaration for Swagger UI (see swagger package)
- Panic recovery to produce HTTP 500, customizable using RecoverHandler(...)
- Route errors produce HTTP 404/405/406/415 errors, customizable using ServiceErrorHandler(...)
- Configurable (trace) logging
### Resources
@ -64,8 +65,8 @@ func (u UserResource) findUser(request *restful.Request, response *restful.Respo
- [gopkg.in](https://gopkg.in/emicklei/go-restful.v1)
- [showcase: Mora - MongoDB REST Api server](https://github.com/emicklei/mora)
[![Build Status](https://drone.io/github.com/emicklei/go-restful/status.png)](https://drone.io/github.com/emicklei/go-restful/latest)[![library users](https://sourcegraph.com/api/repos/github.com/emicklei/go-restful/badges/library-users.png)](https://sourcegraph.com/github.com/emicklei/go-restful) [![authors](https://sourcegraph.com/api/repos/github.com/emicklei/go-restful/badges/authors.png)](https://sourcegraph.com/github.com/emicklei/go-restful) [![xrefs](https://sourcegraph.com/api/repos/github.com/emicklei/go-restful/badges/xrefs.png)](https://sourcegraph.com/github.com/emicklei/go-restful)
[![Build Status](https://drone.io/github.com/emicklei/go-restful/status.png)](https://drone.io/github.com/emicklei/go-restful/latest)
(c) 2012 - 2014, http://ernestmicklei.com. MIT License
(c) 2012 - 2015, http://ernestmicklei.com. MIT License
Type ```git shortlog -s``` for a full list of contributors.

View File

@ -5,8 +5,9 @@ package restful
// that can be found in the LICENSE file.
const (
MIME_XML = "application/xml" // Accept or Content-Type used in Consumes() and/or Produces()
MIME_JSON = "application/json" // Accept or Content-Type used in Consumes() and/or Produces()
MIME_XML = "application/xml" // Accept or Content-Type used in Consumes() and/or Produces()
MIME_JSON = "application/json" // Accept or Content-Type used in Consumes() and/or Produces()
MIME_OCTET = "application/octet-stream" // If Content-Type is not present in request, use the default
HEADER_Allow = "Allow"
HEADER_Accept = "Accept"

View File

@ -7,10 +7,12 @@ package restful
import (
"bytes"
"fmt"
"log"
"net/http"
"os"
"runtime"
"strings"
"github.com/emicklei/go-restful/log"
)
// Container holds a collection of WebServices and a http.ServeMux to dispatch http requests.
@ -107,7 +109,8 @@ func (c *Container) Add(service *WebService) *Container {
// cannot have duplicate root paths
for _, each := range c.webServices {
if each.RootPath() == service.RootPath() {
log.Fatalf("[restful] WebService with duplicate root path detected:['%v']", each)
log.Printf("[restful] WebService with duplicate root path detected:['%v']", each)
os.Exit(1)
}
}
// if rootPath was not set then lazy initialize it
@ -132,7 +135,7 @@ func logStackOnRecover(panicReason interface{}, httpWriter http.ResponseWriter)
}
buffer.WriteString(fmt.Sprintf(" %s:%d\r\n", file, line))
}
log.Println(buffer.String())
log.Print(buffer.String())
httpWriter.WriteHeader(http.StatusInternalServerError)
httpWriter.Write(buffer.Bytes())
}
@ -171,7 +174,7 @@ func (c *Container) dispatch(httpWriter http.ResponseWriter, httpRequest *http.R
var err error
writer, err = NewCompressingResponseWriter(httpWriter, encoding)
if err != nil {
log.Println("[restful] unable to install compressor:", err)
log.Print("[restful] unable to install compressor: ", err)
httpWriter.WriteHeader(http.StatusInternalServerError)
return
}

View File

@ -32,7 +32,7 @@ func (c CrossOriginResourceSharing) Filter(req *Request, resp *Response, chain *
origin := req.Request.Header.Get(HEADER_Origin)
if len(origin) == 0 {
if trace {
traceLogger.Println("no Http header Origin set")
traceLogger.Print("no Http header Origin set")
}
chain.ProcessFilter(req, resp)
return

View File

@ -165,10 +165,17 @@ If you expect to read large amounts of payload data, and you do not use this fea
Trouble shooting
This package has the means to produce detail logging of the complete Http request matching process and filter invocation.
Enabling this feature requires you to set a log.Logger instance such as:
Enabling this feature requires you to set an implementation of restful.StdLogger (e.g. log.Logger) instance such as:
restful.TraceLogger(log.New(os.Stdout, "[restful] ", log.LstdFlags|log.Lshortfile))
Logging
The restful.SetLogger() method allows you to override the logger used by the package. By default restful
uses the standard library `log` package and logs to stdout. Different logging packages are supported as
long as they conform to `StdLogger` interface defined in the `log` sub-package, writing an adapter for your
preferred package is simple.
Resources
[project]: https://github.com/emicklei/go-restful
@ -179,6 +186,6 @@ Resources
[showcases]: https://github.com/emicklei/mora, https://github.com/emicklei/landskape
(c) 2012-2014, http://ernestmicklei.com. MIT License
(c) 2012-2015, http://ernestmicklei.com. MIT License
*/
package restful

View File

@ -55,22 +55,22 @@ func (r RouterJSR311) detectRoute(routes []Route, httpRequest *http.Request) (*R
return nil, NewError(http.StatusMethodNotAllowed, "405: Method Not Allowed")
}
inputMediaOk := methodOk
// content-type
contentType := httpRequest.Header.Get(HEADER_ContentType)
if httpRequest.ContentLength > 0 {
inputMediaOk = []Route{}
for _, each := range methodOk {
if each.matchesContentType(contentType) {
inputMediaOk = append(inputMediaOk, each)
}
}
if len(inputMediaOk) == 0 {
if trace {
traceLogger.Printf("no Route found (from %d) that matches HTTP Content-Type: %s\n", len(methodOk), contentType)
}
return nil, NewError(http.StatusUnsupportedMediaType, "415: Unsupported Media Type")
inputMediaOk = []Route{}
for _, each := range methodOk {
if each.matchesContentType(contentType) {
inputMediaOk = append(inputMediaOk, each)
}
}
if len(inputMediaOk) == 0 {
if trace {
traceLogger.Printf("no Route found (from %d) that matches HTTP Content-Type: %s\n", len(methodOk), contentType)
}
return nil, NewError(http.StatusUnsupportedMediaType, "415: Unsupported Media Type")
}
// accept
outputMediaOk := []Route{}
accept := httpRequest.Header.Get(HEADER_Accept)

View File

@ -0,0 +1,31 @@
package log
import (
stdlog "log"
"os"
)
// Logger corresponds to a minimal subset of the interface satisfied by stdlib log.Logger
type StdLogger interface {
Print(v ...interface{})
Printf(format string, v ...interface{})
}
var Logger StdLogger
func init() {
// default Logger
SetLogger(stdlog.New(os.Stdout, "[restful] ", stdlog.LstdFlags|stdlog.Lshortfile))
}
func SetLogger(customLogger StdLogger) {
Logger = customLogger
}
func Print(v ...interface{}) {
Logger.Print(v...)
}
func Printf(format string, v ...interface{}) {
Logger.Printf(format, v...)
}

View File

@ -1,16 +1,32 @@
package restful
import "log"
// Copyright 2014 Ernest Micklei. All rights reserved.
// Use of this source code is governed by a license
// that can be found in the LICENSE file.
import (
"github.com/emicklei/go-restful/log"
)
var trace bool = false
var traceLogger *log.Logger
var traceLogger log.StdLogger
func init() {
traceLogger = log.Logger // use the package logger by default
}
// TraceLogger enables detailed logging of Http request matching and filter invocation. Default no logger is set.
func TraceLogger(logger *log.Logger) {
// You may call EnableTracing() directly to enable trace logging to the package-wide logger.
func TraceLogger(logger log.StdLogger) {
traceLogger = logger
trace = logger != nil
EnableTracing(logger != nil)
}
// expose the setter for the global logger on the top-level package
func SetLogger(customLogger log.StdLogger) {
log.SetLogger(customLogger)
}
// EnableTracing can be used to Trace logging on and off.
func EnableTracing(enabled bool) {
trace = enabled
}

View File

@ -88,8 +88,24 @@ func (r Route) matchesAccept(mimeTypesWithQuality string) bool {
return false
}
// Return whether the mimeType matches to what this Route can consume.
// Return whether this Route can consume content with a type specified by mimeTypes (can be empty).
func (r Route) matchesContentType(mimeTypes string) bool {
if len(r.Consumes) == 0 {
// did not specify what it can consume ; any media type (“*/*”) is assumed
return true
}
if len(mimeTypes) == 0 {
// idempotent methods with (most-likely or garanteed) empty content match missing Content-Type
m := r.Method
if m == "GET" || m == "HEAD" || m == "OPTIONS" || m == "DELETE" || m == "TRACE" {
return true
}
// proceed with default
mimeTypes = MIME_OCTET
}
parts := strings.Split(mimeTypes, ",")
for _, each := range parts {
var contentType string
@ -100,8 +116,8 @@ func (r Route) matchesContentType(mimeTypes string) bool {
}
// trim before compare
contentType = strings.Trim(contentType, " ")
for _, other := range r.Consumes {
if other == "*/*" || other == contentType {
for _, consumeableType := range r.Consumes {
if consumeableType == "*/*" || consumeableType == contentType {
return true
}
}

View File

@ -5,9 +5,12 @@ package restful
// that can be found in the LICENSE file.
import (
"log"
"os"
"reflect"
"runtime"
"strings"
"github.com/emicklei/go-restful/log"
)
// RouteBuilder is a helper to construct Routes.
@ -126,6 +129,7 @@ func (b *RouteBuilder) Param(parameter *Parameter) *RouteBuilder {
}
// Operation allows you to document what the acutal method/function call is of the Route.
// Unless called, the operation name is derived from the RouteFunction set using To(..).
func (b *RouteBuilder) Operation(name string) *RouteBuilder {
b.operation = name
return b
@ -133,7 +137,7 @@ func (b *RouteBuilder) Operation(name string) *RouteBuilder {
// ReturnsError is deprecated, use Returns instead.
func (b *RouteBuilder) ReturnsError(code int, message string, model interface{}) *RouteBuilder {
log.Println("ReturnsError is deprecated, use Returns instead.")
log.Print("ReturnsError is deprecated, use Returns instead.")
return b.Returns(code, message, model)
}
@ -186,10 +190,17 @@ func (b *RouteBuilder) copyDefaults(rootProduces, rootConsumes []string) {
func (b *RouteBuilder) Build() Route {
pathExpr, err := newPathExpression(b.currentPath)
if err != nil {
log.Fatalf("[restful] Invalid path:%s because:%v", b.currentPath, err)
log.Printf("[restful] Invalid path:%s because:%v", b.currentPath, err)
os.Exit(1)
}
if b.function == nil {
log.Fatalf("[restful] No function specified for route:" + b.currentPath)
log.Printf("[restful] No function specified for route:" + b.currentPath)
os.Exit(1)
}
operationName := b.operation
if len(operationName) == 0 && b.function != nil {
// extract from definition
operationName = nameOfFunction(b.function)
}
route := Route{
Method: b.httpMethod,
@ -202,7 +213,7 @@ func (b *RouteBuilder) Build() Route {
pathExpr: pathExpr,
Doc: b.doc,
Notes: b.notes,
Operation: b.operation,
Operation: operationName,
ParameterDocs: b.parameters,
ResponseErrors: b.errorMap,
ReadSample: b.readSample,
@ -214,3 +225,16 @@ func (b *RouteBuilder) Build() Route {
func concatPath(path1, path2 string) string {
return strings.TrimRight(path1, "/") + "/" + strings.TrimLeft(path2, "/")
}
// nameOfFunction returns the short name of the function f for documentation.
// It uses a runtime feature for debugging ; its value may change for later Go versions.
func nameOfFunction(f interface{}) string {
fun := runtime.FuncForPC(reflect.ValueOf(f).Pointer())
tokenized := strings.Split(fun.Name(), ".")
last := tokenized[len(tokenized)-1]
last = strings.TrimSuffix(last, ")·fm") // < Go 1.5
last = strings.TrimSuffix(last, ")-fm") // Go 1.5
last = strings.TrimSuffix(last, "·fm") // < Go 1.5
last = strings.TrimSuffix(last, "-fm") // Go 1.5
return last
}

View File

@ -52,4 +52,7 @@ func TestRouteBuilder(t *testing.T) {
if r.Consumes[0] != json {
t.Error("consumes invalid")
}
if r.Operation != "dummy" {
t.Error("Operation not set")
}
}

View File

@ -1,5 +1,9 @@
Change history of swagger
=
2015-03-17
- preserve order of Routes per WebService in Swagger listing
- fix use of $ref and type in Swagger models
- add api version to listing
2014-11-14
- operation parameters are now sorted using ordering path,query,form,header,body

View File

@ -6,6 +6,9 @@ import (
"github.com/emicklei/go-restful"
)
// PostBuildDeclarationMapFunc can be used to modify the api declaration map.
type PostBuildDeclarationMapFunc func(apiDeclarationMap map[string]ApiDeclaration)
type Config struct {
// url where the services are available, e.g. http://localhost:8080
// if left empty then the basePath of Swagger is taken from the actual request
@ -24,4 +27,6 @@ type Config struct {
DisableCORS bool
// Top-level API version. Is reflected in the resource listing.
ApiVersion string
// If set then call this handler after building the complete ApiDeclaration Map
PostBuildHandler PostBuildDeclarationMapFunc
}

View File

@ -78,45 +78,48 @@ func (b modelBuilder) buildProperty(field reflect.StructField, model *Model, mod
return "", prop
}
fieldType := field.Type
fieldKind := fieldType.Kind()
if jsonTag := field.Tag.Get("json"); jsonTag != "" {
s := strings.Split(jsonTag, ",")
if len(s) > 1 && s[1] == "string" {
fieldType = reflect.TypeOf("")
}
}
var pType = b.jsonSchemaType(fieldType.String()) // may include pkg path
prop.Type = &pType
if b.isPrimitiveType(fieldType.String()) {
prop.Format = b.jsonSchemaFormat(fieldType.String())
return jsonName, prop
}
// check if type is doing its own marshalling
marshalerType := reflect.TypeOf((*json.Marshaler)(nil)).Elem()
if fieldType.Implements(marshalerType) {
var pType = "string"
prop.Type = &pType
prop.Format = b.jsonSchemaFormat(fieldType.String())
return jsonName, prop
}
if fieldKind == reflect.Struct {
// check if annotation says it is a string
if jsonTag := field.Tag.Get("json"); jsonTag != "" {
s := strings.Split(jsonTag, ",")
if len(s) > 1 && s[1] == "string" {
stringt := "string"
prop.Type = &stringt
return jsonName, prop
}
}
fieldKind := fieldType.Kind()
switch {
case fieldKind == reflect.Struct:
return b.buildStructTypeProperty(field, jsonName, model)
}
if fieldKind == reflect.Slice || fieldKind == reflect.Array {
case fieldKind == reflect.Slice || fieldKind == reflect.Array:
return b.buildArrayTypeProperty(field, jsonName, modelName)
}
if fieldKind == reflect.Ptr {
case fieldKind == reflect.Ptr:
return b.buildPointerTypeProperty(field, jsonName, modelName)
}
if b.isPrimitiveType(fieldType.String()) {
mapped := b.jsonSchemaType(fieldType.String())
prop.Type = &mapped
prop.Format = b.jsonSchemaFormat(fieldType.String())
return jsonName, prop
}
modelType := fieldType.String()
prop.Ref = &modelType
if fieldType.Name() == "" { // override type of anonymous structs
nestedTypeName := modelName + "." + jsonName
var pType = nestedTypeName
prop.Type = &pType
prop.Ref = &nestedTypeName
b.addModel(fieldType, nestedTypeName)
}
return jsonName, prop
@ -129,7 +132,7 @@ func (b modelBuilder) buildStructTypeProperty(field reflect.StructField, jsonNam
// anonymous
anonType := model.Id + "." + jsonName
b.addModel(fieldType, anonType)
prop.Type = &anonType
prop.Ref = &anonType
return jsonName, prop
}
if field.Name == fieldType.Name() && field.Anonymous {
@ -159,7 +162,7 @@ func (b modelBuilder) buildStructTypeProperty(field reflect.StructField, jsonNam
// simple struct
b.addModel(fieldType, "")
var pType = fieldType.String()
prop.Type = &pType
prop.Ref = &pType
return jsonName, prop
}
@ -167,13 +170,19 @@ func (b modelBuilder) buildArrayTypeProperty(field reflect.StructField, jsonName
fieldType := field.Type
var pType = "array"
prop.Type = &pType
elemName := b.getElementTypeName(modelName, jsonName, fieldType.Elem())
prop.Items = &Item{Ref: &elemName}
elemTypeName := b.getElementTypeName(modelName, jsonName, fieldType.Elem())
prop.Items = new(Item)
if b.isPrimitiveType(elemTypeName) {
mapped := b.jsonSchemaType(elemTypeName)
prop.Items.Type = &mapped
} else {
prop.Items.Ref = &elemTypeName
}
// add|overwrite model for element type
if fieldType.Elem().Kind() == reflect.Ptr {
fieldType = fieldType.Elem()
}
b.addModel(fieldType.Elem(), elemName)
b.addModel(fieldType.Elem(), elemTypeName)
return jsonName, prop
}
@ -191,11 +200,11 @@ func (b modelBuilder) buildPointerTypeProperty(field reflect.StructField, jsonNa
} else {
// non-array, pointer type
var pType = fieldType.String()[1:] // no star, include pkg path
prop.Type = &pType
prop.Ref = &pType
elemName := ""
if fieldType.Elem().Name() == "" {
elemName = modelName + "." + jsonName
prop.Type = &elemName
prop.Ref = &elemName
}
b.addModel(fieldType.Elem(), elemName)
}

View File

@ -14,6 +14,29 @@ func (y YesNo) MarshalJSON() ([]byte, error) {
return []byte("no"), nil
}
// clear && go test -v -test.run TestRef_Issue190 ...swagger
func TestRef_Issue190(t *testing.T) {
type User struct {
items []string
}
testJsonFromStruct(t, User{}, `{
"swagger.User": {
"id": "swagger.User",
"required": [
"items"
],
"properties": {
"items": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
}`)
}
// clear && go test -v -test.run TestCustomMarshaller_Issue96 ...swagger
func TestCustomMarshaller_Issue96(t *testing.T) {
type Vote struct {
@ -96,7 +119,7 @@ func TestS2(t *testing.T) {
"Ids": {
"type": "array",
"items": {
"$ref": "string"
"type": "string"
}
}
}
@ -131,7 +154,7 @@ func TestS3(t *testing.T) {
],
"properties": {
"Nested": {
"type": "swagger.NestedS3"
"$ref": "swagger.NestedS3"
}
}
}
@ -180,7 +203,7 @@ func TestSampleToModelAsJson(t *testing.T) {
}
},
"root": {
"type": "swagger.item",
"$ref": "swagger.item",
"description": "root desc"
}
}
@ -284,7 +307,7 @@ func TestAnonymousStruct(t *testing.T) {
],
"properties": {
"A": {
"type": "swagger.X.A"
"$ref": "swagger.X.A"
}
}
},
@ -320,7 +343,7 @@ func TestAnonymousPtrStruct(t *testing.T) {
],
"properties": {
"A": {
"type": "swagger.X.A"
"$ref": "swagger.X.A"
}
}
},
@ -474,7 +497,7 @@ func TestIssue85(t *testing.T) {
"Names": {
"type": "array",
"items": {
"$ref": "string"
"type": "string"
}
}
}
@ -531,7 +554,7 @@ func TestEmbeddedStructA1(t *testing.T) {
],
"properties": {
"B": {
"type": "swagger.A1.B"
"$ref": "swagger.A1.B"
}
}
},
@ -605,7 +628,7 @@ func TestStructA3(t *testing.T) {
],
"properties": {
"B": {
"type": "swagger.D"
"$ref": "swagger.D"
}
}
},
@ -695,7 +718,7 @@ func TestIssue158(t *testing.T) {
],
"properties": {
"address": {
"type": "swagger.Address"
"$ref": "swagger.Address"
},
"name": {
"type": "string"

View File

@ -23,9 +23,11 @@ func TestServiceToApi(t *testing.T) {
ws.Route(ws.DELETE("/a").To(dummy).Writes(sample{}))
ws.ApiVersion("1.2.3")
cfg := Config{
WebServicesUrl: "http://here.com",
ApiPath: "/apipath",
WebServices: []*restful.WebService{ws}}
WebServicesUrl: "http://here.com",
ApiPath: "/apipath",
WebServices: []*restful.WebService{ws},
PostBuildHandler: func(in map[string]ApiDeclaration) {},
}
sws := newSwaggerService(cfg)
decl := sws.composeDeclaration(ws, "/tests")
// checks

View File

@ -5,11 +5,12 @@ import (
"github.com/emicklei/go-restful"
// "github.com/emicklei/hopwatch"
"log"
"net/http"
"reflect"
"sort"
"strings"
"github.com/emicklei/go-restful/log"
)
type SwaggerService struct {
@ -24,7 +25,10 @@ func newSwaggerService(config Config) *SwaggerService {
}
// LogInfo is the function that is called when this package needs to log. It defaults to log.Printf
var LogInfo = log.Printf
var LogInfo = func(format string, v ...interface{}) {
// use the restful package-wide logger
log.Printf(format, v...)
}
// InstallSwaggerService add the WebService that provides the API documentation of all services
// conform the Swagger documentation specifcation. (https://github.com/wordnik/swagger-core/wiki).
@ -73,6 +77,11 @@ func RegisterSwaggerService(config Config, wsContainer *restful.Container) {
}
}
// if specified then call the PostBuilderHandler
if config.PostBuildHandler != nil {
config.PostBuildHandler(sws.apiDeclarationMap)
}
// Check paths for UI serving
if config.StaticHandler == nil && config.SwaggerFilePath != "" && config.SwaggerPath != "" {
swaggerPathSlash := config.SwaggerPath

View File

@ -32,6 +32,8 @@ func compareJson(t *testing.T, actualJsonAsString string, expectedJsonAsString s
fmt.Println(withLineNumbers(expectedJsonAsString))
fmt.Println("---- actual -----")
fmt.Println(withLineNumbers(actualJsonAsString))
fmt.Println("---- raw -----")
fmt.Println(actualJsonAsString)
t.Error("there are differences")
return false
}

View File

@ -1,11 +1,15 @@
package restful
import (
"os"
"github.com/emicklei/go-restful/log"
)
// Copyright 2013 Ernest Micklei. All rights reserved.
// Use of this source code is governed by a license
// that can be found in the LICENSE file.
import "log"
// WebService holds a collection of Route values that bind a Http Method + URL Path to a function.
type WebService struct {
rootPath string
@ -26,7 +30,8 @@ func (w *WebService) compilePathExpression() {
}
compiled, err := newPathExpression(w.rootPath)
if err != nil {
log.Fatalf("[restful] invalid path:%s because:%v", w.rootPath, err)
log.Printf("[restful] invalid path:%s because:%v", w.rootPath, err)
os.Exit(1)
}
w.pathExpr = compiled
}

View File

@ -85,6 +85,50 @@ func TestSelectedRoutePath_Issue100(t *testing.T) {
}
}
func TestContentType415_Issue170(t *testing.T) {
tearDown()
Add(newGetOnlyJsonOnlyService())
httpRequest, _ := http.NewRequest("GET", "http://here.com/get", nil)
httpWriter := httptest.NewRecorder()
DefaultContainer.dispatch(httpWriter, httpRequest)
if 200 != httpWriter.Code {
t.Errorf("Expected 200, got %d", httpWriter.Code)
}
}
func TestContentType415_POST_Issue170(t *testing.T) {
tearDown()
Add(newPostOnlyJsonOnlyService())
httpRequest, _ := http.NewRequest("POST", "http://here.com/post", nil)
httpRequest.Header.Set("Content-Type", "application/json")
httpWriter := httptest.NewRecorder()
DefaultContainer.dispatch(httpWriter, httpRequest)
if 200 != httpWriter.Code {
t.Errorf("Expected 200, got %d", httpWriter.Code)
}
}
// go test -v -test.run TestContentTypeOctet_Issue170 ...restful
func TestContentTypeOctet_Issue170(t *testing.T) {
tearDown()
Add(newGetConsumingOctetStreamService())
// with content-type
httpRequest, _ := http.NewRequest("GET", "http://here.com/get", nil)
httpRequest.Header.Set("Content-Type", MIME_OCTET)
httpWriter := httptest.NewRecorder()
DefaultContainer.dispatch(httpWriter, httpRequest)
if 200 != httpWriter.Code {
t.Errorf("Expected 200, got %d", httpWriter.Code)
}
// without content-type
httpRequest, _ = http.NewRequest("GET", "http://here.com/get", nil)
httpWriter = httptest.NewRecorder()
DefaultContainer.dispatch(httpWriter, httpRequest)
if 200 != httpWriter.Code {
t.Errorf("Expected 200, got %d", httpWriter.Code)
}
}
func newPanicingService() *WebService {
ws := new(WebService).Path("")
ws.Route(ws.GET("/fire").To(doPanic))
@ -97,6 +141,27 @@ func newGetOnlyService() *WebService {
return ws
}
func newPostOnlyJsonOnlyService() *WebService {
ws := new(WebService).Path("")
ws.Consumes("application/json")
ws.Route(ws.POST("/post").To(doNothing))
return ws
}
func newGetOnlyJsonOnlyService() *WebService {
ws := new(WebService).Path("")
ws.Consumes("application/json")
ws.Route(ws.GET("/get").To(doNothing))
return ws
}
func newGetConsumingOctetStreamService() *WebService {
ws := new(WebService).Path("")
ws.Consumes("application/octet-stream")
ws.Route(ws.GET("/get").To(doNothing))
return ws
}
func newSelectedRouteTestingService() *WebService {
ws := new(WebService).Path("")
ws.Route(ws.GET(pathGetFriends).To(selectedRouteChecker))
@ -113,3 +178,6 @@ func doPanic(req *Request, resp *Response) {
println("lightning...")
panic("fire")
}
func doNothing(req *Request, resp *Response) {
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff