Repository: deepmap/oapi-codegen (go)

Issue:
Wrong (double) escape of parameters in url
Having an `id` parameter in url in the following schema:
```
  "/pool/dataset/id/{id}": {
   "get": {
    "tags": [
     "pool.dataset"
    ],
    "responses": {
     "200": {
      "$ref": "#/components/responses/Success"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     }
    },
    "parameters": [
     {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer"
      }
     },
     {
      "name": "offset",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer"
      }
     },
     {
      "name": "count",
      "in": "query",
      "required": false,
      "schema": {
       "type": "boolean"
      }
     },
     {
      "name": "sort",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
  },
```

Making a request with id=`main/ci/3519b2fe-429e-4712-81d8-41c83a03c704` ends in the following url: `/api/v2.0/pool/dataset/id/main%252Fci%252F3519b2fe-429e-4712-81d8-41c83a03c704`

Pull request:
Fix escaped url parsing
Fixes #380

Patch:
diff --git a/examples/petstore-expanded/petstore-client.gen.go b/examples/petstore-expanded/petstore-client.gen.go
index 7dd7eb0..40085ef 100644
--- a/examples/petstore-expanded/petstore-client.gen.go
+++ b/examples/petstore-expanded/petstore-client.gen.go
@@ -224,11 +224,12 @@ func NewFindPetsRequest(server string, params *FindPetsParams) (*http.Request, e
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	queryValues := queryURL.Query()
 
@@ -298,11 +299,12 @@ func NewAddPetRequestWithBody(server string, contentType string, body io.Reader)
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("POST", queryURL.String(), body)
 	if err != nil {
@@ -334,11 +336,12 @@ func NewDeletePetRequest(server string, id int64) (*http.Request, error) {
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("DELETE", queryURL.String(), nil)
 	if err != nil {
@@ -368,11 +371,12 @@ func NewFindPetByIDRequest(server string, id int64) (*http.Request, error) {
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
diff --git a/go.sum b/go.sum
index 4cdb220..466b0e0 100644
--- a/go.sum
+++ b/go.sum
@@ -17,6 +17,7 @@ github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tF
 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
 github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219 h1:utua3L2IbQJmauC5IXdEA547bcoU5dozgQAfc8Onsg4=
 github.com/golangci/lint-1 v0.0.0-20181222135242-d2cdd8c08219/go.mod h1:/X8TswGSh1pIozq4ZwCfxS0WA5JGXguxk94ar/4c87Y=
+github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
 github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
 github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
diff --git a/pkg/chi-middleware/oapi_validate.go b/pkg/chi-middleware/oapi_validate.go
index d7db5c1..d9e8306 100644
--- a/pkg/chi-middleware/oapi_validate.go
+++ b/pkg/chi-middleware/oapi_validate.go
@@ -12,7 +12,7 @@ import (
 	"github.com/getkin/kin-openapi/openapi3"
 	"github.com/getkin/kin-openapi/openapi3filter"
 	"github.com/getkin/kin-openapi/routers"
-	"github.com/getkin/kin-openapi/routers/legacy"
+	"github.com/getkin/kin-openapi/routers/gorillamux"
 )
 
 // Options to customize request validation, openapi3filter specified options will be passed through.
@@ -29,7 +29,7 @@ func OapiRequestValidator(swagger *openapi3.T) func(next http.Handler) http.Hand
 // OapiRequestValidatorWithOptions Creates middleware to validate request by swagger spec.
 // This middleware is good for net/http either since go-chi is 100% compatible with net/http.
 func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) func(next http.Handler) http.Handler {
-	router, err := legacy.NewRouter(swagger)
+	router, err := gorillamux.NewRouter(swagger)
 	if err != nil {
 		panic(err)
 	}
diff --git a/pkg/codegen/templates/client.tmpl b/pkg/codegen/templates/client.tmpl
index e649c14..fc55283 100644
--- a/pkg/codegen/templates/client.tmpl
+++ b/pkg/codegen/templates/client.tmpl
@@ -169,11 +169,12 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
     if operationPath[0] == '/' {
         operationPath = operationPath[1:]
     }
-    operationURL := url.URL{
-    	Path: operationPath,
+    operationURL, err := url.Parse(operationPath)
+    if err != nil {
+        return nil, err
     }
 
-    queryURL := serverURL.ResolveReference(&operationURL)
+    queryURL := serverURL.ResolveReference(operationURL)
 
 {{if .QueryParams}}
     queryValues := queryURL.Query()
diff --git a/pkg/codegen/templates/templates.gen.go b/pkg/codegen/templates/templates.gen.go
index f84945a..f3c9ce2 100644
--- a/pkg/codegen/templates/templates.gen.go
+++ b/pkg/codegen/templates/templates.gen.go
@@ -594,11 +594,12 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
     if operationPath[0] == '/' {
         operationPath = operationPath[1:]
     }
-    operationURL := url.URL{
-    	Path: operationPath,
+    operationURL, err := url.Parse(operationPath)
+    if err != nil {
+        return nil, err
     }
 
-    queryURL := serverURL.ResolveReference(&operationURL)
+    queryURL := serverURL.ResolveReference(operationURL)
 
 {{if .QueryParams}}
     queryValues := queryURL.Query()
diff --git a/pkg/middleware/oapi_validate.go b/pkg/middleware/oapi_validate.go
index cbed69a..01ceac5 100644
--- a/pkg/middleware/oapi_validate.go
+++ b/pkg/middleware/oapi_validate.go
@@ -24,7 +24,7 @@ import (
 	"github.com/getkin/kin-openapi/openapi3"
 	"github.com/getkin/kin-openapi/openapi3filter"
 	"github.com/getkin/kin-openapi/routers"
-	"github.com/getkin/kin-openapi/routers/legacy"
+	"github.com/getkin/kin-openapi/routers/gorillamux"
 	"github.com/labstack/echo/v4"
 	echomiddleware "github.com/labstack/echo/v4/middleware"
 )
@@ -67,7 +67,7 @@ type Options struct {
 
 // Create a validator from a swagger object, with validation options
 func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) echo.MiddlewareFunc {
-	router, err := legacy.NewRouter(swagger)
+	router, err := gorillamux.NewRouter(swagger)
 	if err != nil {
 		panic(err)
 	}


Test patch:
diff --git a/internal/test/client/client.gen.go b/internal/test/client/client.gen.go
index 8cb1f2b..b83a230 100644
--- a/internal/test/client/client.gen.go
+++ b/internal/test/client/client.gen.go
@@ -274,11 +274,12 @@ func NewPostBothRequestWithBody(server string, contentType string, body io.Reade
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("POST", queryURL.String(), body)
 	if err != nil {
@@ -303,11 +304,12 @@ func NewGetBothRequest(server string) (*http.Request, error) {
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -341,11 +343,12 @@ func NewPostJsonRequestWithBody(server string, contentType string, body io.Reade
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("POST", queryURL.String(), body)
 	if err != nil {
@@ -370,11 +373,12 @@ func NewGetJsonRequest(server string) (*http.Request, error) {
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -397,11 +401,12 @@ func NewPostOtherRequestWithBody(server string, contentType string, body io.Read
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("POST", queryURL.String(), body)
 	if err != nil {
@@ -426,11 +431,12 @@ func NewGetOtherRequest(server string) (*http.Request, error) {
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -453,11 +459,12 @@ func NewGetJsonWithTrailingSlashRequest(server string) (*http.Request, error) {
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go
index 3aa31bb..60a1888 100644
--- a/internal/test/components/components.gen.go
+++ b/internal/test/components/components.gen.go
@@ -892,11 +892,12 @@ func NewEnsureEverythingIsReferencedRequestWithBody(server string, contentType s
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), body)
 	if err != nil {
@@ -921,11 +922,12 @@ func NewParamsWithAddPropsRequest(server string, params *ParamsWithAddPropsParam
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	queryValues := queryURL.Query()
 
@@ -987,11 +989,12 @@ func NewBodyWithAddPropsRequestWithBody(server string, contentType string, body
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("POST", queryURL.String(), body)
 	if err != nil {
diff --git a/internal/test/issues/issue-312/issue.gen.go b/internal/test/issues/issue-312/issue.gen.go
index e8c0604..e997862 100644
--- a/internal/test/issues/issue-312/issue.gen.go
+++ b/internal/test/issues/issue-312/issue.gen.go
@@ -190,11 +190,12 @@ func NewGetPetRequest(server string, petId string) (*http.Request, error) {
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -228,11 +229,12 @@ func NewValidatePetsRequestWithBody(server string, contentType string, body io.R
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("POST", queryURL.String(), body)
 	if err != nil {
diff --git a/internal/test/issues/issue-52/issue.gen.go b/internal/test/issues/issue-52/issue.gen.go
index 1a40027..e3328d9 100644
--- a/internal/test/issues/issue-52/issue.gen.go
+++ b/internal/test/issues/issue-52/issue.gen.go
@@ -195,11 +195,12 @@ func NewExampleGetRequest(server string) (*http.Request, error) {
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
diff --git a/internal/test/issues/issue-grab_import_names/issue.gen.go b/internal/test/issues/issue-grab_import_names/issue.gen.go
index dca6350..5bee48f 100644
--- a/internal/test/issues/issue-grab_import_names/issue.gen.go
+++ b/internal/test/issues/issue-grab_import_names/issue.gen.go
@@ -133,11 +133,12 @@ func NewGetFooRequest(server string, params *GetFooParams) (*http.Request, error
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
diff --git a/internal/test/issues/issue-illegal_enum_names/issue.gen.go b/internal/test/issues/issue-illegal_enum_names/issue.gen.go
index 768ff63..d23988f 100644
--- a/internal/test/issues/issue-illegal_enum_names/issue.gen.go
+++ b/internal/test/issues/issue-illegal_enum_names/issue.gen.go
@@ -144,11 +144,12 @@ func NewGetFooRequest(server string) (*http.Request, error) {
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
diff --git a/internal/test/parameters/parameters.gen.go b/internal/test/parameters/parameters.gen.go
index 896539c..c63ff45 100644
--- a/internal/test/parameters/parameters.gen.go
+++ b/internal/test/parameters/parameters.gen.go
@@ -500,11 +500,12 @@ func NewGetContentObjectRequest(server string, param ComplexObject) (*http.Reque
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -527,11 +528,12 @@ func NewGetCookieRequest(server string, params *GetCookieParams) (*http.Request,
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -661,11 +663,12 @@ func NewGetHeaderRequest(server string, params *GetHeaderParams) (*http.Request,
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -774,11 +777,12 @@ func NewGetLabelExplodeArrayRequest(server string, param []int32) (*http.Request
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -808,11 +812,12 @@ func NewGetLabelExplodeObjectRequest(server string, param Object) (*http.Request
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -842,11 +847,12 @@ func NewGetLabelNoExplodeArrayRequest(server string, param []int32) (*http.Reque
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -876,11 +882,12 @@ func NewGetLabelNoExplodeObjectRequest(server string, param Object) (*http.Reque
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -910,11 +917,12 @@ func NewGetMatrixExplodeArrayRequest(server string, id []int32) (*http.Request,
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -944,11 +952,12 @@ func NewGetMatrixExplodeObjectRequest(server string, id Object) (*http.Request,
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -978,11 +987,12 @@ func NewGetMatrixNoExplodeArrayRequest(server string, id []int32) (*http.Request
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -1012,11 +1022,12 @@ func NewGetMatrixNoExplodeObjectRequest(server string, id Object) (*http.Request
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -1043,11 +1054,12 @@ func NewGetPassThroughRequest(server string, param string) (*http.Request, error
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -1070,11 +1082,12 @@ func NewGetDeepObjectRequest(server string, params *GetDeepObjectParams) (*http.
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	queryValues := queryURL.Query()
 
@@ -1113,11 +1126,12 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	queryValues := queryURL.Query()
 
@@ -1273,11 +1287,12 @@ func NewGetSimpleExplodeArrayRequest(server string, param []int32) (*http.Reques
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -1307,11 +1322,12 @@ func NewGetSimpleExplodeObjectRequest(server string, param Object) (*http.Reques
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -1341,11 +1357,12 @@ func NewGetSimpleNoExplodeArrayRequest(server string, param []int32) (*http.Requ
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -1375,11 +1392,12 @@ func NewGetSimpleNoExplodeObjectRequest(server string, param Object) (*http.Requ
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -1409,11 +1427,12 @@ func NewGetSimplePrimitiveRequest(server string, param int32) (*http.Request, er
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go
index df91186..a948bf9 100644
--- a/internal/test/schemas/schemas.gen.go
+++ b/internal/test/schemas/schemas.gen.go
@@ -294,11 +294,12 @@ func NewEnsureEverythingIsReferencedRequest(server string) (*http.Request, error
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -321,11 +322,12 @@ func NewIssue127Request(server string) (*http.Request, error) {
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -359,11 +361,12 @@ func NewIssue185RequestWithBody(server string, contentType string, body io.Reade
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), body)
 	if err != nil {
@@ -395,11 +398,12 @@ func NewIssue209Request(server string, str StringInPath) (*http.Request, error)
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -429,11 +433,12 @@ func NewIssue30Request(server string, pFallthrough string) (*http.Request, error
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -463,11 +468,12 @@ func NewIssue41Request(server string, n1param N5StartsWithNumber) (*http.Request
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	req, err := http.NewRequest("GET", queryURL.String(), nil)
 	if err != nil {
@@ -501,11 +507,12 @@ func NewIssue9RequestWithBody(server string, params *Issue9Params, contentType s
 	if operationPath[0] == '/' {
 		operationPath = operationPath[1:]
 	}
-	operationURL := url.URL{
-		Path: operationPath,
+	operationURL, err := url.Parse(operationPath)
+	if err != nil {
+		return nil, err
 	}
 
-	queryURL := serverURL.ResolveReference(&operationURL)
+	queryURL := serverURL.ResolveReference(operationURL)
 
 	queryValues := queryURL.Query()
 
diff --git a/pkg/chi-middleware/oapi_validate_test.go b/pkg/chi-middleware/oapi_validate_test.go
index 6e2c10f..b67d5f3 100644
--- a/pkg/chi-middleware/oapi_validate_test.go
+++ b/pkg/chi-middleware/oapi_validate_test.go
@@ -5,6 +5,7 @@ import (
 	"errors"
 	"net/http"
 	"net/http/httptest"
+	"net/url"
 	"testing"
 
 	"github.com/deepmap/oapi-codegen/pkg/testutil"
@@ -20,7 +21,7 @@ info:
   version: 1.0.0
   title: TestServer
 servers:
-  - url: http://deepmap.ai
+  - url: http://deepmap.ai/
 paths:
   /resource:
     get:
@@ -91,13 +92,23 @@ components:
       bearerFormat: JWT
 `
 
-func doGet(t *testing.T, mux *chi.Mux, url string) *httptest.ResponseRecorder {
-	response := testutil.NewRequest().Get(url).WithAcceptJson().GoWithHTTPHandler(t, mux)
+func doGet(t *testing.T, mux *chi.Mux, rawURL string) *httptest.ResponseRecorder {
+	u, err := url.Parse(rawURL)
+	if err != nil {
+		t.Fatalf("Invalid url: %s", rawURL)
+	}
+
+	response := testutil.NewRequest().Get(u.RequestURI()).WithHost(u.Host).WithAcceptJson().GoWithHTTPHandler(t, mux)
 	return response.Recorder
 }
 
-func doPost(t *testing.T, mux *chi.Mux, url string, jsonBody interface{}) *httptest.ResponseRecorder {
-	response := testutil.NewRequest().Post(url).WithJsonBody(jsonBody).GoWithHTTPHandler(t, mux)
+func doPost(t *testing.T, mux *chi.Mux, rawURL string, jsonBody interface{}) *httptest.ResponseRecorder {
+	u, err := url.Parse(rawURL)
+	if err != nil {
+		t.Fatalf("Invalid url: %s", rawURL)
+	}
+
+	response := testutil.NewRequest().Post(u.RequestURI()).WithHost(u.Host).WithJsonBody(jsonBody).GoWithHTTPHandler(t, mux)
 	return response.Recorder
 }
 
diff --git a/pkg/middleware/oapi_validate_test.go b/pkg/middleware/oapi_validate_test.go
index f63793d..2f209f3 100644
--- a/pkg/middleware/oapi_validate_test.go
+++ b/pkg/middleware/oapi_validate_test.go
@@ -19,6 +19,7 @@ import (
 	"errors"
 	"net/http"
 	"net/http/httptest"
+	"net/url"
 	"testing"
 
 	"github.com/deepmap/oapi-codegen/pkg/testutil"
@@ -35,7 +36,7 @@ info:
   version: 1.0.0
   title: TestServer
 servers:
-  - url: http://deepmap.ai
+  - url: http://deepmap.ai/
 paths:
   /resource:
     get:
@@ -106,13 +107,23 @@ components:
       bearerFormat: JWT
 `
 
-func doGet(t *testing.T, e *echo.Echo, url string) *httptest.ResponseRecorder {
-	response := testutil.NewRequest().Get(url).WithAcceptJson().Go(t, e)
+func doGet(t *testing.T, e *echo.Echo, rawURL string) *httptest.ResponseRecorder {
+	u, err := url.Parse(rawURL)
+	if err != nil {
+		t.Fatalf("Invalid url: %s", rawURL)
+	}
+
+	response := testutil.NewRequest().Get(u.RequestURI()).WithHost(u.Host).WithAcceptJson().GoWithHTTPHandler(t, e)
 	return response.Recorder
 }
 
-func doPost(t *testing.T, e *echo.Echo, url string, jsonBody interface{}) *httptest.ResponseRecorder {
-	response := testutil.NewRequest().Post(url).WithJsonBody(jsonBody).Go(t, e)
+func doPost(t *testing.T, e *echo.Echo, rawURL string, jsonBody interface{}) *httptest.ResponseRecorder {
+	u, err := url.Parse(rawURL)
+	if err != nil {
+		t.Fatalf("Invalid url: %s", rawURL)
+	}
+
+	response := testutil.NewRequest().Post(u.RequestURI()).WithHost(u.Host).WithJsonBody(jsonBody).GoWithHTTPHandler(t, e)
 	return response.Recorder
 }
 
diff --git a/pkg/testutil/request_helpers.go b/pkg/testutil/request_helpers.go
index 22f7dab..3493827 100644
--- a/pkg/testutil/request_helpers.go
+++ b/pkg/testutil/request_helpers.go
@@ -85,6 +85,10 @@ func (r *RequestBuilder) WithHeader(header, value string) *RequestBuilder {
 	return r
 }
 
+func (r *RequestBuilder) WithHost(value string) *RequestBuilder {
+	return r.WithHeader("Host", value)
+}
+
 func (r *RequestBuilder) WithContentType(value string) *RequestBuilder {
 	return r.WithHeader("Content-Type", value)
 }
@@ -146,6 +150,9 @@ func (r *RequestBuilder) GoWithHTTPHandler(t *testing.T, handler http.Handler) *
 	for h, v := range r.Headers {
 		req.Header.Add(h, v)
 	}
+	if host, ok := r.Headers["Host"]; ok {
+		req.Host = host
+	}
 	for _, c := range r.Cookies {
 		req.AddCookie(c)
 	}