I defined some resource called WorkerAPI using flask-restful and the plan is to process POST request from /api/workers/new and GET request from /api/workers/. When using the following code
api.add_resource(WorkerAPI, '/api/workers/new')
api.add_resource(WorkerAPI, '/api/workers/')
I get errors:
AssertionError: View function mapping is overwriting an existing endpoint function: workerapi
Then I tried to use the following, which seems to work, although I don't know why it works.
api.add_resource(WorkerAPI, '/api/workers/new', endpoint='/workers/new')
api.add_resource(WorkerAPI, '/api/workers/', endpoint='/workers/')
It looks like redundant information to me though. It seems the site works as long as the two endpoints are defined as different strings. What does endpoint mean here?
The thing is that the add_resource function registers the routes with the framework using the given endpoint. If an endpoint isn't given then Flask-RESTful generates one for you from the class name.
Your case is WorkerAPI, the endpoint will beworkerapi for these two methods, better make endpoint explicit and avoid to have conflicting endpoint names registered.
For what's endpoint, you can refer to this answer for more details.
'endpoint' is actually an identifier that is used in determining what logical unit of your code should handle a specific request.
So, an URL path is mapped to an endpoint and then an endpoint is mapped to a view function in your flask app.
In your case, when you are explicitly defining your endpoints for your resources, it helps the flask app internally to map it efficiently to a list of routes, while when your are not explicitly defining it, flask takes some default value, as explained by #Tiny.D, in the above answer.
Related
I am creating an application with FastAPI and so far it goes like this:
But I'm having a problem with the endpoints. The /api/items/filter route has two query parameters: name and category.
However, it gives me the impression that it is being taken as if it were api/items/{user_id}/filter, since when I do the validation in the documentation it throws me an error saying that I have not passed a value for user_id. (Also, previously it asked me to be authenticated (the only route that needed authentication was api/items/{user_id}.
The problems are fixed when I define this endpoint first as shown below:
Why is this happening? Is there a concept that I am not clear?
Ordering your endpoints matters! Endpoints are matched in order they are declared in your FastAPI object. Let say you have only two endpoints, in this order:
api/items/{user_id}
api/items/filter
In this order, when you request endpoint api/items/user_a, your request will be routed to (1) api/items/{user_id}. However, if you request api/items/filter, this also will be routed to (1) api/items/{user_id}! That is because filter is a match for {user_id}, and since this endpoint is evaluated before the second endpoint is evaluated for a match, the second endpoint is not evaluated at all.
That is also why you are asked for authorization; you think you are requesting endpoint 2, but your request is actually routed to endpoint 1, with path parameter {user_id} = "filter".
So, ordering your endpoints is important, and it is just where in your application you are defining them. See here in the docs.
I have a flask route this like:
#app.route('/product/<string:slug>')
def product(slug):
# some codes...
return render_template('product.html', product=product)
Different clients use the project (different websites, same infrastructure). And every customer wants the product URL to be different. Like;
asite.com/product-nike-shoe-323
bsite.com/nike-shoe
csite.com/product/nike-shoue
vs. vs
How do I set the URL structure to come from the database?
like:
url_config = "product-{product_name}-{product_id}"
or
url_config = "product-{product_id}"
Note: please without redirect.
I’m not 100% clear on what you refer to when you say “database” here. From context I infer you may be talking about the Flask Config object. If that’s the case, you can simply register your view function right after setting up the app configuration. Just call app.add_url_rule() to register the URL pattern from the configuration to point to your view function of choice.
If, however, you are talking about a SQL or NoSQL database and you have built a web UI to register routes, then don’t dispair. Flask routes can be registered with the app object at any point. There is no point in the Flask app lifecycle after which you can no longer register a route!
All that registering a route does, is create a mapping between a URL template and endpoint name, an opaque string. Most of the time, you also register a function to be called to handle the specific endpoint, and most of the time, Flask infers the endpoint name from the function. Once registered in the mapping any next incoming request can be routed to the function for the given endpoint.
So, Flask keeps two maps:
from url route -> endpoint name: Flask.url_map
from endpoint name -> function: Flask.view_functions
That said, there is API for removing or changing url registrations (other than restarting your server, of course). You can’t change the url route, the endpoint name for a given route or what endpoint maps to what function. The intention of the framework is that you register your routes early on when first starting your server, via code that runs directly when imported or when bound to the app (Blueprints and Flask extensions do the latter). The majority of Flask apps will create their Flask instance, register all their routes and extensions, then pass the instance to the WSGI server for request dispatch, and that’s it. But there is nothing in the implementation stopping you from registering more routes after this point.
If you want to register URL routes from database information, you have to take care of at least the following two things:
Register existing routes at start-up. Once you have a connection to your database established, retrieve the existing routes and register them.
If a new entry is added to the database, register a new route.
First of all: if I were to implement something like this I’d use one view function. You can always figure out what url rule was matched and what endpoint name this mapped to by looking at request.url_rule and request.endpoint, respectively.
Next, I’d explicitly generate endpoint names for each url rule from the database. Use the primary key in the name; you want to be able to find the database row from the endpoint name and vice versa. How you do this is up to you; let’s assume you know how to do this, and you have two functions for this named pk_from_endpoint() and endpoint_from_pk().
Your view function can then look like this:
from flask import request
def product_request(**kwargs):
key = pk_from_endpoint(request.endpoint)
row = database_query(key)
# … process request
You register a route for a given database row with:
app.add_url_route(row.url_config, endpoint_from_pk(row.id), product_request)
As mentioned, you can’t change URL registrations. But, as long as changes to these URLs are infrequent you could always add new registrations and for any old entries use abort(404) to return a 404 Not Found response.
That's not possible with Flask's routing system. The URL map is supposed to be defined at startup and not change after that.
However, if you have some specific path where you need the dynamic parts (e.g. /product/WHATEVER), then you can register a route for /product/<slug> and query the database within your view function.
That said, if you REALLY want URL rules in a DB, and do not mind connecting to your database during startup (usually that's ugly), then nothing stop you from querying the database at startup time and define the URL rules based on data from the DB. Quite ugly, but doable.
Example:
with app.app_context():
url_map = {u.endpoint: u.rule for u in URLRules.query}
#app.route(url_map['foo'])
def foo():
...
Of course doing so makes it harder to nicely structure your app unless you use app.add_url_rule() for all the endpoints in a single place instead of the #app.route() decorators.
Likewise with blueprints of course.
In a GCP Cloud Function using the Python environment, I'd like to get the entire actual http request URL. Normally, Flask exposes this via request.url. However, in the cloud function environment, the request object appears to be manipulated by GCP so that request.url does not provide the actual full URL, with query parameters. For instance, if I POST to my function at:
https://us-east1-my-project.cloudfunctions.net/func-name?test=true
the value of request.url is (note the scheme):
http://us-east1-my-project.cloudfunctions.net?test=true
I found nothing in the documentation that would explain this. It seems that the actual function name is available as an environment variable (FUNCTION_NAME), but I'd have to re-assemble the URL using this, including guessing/hoping the scheme was HTTPs, and it seems like an ugly way to go about it. Thanks.
I have a portion of my API that i am exposing using Bottle (http://bottlepy.org/docs/dev/index.html).
I am now looking to document these endpoints for the end user clients and am looking for a good solution. I am looking for something that is tightly integrated with my"routes" defined in the Bottle app so that any changes in the future keep in sync. The key areas i want to document are the HTTP method types that are accepted and the necessary query parameters.
I have included an example route below which queries whether an instance defined in the underlying API is online. As you can see the route only accepts GET requests, and the "check_valid_instance" function expects to find a query parameter. Looking at this route definition there is no indication that a query param is needed and that is what i am trying to add here! Both to the source code, and also externally to some type of help page
#app.route("/application/app_instance/is_instance_online", method="GET")
def is_instance_online():
_check_valid_instance()
function = eval("app_instance.is_instance_online")
return _process_request_for_function(function)
The above route would be called as following
http://IP:Port/applicaton/app_instance/is_instance_online?instance=instance_name
Any suggestions welcome!
Thanks!
For additional params you can create a structure similar to this:
COMMANDS = {'is_instance_online': {'mandatory_params': 'instance_name',
'description': 'command description'}}
self.bottle.route('/<command>', method='GET', commands=COMMANDS)(self.command_execute)
Then you should be able to generate JSON description of the whole API as shown below:
Automatic Generation of REST API description with json
I'd like to check the datastore first, to see if there is any data, and if not, then redirect to another page (most likely /admin). However, I don't want to rewrite the url mapping framework that is already there.
Is there some way to set a handler that will process all requests before they are mapped?
I'm using google app engine with Python 2.7 and webapp2.
Yes, you can override dispatch() with a custom class. In the example shown in the link, the new class name is MyHandler. This means that all of your request classes need to be derived from MyHandler instead of webapp2.RequestHandler. Since this is how you would implement Sessions, you can put your code in dispatch() before it calls webapp2.RequestHandler.dispatch(self). In other words, you probably want to replace webapp2.RequestHandler anyway.