diff --git a/CHANGES.rst b/CHANGES.rst index cf47ec8d..d98d91fe 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -64,6 +64,9 @@ Unreleased This could allow a session interface to change behavior based on ``request.endpoint``. :issue:`3776` - Use Jinja's implementation of the ``|tojson`` filter. :issue:`3881` +- Add route decorators for common HTTP methods. For example, + ``@app.post("/login")`` is a shortcut for + ``@app.route("/login", methods=["POST"])``. :pr:`3907` Version 1.1.2 diff --git a/src/flask/scaffold.py b/src/flask/scaffold.py index 5b6bb80c..d1c24bd1 100644 --- a/src/flask/scaffold.py +++ b/src/flask/scaffold.py @@ -146,6 +146,47 @@ class Scaffold(_PackageBoundObject): def _is_setup_finished(self): raise NotImplementedError + def _method_route(self, method, rule, options): + if "methods" in options: + raise TypeError("Use the 'route' decorator to use the 'methods' argument.") + + return self.route(rule, methods=[method], **options) + + def get(self, rule, **options): + """Shortcut for :meth:`route` with ``methods=["GET"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("GET", rule, options) + + def post(self, rule, **options): + """Shortcut for :meth:`route` with ``methods=["POST"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("POST", rule, options) + + def put(self, rule, **options): + """Shortcut for :meth:`route` with ``methods=["PUT"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("PUT", rule, options) + + def delete(self, rule, **options): + """Shortcut for :meth:`route` with ``methods=["DELETE"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("DELETE", rule, options) + + def patch(self, rule, **options): + """Shortcut for :meth:`route` with ``methods=["PATCH"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("PATCH", rule, options) + def route(self, rule, **options): """A decorator that is used to register a view function for a given URL rule. This does the same thing as :meth:`add_url_rule` diff --git a/tests/test_basic.py b/tests/test_basic.py index f4decf0c..d6ec3fe4 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -48,6 +48,23 @@ def test_options_on_multiple_rules(app, client): assert sorted(rv.allow) == ["GET", "HEAD", "OPTIONS", "POST", "PUT"] +@pytest.mark.parametrize("method", ["get", "post", "put", "delete", "patch"]) +def test_method_route(app, client, method): + method_route = getattr(app, method) + client_method = getattr(client, method) + + @method_route("/") + def hello(): + return "Hello" + + assert client_method("/").data == b"Hello" + + +def test_method_route_no_methods(app): + with pytest.raises(TypeError): + app.get("/", methods=["GET", "POST"]) + + def test_provide_automatic_options_attr(): app = flask.Flask(__name__)