Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change Request method via middleware #3519

Closed
shish opened this issue Jan 10, 2019 · 6 comments
Closed

Change Request method via middleware #3519

shish opened this issue Jan 10, 2019 · 6 comments
Labels

Comments

@shish
Copy link

shish commented Jan 10, 2019

Long story short

Browsers still only support GET and POST on HTML forms. I want to make a web front end for my REST API which includes DELETEing things, without having to use javascript. The standard suggestion here is to use POST and have a hidden field <input type="hidden" name="_method" value="DELETE">, and then have your middleware redirect that request to use the DELETE handler.

Expected behaviour

There should be some way to do this

Actual behaviour

As far as I can tell this is impossible with aiohttp?

Steps to reproduce

    @web.middleware
    async def set_method(request, handler):
        data = await request.post()
        if '_method' in data:
            request.method = data['_method']  # doesn't work because method is reified and immutable
            request._method = data['_method']  # has no effect because method is reified
            request = request.clone(method=data['_method'])  # can't clone a request after calling .post() on it
        return await handler(request)

in all cases the route handler for POST gets called instead of DELETE :(

Your environment

3.5.2 server

@shish shish changed the title Change Request method Change Request method via middleware Jan 10, 2019
@aio-libs-bot
Copy link

GitMate.io thinks the contributor most likely able to help you is @asvetlov.

Possibly related issues are #2919 (Call method to clean middleware class), #3097 (aiohttp middleware and replacing a request in flight), #2225 (Middleware factory is run for every single request), #1392 (Issue with ClientSession.request('POST') method), and #491 (Handling basic auth with a middleware or a request annotation).

@shish
Copy link
Author

shish commented Jan 10, 2019

Custom Routing Criteria looks like maybe it could work, but I would have to manually override all of my routes, I can't just say "if _method==DELETE, call .delete() instead of .post()" in one place?

@asvetlov
Copy link
Member

The problem is: if you started to read request body (await request.post()) you cannot change the request because its body is at least partially consumed.

@shish
Copy link
Author

shish commented Jan 11, 2019

If the request can't be modified, is there an elegant way to re-route the request as-is? The high-level goal is just that a POST with _method=DELETE should go to the route that has been configured to handle DELETE, without having to add

def post(self):
    data = await self.request.post()
    if data.get("_method") == "DELETE":
        return await self.delete()

def delete(self):
    [...]

into every web.View individually

@arthurdarcet
Copy link
Contributor

arthurdarcet commented Jan 11, 2019

you could create a base view such as

class BaseView:
    async def post(self):
        data = await self.request.post()
        if data.get('_method') == 'delete':
            return await self.delete()
        return await self.real_post()

    async def real_post(self):
        return await super().post() # will raise a 405

class View(BaseView):
    async def delete(self):
        ...
    async def real_post(self):
        ...

or you can do some weird magic with metaclasses or __init_subclass__ to have real_post named post in the child classes, but that's up to you

@lock
Copy link

lock bot commented Jan 16, 2020

This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs.

If you feel like there's important points made in this discussion,
please include those exceprts into that new issue.

@lock lock bot added the outdated label Jan 16, 2020
@lock lock bot locked as resolved and limited conversation to collaborators Jan 16, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants