Repository: avenga/couper
Pull request #516 (2022-06-02 12:23:57)

No path in proxy or endpoint
Removed `path` attribute from `endpoint` (and `proxy`) block

---
<details>
    <summary>Reviewer checklist</summary>
    <ul>
        <li>Read PR description: a summary about the changes is required</li>
        <li>Changelog updated</li>
        <li>Documentation: docs/{Reference, Cli, ...}, Docker and cli help/usage</li>
        <li>Pulled branch, manually tested</li>
        <li>Verified requirements are met</li>
        <li>Reviewed the code</li>
        <li>Reviewed the related tests</li>
    </ul>
</details>



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d57ec096..b357c791 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -42,6 +42,7 @@ Unreleased changes are available as `avenga/couper:edge` container.
 * **Removed**
   * support for `beta_oidc` block (use [`oidc` block](./docs/REFERENCE.md#oidc-block) instead) ([#475](https://github.com/avenga/couper/pull/475))
   * support for `beta_oauth_authorization_url` and `beta_oauth_verifier` functions (use `oauth2_authorization_url` and `oauth2_verifier` [functions](./docs/REFERENCE.md#functions) instead) ([#475](https://github.com/avenga/couper/pull/475))
+  * `path` attribute from `endpoint` (and `proxy`) block; use `path` attribute in `backend` block instead ([#516](https://github.com/avenga/couper/pull/516))
 
 ---
 
diff --git a/config/backend.go b/config/backend.go
index 5e418e26..296f9f9b 100644
--- a/config/backend.go
+++ b/config/backend.go
@@ -48,6 +48,7 @@ func (b Backend) Inline() interface{} {
 		Hostname       string                    `hcl:"hostname,optional"`
 		LogFields      map[string]hcl.Expression `hcl:"custom_log_fields,optional"`
 		Origin         string                    `hcl:"origin,optional"`
+		Path           string                    `hcl:"path,optional"`
 		PathPrefix     string                    `hcl:"path_prefix,optional"`
 		ProxyURL       string                    `hcl:"proxy,optional"`
 		ResponseStatus *uint8                    `hcl:"set_response_status,optional"`
diff --git a/config/configload/schema.go b/config/configload/schema.go
index e21e0dde..aed42c5f 100644
--- a/config/configload/schema.go
+++ b/config/configload/schema.go
@@ -30,6 +30,7 @@ var (
 
 func ValidateConfigSchema(body hcl.Body, obj interface{}) hcl.Diagnostics {
 	attrs, blocks, diags := getSchemaComponents(body, obj)
+	diags = enhanceErrors(diags, obj)
 	diags = filterValidErrors(attrs, blocks, diags)
 
 	for _, block := range blocks {
@@ -39,6 +40,20 @@ func ValidateConfigSchema(body hcl.Body, obj interface{}) hcl.Diagnostics {
 	return uniqueErrors(diags)
 }
 
+// enhanceErrors enhances diagnostics e.g. by providing a hint how to solve the issue
+func enhanceErrors(diags hcl.Diagnostics, obj interface{}) hcl.Diagnostics {
+	_, isEndpoint := obj.(*config.Endpoint)
+	_, isProxy := obj.(*config.Proxy)
+	for _, err := range diags {
+		if err.Summary == summUnsupportedAttr && (isEndpoint || isProxy) {
+			if matches := reFetchUnexpectedArg.FindStringSubmatch(err.Detail); matches != nil && matches[1] == `"path"` {
+				err.Detail = err.Detail + ` Use the "path" attribute in a backend block instead.`
+			}
+		}
+	}
+	return diags
+}
+
 // filterValidErrors ignores certain schema related errors due to their specific non hcl conform implementation.
 // Related attributes and blocks will be logic checked with LoadConfig.
 // TODO: Improve checkObjectFields to remove this filter requirement. E.g. optional label struct tag
diff --git a/config/meta/attributes.go b/config/meta/attributes.go
index 305e09e8..eda70150 100644
--- a/config/meta/attributes.go
+++ b/config/meta/attributes.go
@@ -29,9 +29,6 @@ type Attributes struct {
 	AddResponseHeaders map[string]string `hcl:"add_response_headers,optional"`
 	DelResponseHeaders []string          `hcl:"remove_response_headers,optional"`
 	SetResponseHeaders map[string]string `hcl:"set_response_headers,optional"`
-
-	// Other
-	Path string `hcl:"path,optional"`
 }
 
 func SchemaWithAttributes(schema *hcl.BodySchema) *hcl.BodySchema {
diff --git a/docs/README.md b/docs/README.md
index 717fc315..9cec8e6b 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -222,11 +222,11 @@ Couper's main concept is exposing APIs via the configuration block `endpoint`, f
 server "example"{
 
   endpoint "/public/**"{
-    path = "/**"
 
     proxy {
       backend {
         origin = "https://httpbin.org"
+        path = "/**"
       }
     }
   }
@@ -247,11 +247,11 @@ server "example" {
 
   endpoint "/private/**" {
     access_control = ["accessToken"]
-    path = "/**"
 
     proxy {
       backend {
         origin = "https://httpbin.org"
+        path = "/**"
       }
     }
   }
@@ -283,9 +283,8 @@ api "my_api" {
   }
 
   endpoint "/cart/**" {
-    path = "/api/v1/**"
     proxy {
-      url = "http://cartservice:8080"
+      url = "http://cartservice:8080/api/v1/**"
     }
   }
 
diff --git a/docs/REFERENCE.md b/docs/REFERENCE.md
index 6d5af8c4..bbbc00ee 100644
--- a/docs/REFERENCE.md
+++ b/docs/REFERENCE.md
@@ -127,9 +127,7 @@ as JSON error with an error body payload. This can be customized via `error_file
 ### Endpoint Block
 
 `endpoint` blocks define the entry points of Couper. The required _label_
-defines the path suffix for the incoming client request. The `path` attribute
-changes the path for the outgoing request (compare
-[path mapping example](README.md#routing-path-mapping)). Each `endpoint` block must
+defines the path suffix for the incoming client request. Each `endpoint` block must
 produce an explicit or implicit client response.
 
 | Block name | Context                                                | Label                                                                  | Nested block(s)                                                                                                                                                      |
@@ -141,7 +139,6 @@ produce an explicit or implicit client response.
 | Attribute(s)            | Type             | Default | Description                                                                                                       | Characteristic(s)                                                                                                                                                                                                                                                                                                                                                                                                                               | Example                                                              |
 |:------------------------|:-----------------|:--------|:------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------|
 | `request_body_limit`    | string           | `"64MiB"` | Configures the maximum buffer size while accessing `request.form_body` or `request.json_body` content.          | &#9888; Valid units are: `KiB, MiB, GiB`                                                                                                                                                                                                                                                                                                                                                                                                        | `request_body_limit = "200KiB"`                                      |
-| `path`                  | string           | -       | Changeable part of the upstream URL. Changes the path suffix of the outgoing request.                             | -                                                                                                                                                                                                                                                                                                                                                                                                                                               | -                                                                    |
 | `access_control`        | tuple (string)   | -       | Sets predefined [Access Control](#access-control) for `endpoint` block context.                                   | -                                                                                                                                                                                                                                                                                                                                                                                                                                               | `access_control = ["foo"]`                                           |
 | `disable_access_control` | tuple (string)  | -       | Disables access controls by name.                                                                                 | -                                                                                                                                                                                                                                                                                                                                                                                                                                               | `disable_access_control = ["foo"]`                                   |
 | `allowed_methods`       | tuple (string)  | `["*"]` == `["GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]` | Sets allowed methods _overriding_ a default set in the containing `api` block. Requests with a method that is not allowed result in an error response with a `405 Method Not Allowed` status. | The default value `"*"` can be combined with additional methods. Methods are matched case-insensitively. `Access-Control-Allow-Methods` is only sent in response to a [CORS](#cors-block) preflight request, if the method requested by `Access-Control-Request-Method` is an allowed method.      | `allowed_methods = ["GET", "POST"]` or `allowed_methods = ["*", "BREW"]` |
diff --git a/eval/http.go b/eval/http.go
index 61a6664d..d8835d9f 100644
--- a/eval/http.go
+++ b/eval/http.go
@@ -100,6 +100,14 @@ func SetBody(req *http.Request, body []byte) {
 	parseForm(req)
 }
 
+func getPathAttribute(body hcl.Body) (*hcl.Attribute, error) {
+	bodyContent, _, diags := body.PartialContent(config.BackendInlineSchema)
+	if diags.HasErrors() {
+		return nil, errors.Evaluation.With(diags)
+	}
+	return bodyContent.Attributes[attrPath], nil
+}
+
 func ApplyRequestContext(httpCtx *hcl.EvalContext, body hcl.Body, req *http.Request) error {
 	if req == nil {
 		return nil
@@ -107,12 +115,19 @@ func ApplyRequestContext(httpCtx *hcl.EvalContext, body hcl.Body, req *http.Requ
 
 	headerCtx := req.Header
 
-	attrs, err := getAllAttributes(body)
+	pathAttr, err := getPathAttribute(body)
 	if err != nil {
 		return err
 	}
 
-	if err = evalPathAttr(req, attrs, httpCtx); err != nil {
+	if pathAttr != nil {
+		if err = evalPathAttr(req, pathAttr, httpCtx); err != nil {
+			return err
+		}
+	}
+
+	attrs, err := getAllAttributes(body)
+	if err != nil {
 		return err
 	}
 
@@ -264,9 +279,8 @@ func getFormParams(ctx *hcl.EvalContext, req *http.Request, attrs map[string]*hc
 	return nil
 }
 
-func evalPathAttr(req *http.Request, attrs map[string]*hcl.Attribute, httpCtx *hcl.EvalContext) error {
-	pathAttr, ok := attrs[attrPath]
-	if !ok {
+func evalPathAttr(req *http.Request, pathAttr *hcl.Attribute, httpCtx *hcl.EvalContext) error {
+	if pathAttr == nil {
 		return nil
 	}
 	path := req.URL.Path


Test patch:
diff --git a/config/configload/validate_test.go b/config/configload/validate_test.go
index f5fda3cf..b7430176 100644
--- a/config/configload/validate_test.go
+++ b/config/configload/validate_test.go
@@ -418,18 +418,9 @@ defaults {
 		},
 	}
 
-	logger, _ := logrustest.NewNullLogger()
-	log := logger.WithContext(context.TODO())
-
 	for _, tt := range tests {
 		t.Run(tt.name, func(subT *testing.T) {
-			conf, err := LoadBytes([]byte(tt.hcl), "couper.hcl")
-			if conf != nil {
-				tmpStoreCh := make(chan struct{})
-				defer close(tmpStoreCh)
-
-				_, err = runtime.NewServerConfiguration(conf, log, cache.New(log, tmpStoreCh))
-			}
+			_, err := LoadBytes([]byte(tt.hcl), "couper.hcl")
 
 			var errMsg string
 			if err != nil {
@@ -531,18 +522,9 @@ func TestPermissionMixed(t *testing.T) {
 		},
 	}
 
-	logger, _ := logrustest.NewNullLogger()
-	log := logger.WithContext(context.TODO())
-
 	for _, tt := range tests {
 		t.Run(tt.name, func(subT *testing.T) {
-			conf, err := LoadBytes([]byte(tt.hcl), "couper.hcl")
-			if conf != nil {
-				tmpStoreCh := make(chan struct{})
-				defer close(tmpStoreCh)
-
-				_, err = runtime.NewServerConfiguration(conf, log, cache.New(log, tmpStoreCh))
-			}
+			_, err := LoadBytes([]byte(tt.hcl), "couper.hcl")
 
 			var errMsg string
 			if err != nil {
@@ -556,3 +538,80 @@ func TestPermissionMixed(t *testing.T) {
 		})
 	}
 }
+
+func TestPathAttr(t *testing.T) {
+	tests := []struct {
+		name  string
+		hcl   string
+		error string
+	}{
+		{
+			"path in endpoint: error",
+			`server {
+  endpoint "/**" {
+    path = "/a/**"
+  }
+}`,
+			"couper.hcl:3,5-9: Unsupported argument; An argument named \"path\" is not expected here. Use the \"path\" attribute in a backend block instead.",
+		},
+		{
+			"path in proxy: error",
+			`server {
+  endpoint "/**" {
+    proxy {
+      path = "/a/**"
+    }
+  }
+}`,
+			"couper.hcl:4,7-11: Unsupported argument; An argument named \"path\" is not expected here. Use the \"path\" attribute in a backend block instead.",
+		},
+		{
+			"path in referenced backend: ok",
+			`server {
+  endpoint "/**" {
+    proxy {
+      backend = "a"
+    }
+  }
+}
+definitions {
+  backend "a" {
+    path = "/a/**"
+  }
+}`,
+			"",
+		},
+		{
+			"path in refined backend: ok",
+			`server {
+  endpoint "/**" {
+    proxy {
+      backend "a" {
+        path = "/a/**"
+      }
+    }
+  }
+}
+definitions {
+  backend "a" {
+  }
+}`,
+			"",
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(subT *testing.T) {
+			_, err := LoadBytes([]byte(tt.hcl), "couper.hcl")
+
+			var errMsg string
+			if err != nil {
+				errMsg = err.Error()
+			}
+
+			if tt.error != errMsg {
+				subT.Errorf("%q: Unexpected configuration error:\n\tWant: %q\n\tGot:  %q", tt.name, tt.error, errMsg)
+			}
+		})
+	}
+}
diff --git a/server/http_backend_test.go b/server/http_backend_test.go
index a902f18e..b1ee4699 100644
--- a/server/http_backend_test.go
+++ b/server/http_backend_test.go
@@ -142,11 +142,10 @@ func TestBackend_WithoutOrigin(t *testing.T) {
 		path    string
 		message string
 	}{
-		{"/proxy/path", `configuration error: anonymous_6_13: the origin attribute has to contain an absolute URL with a valid hostname: ""`},
-		{"/proxy/backend-path", `configuration error: anonymous_15_13: the origin attribute has to contain an absolute URL with a valid hostname: ""`},
-		{"/proxy/url", `configuration error: anonymous_24_13: the origin attribute has to contain an absolute URL with a valid hostname: ""`},
-		{"/request/backend-path", `configuration error: anonymous_37_15: the origin attribute has to contain an absolute URL with a valid hostname: ""`},
-		{"/request/url", `configuration error: anonymous_46_13: the origin attribute has to contain an absolute URL with a valid hostname: ""`},
+		{"/proxy/backend-path", `configuration error: anonymous_6_13: the origin attribute has to contain an absolute URL with a valid hostname: ""`},
+		{"/proxy/url", `configuration error: anonymous_15_13: the origin attribute has to contain an absolute URL with a valid hostname: ""`},
+		{"/request/backend-path", `configuration error: anonymous_28_15: the origin attribute has to contain an absolute URL with a valid hostname: ""`},
+		{"/request/url", `configuration error: anonymous_37_15: the origin attribute has to contain an absolute URL with a valid hostname: ""`},
 	} {
 		t.Run(tc.path, func(st *testing.T) {
 			hook.Reset()
diff --git a/server/http_integration_test.go b/server/http_integration_test.go
index 30cf5c81..d9b532be 100644
--- a/server/http_integration_test.go
+++ b/server/http_integration_test.go
@@ -784,9 +784,6 @@ func TestHTTPServer_PathPrefix(t *testing.T) {
 		{"/v1", expectation{
 			Path: "/xxx/xxx/v1",
 		}},
-		{"/v1/uuu/foo", expectation{
-			Path: "/xxx/xxx/api/foo",
-		}},
 		{"/v1/vvv/foo", expectation{
 			Path: "/xxx/xxx/api/foo",
 		}},
@@ -851,25 +848,6 @@ func TestHTTPServer_BackendLogPath(t *testing.T) {
 	}
 }
 
-func TestHTTPServer_BackendLogPathInEndpoint(t *testing.T) {
-	client := newClient()
-	helper := test.New(t)
-
-	shutdown, hook := newCouper("testdata/integration/api/08_couper.hcl", helper)
-	defer shutdown()
-
-	req, err := http.NewRequest(http.MethodGet, "http://example.com:8080/abc?query#fragment", nil)
-	helper.Must(err)
-
-	hook.Reset()
-	_, err = client.Do(req)
-	helper.Must(err)
-
-	if p := hook.AllEntries()[0].Data["request"].(logging.Fields)["path"]; p != "/new/path/abc?query" {
-		t.Errorf("Unexpected path given: %s", p)
-	}
-}
-
 func TestHTTPServer_BackendLogRequestProto(t *testing.T) {
 	client := newClient()
 	helper := test.New(t)
@@ -3015,70 +2993,6 @@ func TestHTTPServer_request_variables(t *testing.T) {
 	}
 }
 
-func TestHTTPServer_Endpoint_Evaluation_Inheritance(t *testing.T) {
-	client := newClient()
-
-	for _, confFile := range []string{"02_couper.hcl", "03_couper.hcl"} {
-		confPath := path.Join("testdata/integration/endpoint_eval", confFile)
-
-		type expectation struct {
-			Path           string
-			ResponseStatus int
-		}
-
-		type testCase struct {
-			reqPath string
-			exp     expectation
-		}
-
-		for _, tc := range []testCase{
-			{"/endpoint1", expectation{
-				Path:           "/anything",
-				ResponseStatus: http.StatusOK,
-			}},
-			{"/endpoint2", expectation{
-				Path:           "/anything",
-				ResponseStatus: http.StatusOK,
-			}},
-			{"/endpoint3", expectation{
-				Path:           "/unset/by/endpoint",
-				ResponseStatus: http.StatusNotFound,
-			}},
-			{"/endpoint4", expectation{
-				Path:           "/anything",
-				ResponseStatus: http.StatusOK,
-			}},
-		} {
-			t.Run(confFile+"_"+tc.reqPath, func(subT *testing.T) {
-				helper := test.New(subT)
-				shutdown, _ := newCouper(confPath, helper)
-				defer shutdown()
-
-				req, err := http.NewRequest(http.MethodGet, "http://example.com:8080"+tc.reqPath, nil)
-				helper.Must(err)
-
-				res, err := client.Do(req)
-				helper.Must(err)
-
-				resBytes, err := io.ReadAll(res.Body)
-				helper.Must(err)
-
-				_ = res.Body.Close()
-
-				var jsonResult expectation
-				err = json.Unmarshal(resBytes, &jsonResult)
-				if err != nil {
-					subT.Errorf("unmarshal json: %v: got:\n%s", err, string(resBytes))
-				}
-
-				if !reflect.DeepEqual(jsonResult, tc.exp) {
-					subT.Errorf("%q: %q:\nwant:\t%#v\ngot:\t%#v\npayload:\n%s", confFile, tc.reqPath, tc.exp, jsonResult, string(resBytes))
-				}
-			})
-		}
-	}
-}
-
 func TestOpenAPIValidateConcurrentRequests(t *testing.T) {
 	helper := test.New(t)
 	client := newClient()
diff --git a/server/testdata/integration/api/06_couper.hcl b/server/testdata/integration/api/06_couper.hcl
index 007267e7..cd74a648 100644
--- a/server/testdata/integration/api/06_couper.hcl
+++ b/server/testdata/integration/api/06_couper.hcl
@@ -10,15 +10,6 @@ server "multi-api" {
         }
       }
     }
-    endpoint "/uuu/**" {
-      path = "/api/**"
-      proxy {
-        backend {
-          origin = env.COUPER_TEST_BACKEND_ADDR
-          path_prefix = "/${request.headers.x-val}/xxx/"
-        }
-      }
-    }
     endpoint "/vvv/**" {
       proxy {
         backend {
diff --git a/server/testdata/integration/api/07_couper.hcl b/server/testdata/integration/api/07_couper.hcl
index a23e5986..5d8416e4 100644
--- a/server/testdata/integration/api/07_couper.hcl
+++ b/server/testdata/integration/api/07_couper.hcl
@@ -1,7 +1,6 @@
 server "api" {
   api {
     endpoint "/**" {
-      path = "/new/path/**"
       proxy {
         backend {
           origin = "${env.COUPER_TEST_BACKEND_ADDR}"
diff --git a/server/testdata/integration/api/08_couper.hcl b/server/testdata/integration/api/08_couper.hcl
deleted file mode 100644
index 12ba4d89..00000000
--- a/server/testdata/integration/api/08_couper.hcl
+++ /dev/null
@@ -1,12 +0,0 @@
-server "api" {
-  api {
-    endpoint "/**" {
-      path = "/new/path/**"
-      proxy {
-        backend {
-          origin = "${env.COUPER_TEST_BACKEND_ADDR}"
-        }
-      }
-    }
-  }
-}
diff --git a/server/testdata/integration/api/09_couper.hcl b/server/testdata/integration/api/09_couper.hcl
index 63648070..e8c73463 100644
--- a/server/testdata/integration/api/09_couper.hcl
+++ b/server/testdata/integration/api/09_couper.hcl
@@ -1,7 +1,6 @@
 server "api" {
   api {
     endpoint "/**" {
-      path = "/new/path/**"
       proxy {
         backend {
           origin = "${env.COUPER_TEST_BACKEND_ADDR}"
diff --git a/server/testdata/integration/api/10_couper.hcl b/server/testdata/integration/api/10_couper.hcl
index ba1880cf..6444f616 100644
--- a/server/testdata/integration/api/10_couper.hcl
+++ b/server/testdata/integration/api/10_couper.hcl
@@ -1,7 +1,6 @@
 server "api" {
   api {
     endpoint "/**" {
-      path = "/new/path/**"
       proxy {
         backend {
           origin = "${env.COUPER_TEST_BACKEND_ADDR}"
diff --git a/server/testdata/integration/api/11_couper.hcl b/server/testdata/integration/api/11_couper.hcl
index 9baee0f0..3d16dc7a 100644
--- a/server/testdata/integration/api/11_couper.hcl
+++ b/server/testdata/integration/api/11_couper.hcl
@@ -1,7 +1,6 @@
 server "api" {
   api {
     endpoint "/**" {
-      path = "/new/path/**"
       proxy {
         backend {
           origin = "${env.COUPER_TEST_BACKEND_ADDR}"
diff --git a/server/testdata/integration/api/12_couper.hcl b/server/testdata/integration/api/12_couper.hcl
index 4911c7da..ea51dda2 100644
--- a/server/testdata/integration/api/12_couper.hcl
+++ b/server/testdata/integration/api/12_couper.hcl
@@ -1,7 +1,6 @@
 server "api" {
   api {
     endpoint "/**" {
-      path = "/new/path/**"
       proxy {
         backend {
           origin = "${env.COUPER_TEST_BACKEND_ADDR}"
diff --git a/server/testdata/integration/backends/01_couper.hcl b/server/testdata/integration/backends/01_couper.hcl
index e06c21a7..d26158ca 100644
--- a/server/testdata/integration/backends/01_couper.hcl
+++ b/server/testdata/integration/backends/01_couper.hcl
@@ -2,15 +2,6 @@ server {
   api {
     base_path = "/proxy"
 
-    endpoint "/path" {
-      proxy {
-        path = "/my-path"
-        backend {
-          # no origin
-        }
-      }
-    }
-
     endpoint "/backend-path" {
       proxy {
         backend {
@@ -43,7 +34,7 @@ server {
     }
 
     endpoint "/url" {
-      proxy {
+      request {
         url = "/my-path"
         backend {
           # no origin
diff --git a/server/testdata/integration/backends/05_couper.hcl b/server/testdata/integration/backends/05_couper.hcl
index b7190411..3db6edd9 100644
--- a/server/testdata/integration/backends/05_couper.hcl
+++ b/server/testdata/integration/backends/05_couper.hcl
@@ -1,8 +1,7 @@
 server {
   endpoint "/**" {
     proxy {
-      path = "/**"
-      url = "{{ .origin }}/"
+      url = "{{ .origin }}/**"
     }
   }
 }
diff --git a/server/testdata/integration/endpoint_eval/01_couper.hcl b/server/testdata/integration/endpoint_eval/01_couper.hcl
index 0723dee5..6623890a 100644
--- a/server/testdata/integration/endpoint_eval/01_couper.hcl
+++ b/server/testdata/integration/endpoint_eval/01_couper.hcl
@@ -5,7 +5,6 @@ server "api" {
     error_file = "./../api_error.json"
 
     endpoint "/{path}/{hostname}/{origin}" {
-      path = "/set/by/endpoint/unset/by/backend"
       proxy {
         backend "anything" {
           path = "/anything"
diff --git a/server/testdata/integration/endpoint_eval/02_couper.hcl b/server/testdata/integration/endpoint_eval/02_couper.hcl
deleted file mode 100644
index 0a68b29d..00000000
--- a/server/testdata/integration/endpoint_eval/02_couper.hcl
+++ /dev/null
@@ -1,47 +0,0 @@
-server "api" {
-  api {
-    endpoint "/endpoint1" {
-      path = "/123"
-      proxy {
-        backend "anything" {
-          path = "/anything"
-        }
-      }
-    }
-
-    endpoint "/endpoint2" {
-     path = "/unset/by/local-backend"
-      proxy {
-        backend "anything" {
-          path = "/anything"
-        }
-      }
-    }
-
-    # don't override path
-    endpoint "/endpoint3" {
-      path = "/backend/wins"
-      proxy {
-        backend  = "anything"
-      }
-    }
-
-    endpoint "/endpoint4" {
-      path = "/anything"
-      proxy {
-        backend {
-		  origin = env.COUPER_TEST_BACKEND_ADDR != "" ? env.COUPER_TEST_BACKEND_ADDR : "http://127.0.0.1:1"
-        }
-      }
-    }
-
-  }
-}
-
-definitions {
-  # backend origin within a definition block gets replaced with the integration test "anything" server.
-  backend "anything" {
-    path = "/unset/by/endpoint"
-    origin = env.COUPER_TEST_BACKEND_ADDR
-  }
-}
diff --git a/server/testdata/integration/endpoint_eval/03_couper.hcl b/server/testdata/integration/endpoint_eval/03_couper.hcl
deleted file mode 100644
index eebf6c35..00000000
--- a/server/testdata/integration/endpoint_eval/03_couper.hcl
+++ /dev/null
@@ -1,46 +0,0 @@
-server "api" {
-  api {
-
-    endpoint "/endpoint1" {
-      proxy {
-        backend "anything" {
-          path = "/anything"
-        }
-      }
-    }
-
-    endpoint "/endpoint2" {
-      path = "/unset/by/local-backend"
-      proxy {
-        backend "anything" {
-          path = "/anything"
-        }
-      }
-    }
-
-    # don't override path
-    endpoint "/endpoint3" {
-      proxy {
-        backend = "anything"
-      }
-    }
-
-    endpoint "/endpoint4" {
-      path = "/unset/here"
-      proxy {
-        backend "anything" {
-          path = "/anything"
-        }
-      }
-    }
-
-  }
-}
-
-definitions {
-  # backend origin within a definition block gets replaced with the integration test "anything" server.
-  backend "anything" {
-    path = "/unset/by/endpoint"
-    origin = env.COUPER_TEST_BACKEND_ADDR
-  }
-}
diff --git a/server/testdata/integration/endpoint_eval/05_couper.hcl b/server/testdata/integration/endpoint_eval/05_couper.hcl
index 9a911166..c92aa59c 100644
--- a/server/testdata/integration/endpoint_eval/05_couper.hcl
+++ b/server/testdata/integration/endpoint_eval/05_couper.hcl
@@ -1,7 +1,6 @@
 server "api" {
   api {
     endpoint "/" {
-      path = "/yyy"
       proxy {
         backend = "anything"
       }
diff --git a/server/testdata/integration/endpoint_eval/06_couper.hcl b/server/testdata/integration/endpoint_eval/06_couper.hcl
index 2bea1aa6..7bbd0e12 100644
--- a/server/testdata/integration/endpoint_eval/06_couper.hcl
+++ b/server/testdata/integration/endpoint_eval/06_couper.hcl
@@ -1,7 +1,6 @@
 server "api" {
   api {
     endpoint "/" {
-      path = "/yyy"
       proxy {
         backend "anything" {
           path = "/zzz"
diff --git a/server/testdata/integration/endpoint_eval/11_couper.hcl b/server/testdata/integration/endpoint_eval/11_couper.hcl
index a5bffb09..7ca92d23 100644
--- a/server/testdata/integration/endpoint_eval/11_couper.hcl
+++ b/server/testdata/integration/endpoint_eval/11_couper.hcl
@@ -1,7 +1,6 @@
 server "api" {
   api {
     endpoint "/**" {
-      path = "/**"
       proxy {
         backend {
           origin = env.COUPER_TEST_BACKEND_ADDR
diff --git a/server/testdata/integration/files_spa_api/01_couper.hcl b/server/testdata/integration/files_spa_api/01_couper.hcl
index f67780ea..8cffaec7 100644
--- a/server/testdata/integration/files_spa_api/01_couper.hcl
+++ b/server/testdata/integration/files_spa_api/01_couper.hcl
@@ -10,7 +10,6 @@ server "spa" {
   api {
     error_file = "./../api_error.json"
     endpoint "/api" {
-      path = "/"
       proxy {
         backend = "anything"
       }
diff --git a/server/testdata/integration/vhosts/01_couper.hcl b/server/testdata/integration/vhosts/01_couper.hcl
index 3f678499..6fde75ac 100644
--- a/server/testdata/integration/vhosts/01_couper.hcl
+++ b/server/testdata/integration/vhosts/01_couper.hcl
@@ -16,7 +16,6 @@ server "v-server1" {
     error_file = "./../api_error.json"
 
     endpoint "/" {
-      path = "/"
       proxy {
         backend = "anything"
       }
@@ -43,7 +42,6 @@ server "v-server2" {
     error_file = "./../api_error.json"
 
     endpoint "/" {
-      path = "/"
       proxy {
         backend = "anything"
       }