Skip to content

Commit

Permalink
Add syntatic sugar for route registration
Browse files Browse the repository at this point in the history
This takes a popular API whereby instead of passing the HTTP method as
an argument to route it is instead used as the method name i.e.

    @app.route("/", methods=["POST"])

is now writeable as,

    @app.post("/")

This is simply syntatic sugar, it doesn't do anything else, but makes
it slightly easier for users.

I've included all the methods that are relevant and aren't auto
generated i.e. not connect, head, options, and trace.
  • Loading branch information
pgjones authored and davidism committed Mar 8, 2021
1 parent 82d69cd commit 705e526
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
41 changes: 41 additions & 0 deletions src/flask/scaffold.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,47 @@ def __init__(
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`
Expand Down
17 changes: 17 additions & 0 deletions tests/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,23 @@ def index_put():
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__)

Expand Down

0 comments on commit 705e526

Please sign in to comment.