Repository: striglia/pyramid_swagger
Pull request #201 (2017-04-06 13:40:39)

support virtual hosting
use request.path_info for matching api paths, which allows reverse proxying an API on a subpath.


Patch:
diff --git a/pyramid_swagger/api.py b/pyramid_swagger/api.py
index fa57fdd..6774977 100644
--- a/pyramid_swagger/api.py
+++ b/pyramid_swagger/api.py
@@ -536,9 +536,9 @@ def _build_swagger_20_schema_views(config):
     file_map = {}
 
     def view_for_swagger_schema(request):
-        path, ext = os.path.splitext(request.path)
+        path, ext = os.path.splitext(request.path_info)
         ext = ext.lstrip('.')
-        actual_fname = file_map[request.path]
+        actual_fname = file_map[request.path_info]
         with spec.resolver.resolving(actual_fname) as spec_dict:
             clean_response = strip_xscope(spec_dict)
             ref_walker = NodeWalkerForCleaningRefs()
diff --git a/pyramid_swagger/load_schema.py b/pyramid_swagger/load_schema.py
index 62299b7..08b0b6d 100644
--- a/pyramid_swagger/load_schema.py
+++ b/pyramid_swagger/load_schema.py
@@ -229,7 +229,7 @@ class RequestMatcher(object):
         :returns: True if this matcher matches the request, False otherwise
         """
         return (
-            partial_path_match(request.path, self.path) and
+            partial_path_match(request.path_info, self.path) and
             request.method == self.method
         )
 
diff --git a/pyramid_swagger/model.py b/pyramid_swagger/model.py
index 631d17a..10a2d5e 100644
--- a/pyramid_swagger/model.py
+++ b/pyramid_swagger/model.py
@@ -51,7 +51,7 @@ class SwaggerSchema(object):
 
         raise PathNotMatchedError(
             'Could not find the relevant path ({0}) in the Swagger schema. '
-            'Perhaps you forgot to add it?'.format(request.path)
+            'Perhaps you forgot to add it?'.format(request.path_info)
         )
 
     def get_api_doc_endpoints(self):
diff --git a/pyramid_swagger/tween.py b/pyramid_swagger/tween.py
index 83d9b33..ac2e915 100644
--- a/pyramid_swagger/tween.py
+++ b/pyramid_swagger/tween.py
@@ -438,7 +438,7 @@ def should_exclude_request(settings, request, route_info):
     ))
     return (
         disable_all_validation or
-        should_exclude_path(settings.exclude_paths, request.path) or
+        should_exclude_path(settings.exclude_paths, request.path_info) or
         should_exclude_route(settings.exclude_routes, route_info) or
         is_swagger_documentation_route(route_info)
     )


Test patch:
diff --git a/tests/acceptance/api_test.py b/tests/acceptance/api_test.py
index b0f33d6..c2a1599 100644
--- a/tests/acceptance/api_test.py
+++ b/tests/acceptance/api_test.py
@@ -96,3 +96,8 @@ def test_recursive_swagger_api_external_refs():
 
     recursive_test_app.get('/swagger.json', status=200)
     recursive_test_app.get('/external.json', status=200)
+
+
+def test_virtual_subpath(settings):
+    test_app = App(main({}, **settings), {'SCRIPT_NAME': '/subpath'})
+    test_app.get('/subpath/swagger.json', status=200)
diff --git a/tests/model_test.py b/tests/model_test.py
index ab5704b..25df64c 100644
--- a/tests/model_test.py
+++ b/tests/model_test.py
@@ -27,7 +27,7 @@ def test_swagger_schema_for_request_different_methods(schema):
     # either and have them pass validation.
     value = schema.validators_for_request(
         request=mock.Mock(
-            path="/sample",
+            path_info="/sample",
             method="GET"
         ),
     )
@@ -35,7 +35,7 @@ def test_swagger_schema_for_request_different_methods(schema):
 
     value = schema.validators_for_request(
         request=mock.Mock(
-            path="/sample",
+            path_info="/sample",
             method="POST",
             body={'foo': 1, 'bar': 2},
         ),
@@ -57,7 +57,7 @@ def test_swagger_schema_for_request_not_found(schema):
     with pytest.raises(PathNotMatchedError) as excinfo:
         schema.validators_for_request(
             request=mock.Mock(
-                path="/does_not_exist",
+                path_info="/does_not_exist",
                 method="GET"
             ),
         )
@@ -78,3 +78,18 @@ def test_partial_path_match():
         '/v1/google/forward_unstructured',
         '/v1/bing/forward_unstructured'
     )
+
+
+def test_swagger_schema_for_request_virtual_subpath(schema):
+
+    # There exists a GET and POST for this endpoint. We should be able to call
+    # either and have them pass validation.
+    value = schema.validators_for_request(
+        request=mock.Mock(
+            path="/subpath/sample",
+            script_name="/subpath",
+            path_info="/sample",
+            method="GET"
+        ),
+    )
+    assert value.body.schema is None