diff --git a/httpbin/core.py b/httpbin/core.py
index a82c1b88..4e7f0264 100644
--- a/httpbin/core.py
+++ b/httpbin/core.py
@@ -33,7 +33,10 @@
except ImportError: # werkzeug < 2.1
from werkzeug.wrappers import BaseResponse as Response
-from flasgger import Swagger, NO_SANITIZER
+try:
+ from flasgger import Swagger, NO_SANITIZER
+except ImportError:
+ Swagger = None
from . import filters
from .helpers import (
@@ -93,79 +96,82 @@ def jsonify(*args, **kwargs):
app.add_template_global("HTTPBIN_TRACKING" in os.environ, name="tracking_enabled")
-app.config["SWAGGER"] = {"title": "httpbin.org", "uiversion": 3}
-
-template = {
- "swagger": "2.0",
- "info": {
- "title": "httpbin.org",
- "description": (
- "A simple HTTP Request & Response Service."
- "
A Kenneth Reitz project."
- "
Run locally:
"
- "$ docker pull ghcr.io/psf/httpbin
"
- "$ docker run -p 80:8080 ghcr.io/psf/httpbin
"
- ),
- "contact": {
- "responsibleOrganization": "Python Software Foundation",
- "responsibleDeveloper": "Kenneth Reitz",
- "url": "https://github.com/psf/httpbin/",
- },
- # "termsOfService": "http://me.com/terms",
- "version": version,
- },
- "host": "httpbin.org", # overrides localhost:5000
- "basePath": "/", # base bash for blueprint registration
- "schemes": ["https"],
- "protocol": "https",
- "tags": [
- {
- "name": "HTTP Methods",
- "description": "Testing different HTTP verbs",
- # 'externalDocs': {'description': 'Learn more', 'url': 'https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html'}
- },
- {"name": "Auth", "description": "Auth methods"},
- {
- "name": "Status codes",
- "description": "Generates responses with given status code",
- },
- {"name": "Request inspection", "description": "Inspect the request data"},
- {
- "name": "Response inspection",
- "description": "Inspect the response data like caching and headers",
- },
- {
- "name": "Response formats",
- "description": "Returns responses in different data formats",
- },
- {"name": "Dynamic data", "description": "Generates random and dynamic data"},
- {"name": "Cookies", "description": "Creates, reads and deletes Cookies"},
- {"name": "Images", "description": "Returns different image formats"},
- {"name": "Redirects", "description": "Returns different redirect responses"},
- {
- "name": "Anything",
- "description": "Returns anything that is passed to request",
+if Swagger is not None:
+ app.config["SWAGGER"] = {"title": "httpbin.org", "uiversion": 3}
+
+ template = {
+ "swagger": "2.0",
+ "info": {
+ "title": "httpbin.org",
+ "description": (
+ "A simple HTTP Request & Response Service."
+ "
A Kenneth Reitz project."
+ "
Run locally:
"
+ "$ docker pull ghcr.io/psf/httpbin
"
+ "$ docker run -p 80:8080 ghcr.io/psf/httpbin
"
+ ),
+ "contact": {
+ "responsibleOrganization": "Python Software Foundation",
+ "responsibleDeveloper": "Kenneth Reitz",
+ "url": "https://github.com/psf/httpbin/",
+ },
+ # "termsOfService": "http://me.com/terms",
+ "version": version,
},
- ],
-}
-
-swagger_config = {
- "headers": [],
- "specs": [
- {
- "endpoint": "spec",
- "route": "/spec.json",
- "rule_filter": lambda rule: True, # all in
- "model_filter": lambda tag: True, # all in
- }
- ],
- "static_url_path": "/flasgger_static",
- # "static_folder": "static", # must be set by user
- "swagger_ui": True,
- "specs_route": "/",
-}
+ "host": "httpbin.org", # overrides localhost:5000
+ "basePath": "/", # base bash for blueprint registration
+ "schemes": ["https"],
+ "protocol": "https",
+ "tags": [
+ {
+ "name": "HTTP Methods",
+ "description": "Testing different HTTP verbs",
+ # 'externalDocs': {'description': 'Learn more', 'url': 'https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html'}
+ },
+ {"name": "Auth", "description": "Auth methods"},
+ {
+ "name": "Status codes",
+ "description": "Generates responses with given status code",
+ },
+ {"name": "Request inspection", "description": "Inspect the request data"},
+ {
+ "name": "Response inspection",
+ "description": "Inspect the response data like caching and headers",
+ },
+ {
+ "name": "Response formats",
+ "description": "Returns responses in different data formats",
+ },
+ {"name": "Dynamic data", "description": "Generates random and dynamic data"},
+ {"name": "Cookies", "description": "Creates, reads and deletes Cookies"},
+ {"name": "Images", "description": "Returns different image formats"},
+ {"name": "Redirects", "description": "Returns different redirect responses"},
+ {
+ "name": "Anything",
+ "description": "Returns anything that is passed to request",
+ },
+ ],
+ }
-swagger = Swagger(app, sanitizer=NO_SANITIZER, template=template, config=swagger_config)
+ swagger_config = {
+ "headers": [],
+ "specs": [
+ {
+ "endpoint": "spec",
+ "route": "/spec.json",
+ "rule_filter": lambda rule: True, # all in
+ "model_filter": lambda tag: True, # all in
+ }
+ ],
+ "static_url_path": "/flasgger_static",
+ # "static_folder": "static", # must be set by user
+ "swagger_ui": True,
+ "specs_route": "/",
+ }
+
+ swagger = Swagger(app, sanitizer=NO_SANITIZER, template=template, config=swagger_config)
+else:
+ app.logger.warning("Swagger not found, legacy index will be used.")
# Set up Bugsnag exception tracking, if desired. To use Bugsnag, install the
# Bugsnag Python client with the command "pip install bugsnag", and set the
@@ -244,6 +250,13 @@ def set_cors_headers(response):
# ------
+if Swagger is None:
+ @app.route("/")
+ def no_flasgger_index():
+ """Redirect to legacy index if flasgger is not available."""
+ return redirect(url_for("view_landing_page"))
+
+
@app.route("/legacy")
def view_landing_page():
"""Generates Landing Page in legacy layout."""
diff --git a/pyproject.toml b/pyproject.toml
index c5bdb811..34e2c43d 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -33,7 +33,6 @@ classifiers = [
dependencies = [
"brotlicffi",
"decorator",
- "flasgger",
"flask >= 2.2.4",
'greenlet < 3.0; python_version<"3.12"',
'greenlet >= 3.0.0a1; python_version>="3.12.0rc0"',
@@ -44,6 +43,9 @@ dependencies = [
[project.optional-dependencies]
test = ["pytest", "tox"]
+flasgger = [
+ "flasgger",
+]
mainapp = [
"gunicorn",
"gevent",
diff --git a/tests/test_httpbin.py b/tests/test_httpbin.py
index 6b751245..2ce63a61 100755
--- a/tests/test_httpbin.py
+++ b/tests/test_httpbin.py
@@ -10,6 +10,7 @@
from io import BytesIO
import httpbin
+from httpbin.core import Swagger
from httpbin.helpers import parse_multi_value_header
@@ -115,7 +116,8 @@ def setUp(self):
def test_index(self):
response = self.app.get('/', headers={'User-Agent': 'test'})
- self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.status_code,
+ 200 if Swagger is not None else 302)
def get_data(self, response):
if 'get_data' in dir(response):