Skip to content

Commit 44dcad0

Browse files
authored
Merge pull request #658 from marle3003/develop
fix: resolve HTTP parameter when API uses a server URL with base path
2 parents 78572f9 + 45812ff commit 44dcad0

File tree

4 files changed

+47
-8
lines changed

4 files changed

+47
-8
lines changed

providers/openapi/handler_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,26 @@ func TestResolveEndpoint(t *testing.T) {
6464
require.Equal(t, "application/json", rr.Header().Get("Content-Type"))
6565
},
6666
},
67+
{
68+
name: "base path with parameters",
69+
test: func(t *testing.T, h http.HandlerFunc, c *openapi.Config) {
70+
c.Servers[0].Url = "http://localhost/root"
71+
op := openapitest.NewOperation(
72+
openapitest.WithOperationParam("bar", true),
73+
openapitest.WithResponse(http.StatusOK,
74+
openapitest.WithContent("application/json",
75+
openapitest.NewContent()),
76+
),
77+
)
78+
openapitest.AppendPath("/foo/{bar}", c, openapitest.WithOperation("get", op))
79+
80+
r := httptest.NewRequest("get", "http://localhost/root/foo/bar", nil)
81+
r = r.WithContext(context.WithValue(r.Context(), "servicePath", "/root"))
82+
rr := httptest.NewRecorder()
83+
h(rr, r)
84+
require.Equal(t, http.StatusOK, rr.Code)
85+
},
86+
},
6787
{
6888
// there is no official specification for trailing slash. For ease of use, mokapi considers it equivalent
6989
name: "spec define suffix / but request does not",

providers/openapi/parameter/path.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,19 @@ func parsePath(param *Parameter, route string, r *http.Request) (*RequestParamet
4848
}
4949

5050
func findPathValue(p *Parameter, route string, r *http.Request) (string, error) {
51+
requestPath := r.URL.Path
52+
if len(requestPath) > 1 {
53+
requestPath = strings.TrimRight(requestPath, "/")
54+
}
55+
56+
servicePath, ok := r.Context().Value("servicePath").(string)
57+
if ok && servicePath != "/" {
58+
requestPath = strings.Replace(requestPath, servicePath, "", 1)
59+
if requestPath == "" {
60+
requestPath = "/"
61+
}
62+
}
63+
5164
// Find all {param} names
5265
re := regexp.MustCompile(`\{([^}]+)\}`)
5366
names := re.FindAllStringSubmatch(route, -1)
@@ -68,7 +81,7 @@ func findPathValue(p *Parameter, route string, r *http.Request) (string, error)
6881
return "", fmt.Errorf("path parameter %s not found in route %s", p.Name, route)
6982
}
7083

71-
match := re.FindStringSubmatch(r.URL.Path)
84+
match := re.FindStringSubmatch(requestPath)
7285
if match == nil {
7386
// path parameters are always required
7487
return "", fmt.Errorf("url does not match route")

providers/openapi/request_body.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@ package openapi
22

33
import (
44
"fmt"
5-
"gopkg.in/yaml.v3"
65
"io"
6+
"maps"
77
"mime/multipart"
88
"mokapi/config/dynamic"
99
"mokapi/media"
1010
"mokapi/providers/openapi/schema"
1111
"mokapi/schema/encoding"
1212
"mokapi/schema/json/parser"
1313
"net/http"
14+
"slices"
1415
"strings"
16+
17+
"gopkg.in/yaml.v3"
1518
)
1619

1720
var defaultContentType = media.ParseContentType("application/octet-stream")
@@ -58,7 +61,7 @@ func BodyFromRequest(r *http.Request, op *Operation) (body *Body, err error) {
5861
contentType := media.ParseContentType(r.Header.Get("content-type"))
5962
_, mt := getMedia(contentType, op.RequestBody.Value)
6063
if !contentType.IsEmpty() && mt == nil {
61-
return noMatch(r, contentType)
64+
return noMatch(r, contentType, op)
6265
}
6366

6467
var b *Body
@@ -78,12 +81,14 @@ func BodyFromRequest(r *http.Request, op *Operation) (body *Body, err error) {
7881
return b, err
7982
}
8083

81-
func noMatch(r *http.Request, contentType media.ContentType) (*Body, error) {
84+
func noMatch(r *http.Request, contentType media.ContentType, op *Operation) (*Body, error) {
8285
data, err := io.ReadAll(r.Body)
8386
if err != nil {
8487
return nil, fmt.Errorf("read request body failed: %w", err)
8588
}
86-
return &Body{Raw: string(data)}, fmt.Errorf("read request body failed: no matching content type for '%v' defined", contentType.String())
89+
supported := slices.Collect(maps.Keys(op.RequestBody.Value.Content))
90+
errHttp := newHttpErrorf(http.StatusUnsupportedMediaType, "Unsupported Content-Type: %s\nThis operation only accepts: %s\nPlease set the Content-Type header to one of the supported types.", contentType.String(), strings.Join(supported, ", "))
91+
return &Body{Raw: string(data)}, errHttp
8792
}
8893

8994
func readBodyDetectContentType(r *http.Request, op *Operation) (*Body, error) {

providers/openapi/request_body_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@ package openapi_test
33
import (
44
"encoding/json"
55
"fmt"
6-
"github.com/stretchr/testify/require"
7-
"gopkg.in/yaml.v3"
86
"mokapi/providers/openapi"
97
"mokapi/providers/openapi/openapitest"
108
"mokapi/providers/openapi/schema/schematest"
119
"net/http"
1210
"net/http/httptest"
1311
"strings"
1412
"testing"
13+
14+
"github.com/stretchr/testify/require"
15+
"gopkg.in/yaml.v3"
1516
)
1617

1718
type errReader int
@@ -263,7 +264,7 @@ func TestBodyFromRequest(t *testing.T) {
263264
return r
264265
},
265266
test: func(t *testing.T, result *openapi.Body, err error) {
266-
require.EqualError(t, err, "read request body failed: no matching content type for 'application/xml' defined")
267+
require.EqualError(t, err, "Unsupported Content-Type: application/xml\nThis operation only accepts: application/json\nPlease set the Content-Type header to one of the supported types.")
267268
require.Equal(t, "<root><foo>bar</foo></root>", result.Raw)
268269
},
269270
},

0 commit comments

Comments
 (0)