diff --git a/apisprout.go b/apisprout.go index 44fc633..ac60488 100644 --- a/apisprout.go +++ b/apisprout.go @@ -57,6 +57,7 @@ var ( type RefreshableRouter struct { router *openapi3filter.Router + uri string } func (rr *RefreshableRouter) Set(router *openapi3filter.Router) { @@ -167,10 +168,34 @@ func addParameter(flags *pflag.FlagSet, name, short string, def interface{}, des viper.BindPFlag(name, flags.Lookup(name)) } +func getTypedExampleValue(rr *RefreshableRouter, example *openapi3.ExampleRef) (interface{}, error) { + + if example == nil || example.Value == nil { + return nil, fmt.Errorf("nil example") + } + + if example.Value.ExternalValue != "" { + if strings.HasPrefix(example.Value.ExternalValue, "http") { + resp, err := http.Get(example.Value.ExternalValue) + if err != nil { + return nil, err + } + //noinspection GoUnhandledErrorResult + defer resp.Body.Close() + return ioutil.ReadAll(resp.Body) + } else if !strings.HasPrefix(rr.uri, "http") { + return ioutil.ReadFile(filepath.Join(filepath.Dir(rr.uri), example.Value.ExternalValue)) + } + return nil, fmt.Errorf("external value %q not supported for uri %q", example.Value.ExternalValue, rr.uri) + } + + return example.Value.Value, nil +} + // getTypedExample will return an example from a given media type, if such an // example exists. If multiple examples are given, then one is selected at // random unless an "example" item exists in the Prefer header -func getTypedExample(mt *openapi3.MediaType, prefer map[string]string) (interface{}, error) { +func getTypedExample(rr *RefreshableRouter, mt *openapi3.MediaType, prefer map[string]string) (interface{}, error) { if mt.Example != nil { return mt.Example, nil } @@ -181,7 +206,7 @@ func getTypedExample(mt *openapi3.MediaType, prefer map[string]string) (interfac if mapContainsKey(prefer, "example") { preferredExample = prefer["example"] if _, ok := mt.Examples[preferredExample]; ok { - return mt.Examples[preferredExample].Value.Value, nil + return getTypedExampleValue(rr, mt.Examples[preferredExample]) } } @@ -193,7 +218,7 @@ func getTypedExample(mt *openapi3.MediaType, prefer map[string]string) (interfac if len(keys) > 0 { selected := keys[rand.Intn(len(keys))] - return mt.Examples[selected].Value.Value, nil + return getTypedExampleValue(rr, mt.Examples[selected]) } } @@ -207,7 +232,7 @@ func getTypedExample(mt *openapi3.MediaType, prefer map[string]string) (interfac // getExample tries to return an example for a given operation. // Using the Prefer http header, the consumer can specify the type of response they want. -func getExample(negotiator *ContentNegotiator, prefer map[string]string, op *openapi3.Operation) (int, string, map[string]*openapi3.HeaderRef, interface{}, error) { +func getExample(rr *RefreshableRouter, negotiator *ContentNegotiator, prefer map[string]string, op *openapi3.Operation) (int, string, map[string]*openapi3.HeaderRef, interface{}, error) { var responses []string var blankHeaders = make(map[string]*openapi3.HeaderRef) @@ -257,7 +282,7 @@ func getExample(negotiator *ContentNegotiator, prefer map[string]string, op *ope continue } - example, err := getTypedExample(content, prefer) + example, err := getTypedExample(rr, content, prefer) if err == nil { return status, mt, response.Value.Headers, example, nil } @@ -532,7 +557,7 @@ var handler = func(rr *RefreshableRouter) http.Handler { prefer := parsePreferHeader(req.Header.Get("Prefer")) - status, mediatype, headers, example, err := getExample(negotiator, prefer, route.Operation) + status, mediatype, headers, example, err := getExample(rr, negotiator, prefer, route.Operation) if err != nil { log.Printf("%s => Missing example", info) w.WriteHeader(http.StatusTeapot) @@ -604,6 +629,7 @@ func server(cmd *cobra.Command, args []string) { rr := NewRefreshableRouter() uri := args[0] + rr.uri = uri var err error var data []byte