Home > database >  Determining which route would be used for a request URL
Determining which route would be used for a request URL

Time:05-28

In the Flask framework, I would like to be able to determine which request route would be selected to serve a URL, without having to actually request the URL itself. For example, if I have an app like:

import flask

app = flask.Flask(__name__)

@app.route('/')
def index():
    pass

@app.route('/<id:int>')
@app.route('/<id:int>-<slug>')
def show_page(id, slug = None):
    pass

then I'd like to be able to do something like (fictional example):

route = app.get_url_rule("/12345")

and get a result like:

('show_page', {'id':12345,'slug':None})

As far as I can tell, Flask doesn't expose any functionality like this on its own, but is there a way to possibly dig down into its request routing layer (or possibly Werkzeug) to implement this myself?

CodePudding user response:

I tried Davidism's method with your route code, in case this helps...

from flask import Flask, request

app = Flask(__name__)

@app.route('/<int:id>')
@app.route('/<int:id>-<slug>')
def show_page(id, slug = None):
    adapter = app.create_url_adapter(request)
    endpoint, values = adapter.match()
    
    # Return this to frontend of ease of demo
    return {endpoint: values}

A request to /123 returns:

{
  "show_page": {
    "id": 123
  }
}

A request to /123-abc returns:

{
  "show_page": {
    "id": 123, 
    "slug": "abc"
  }
}

CodePudding user response:

The result you're looking for is exactly what Flask does for routing, through Werkzeug. When you decorate view functions, the rules are registered in an instance of werkzeug.routing.Map. When the app handles a request, the map is bound to the request to create a MapAdapter. The adapter has a match() method which either returns an endpoint, args match or raises a routing error such as 307, 404, or 405. Flask call this and uses the result to call the appropriate view function.

Call app.create_url_adapter() to get an adapter based on the app configuration. When not in a request, this requires configuring SERVER_NAME. Then call adapter.match(url) to get a match. This example ignores routing exceptions and returns None.

from werkzeug.exceptions import HTTPException

# remember to configure app.config["SERVER_NAME"]

def match_url(url):
    adapter = app.get_url_adapter()
    
    try:
        return adapter.match(url)
    except HTTPException:
        return None

Calling match_url("/12345-example") returns ('show_page', {'id': 12345, 'slug': 'example'}).

Note that this normally isn't useful, as the point of Flask is that it will already do the routing and call the appropriate view.

  • Related