Search code examples
pythonregexsanic

Regex with optional slashes in Sanic endpoints


I want to do an API REST with Sanic (https://github.com/huge-success/sanic) and I'm stuck with the regular expressions.

I have this endpoint: api/foo/<string_with_or_without_slashes>/bar/<string>/baz

My python code is:

from sanic import Sanic                                                                                                                                                                  
from sanic.response import json                                                                                                                                                          

app = Sanic()                                                                                                                                                                            

@app.route('/api/foo/<foo_id:[^/].*?>/baz')                                                                                                                                              
async def test1(request, foo_id):                                                                                                                                                        
    return json({'test1': foo_id})                                                                                                                                                       

@app.route('/api/foo/<foo_id:[^/].*?>/bar/<bar_id>/baz')                                                                                                                                 
async def test2(request, foo_id, bar_id):                                                                                                                                                 
    return json({'test2': f'{foo_id}:{bar_id}'})                                                                                                                                         

if __name__ == '__main__':                                                                                                                                                               
    app.run(host='0.0.0.0', port=8000)          

If I do:

$ curl -i http://localhost:8000/api/foo/aa/bar/bb/baz
{"test1":"aa\/bar\/bb"} 

Or $ curl -i http://localhost:8000/api/foo/a/a/bar/bb/baz.

It's always called test1 when I want to call test2 function.

Can you help me? Thank you very much! :)


Solution

  • Both routes match your test requests, and as the first matching route is used (see this issue on GitHub) test1 is executed.

    Because your first route is more general than your second route, you could just define test2 before test1:

    from sanic import Sanic
    from sanic.response import json
    
    app = Sanic()
    
    @app.route('/api/foo/<foo_id:[^/].*?>/bar/<bar_id>/baz')
    async def test2(request, foo_id, bar_id):
        return json({'test2': f'{foo_id}:{bar_id}'})
    
    @app.route('/api/foo/<foo_id:[^/].*?>/baz')
    async def test1(request, foo_id):
        return json({'test1': foo_id})
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=8000)