Reputation: 1867
The below works in Flask-Classful (it's a maintained fork of the now-abandoned Flask-Classy), but I was wondering if there is a "native" version of the logic I have for the last two routes in Flask-Classful, without mixing Flask routes and Flask-Classful built-in special methods like get()
and post()
?
From the extensive documentation Flask-Classy has at https://pythonhosted.org/Flask-Classy/ I unfortunately couldn't spot an example for the last two routes in the below code, which would be eg. GET /news/123/comments/
and GET /news/123/comments/321
. There were some examples for cases that would be like GET /news/comments/123
, but not for when you have two variables you pick from the route URI (which will be used for DB queries).
from flask_classful import FlaskView, route
class NewsView(FlaskView):
def index(self):
return "This is GET /news\n"
def get(self, news_id):
return "This is GET /news/{}\n".format(news_id)
def post(self):
return "This is POST /news\n"
def put(self, news_id):
return "This is PUT /news/{}\n".format(news_id)
def patch(self, news_id):
return "This is PATCH /news/{}\n".format(news_id)
def delete(self, news_id):
return "This is DELETE /news/{}\n".format(news_id)
@route("/<int:news_id>/comments/<int:comment_id>", methods=["GET"])
def news_comment(self, news_id, comment_id):
return "This is GET /news/{}/comments/{}\n".format(news_id, comment_id)
@route("/<int:news_id>/comments/", methods=["GET"])
def news_comments(self, news_id):
return "This is GET /news/{}/comments/\n".format(news_id)
The routes are registered with:
def register_views(app):
api_path = "/api/1.0"
from apps.news.views import NewsView
NewsView.register(app, route_base="{}/news/".format(api_path))
It seems to work though. Maybe it's just splitting hairs, but I would think something like this would have built-in support in Flask-Classful?
Here's some test requests, where it works:
$ curl -X GET https://localhost:443/api/1.0/news/ --insecure -L
This is GET /news
$ curl -X GET https://localhost:443/api/1.0/news/123 --insecure -L
This is GET /news/123
$ curl -X POST https://localhost:443/api/1.0/news/ --insecure -L
This is POST /news
$ curl -X PUT https://localhost:443/api/1.0/news/123 --insecure -L
This is PUT /news/123
$ curl -X PATCH https://localhost:443/api/1.0/news/123 --insecure -L
This is PATCH /news/123
$ curl -X DELETE https://localhost:443/api/1.0/news/123 --insecure -L
This is DELETE /news/123
$ curl -X GET https://localhost:443/api/1.0/news/1/comments/ --insecure -L
This is GET /news/1/comments/
$ curl -X GET https://localhost:443/api/1.0/news/1/comments/2 --insecure -L
This is GET /news/1/comments/2
Upvotes: 2
Views: 3410
Reputation: 146510
By default when you create a method using some name
class NewsView(FlaskView):
def comments(self, news_id, comment_id):
pass
The above by default will register it as /comments/<news_id>/<comment_id>
and since your base route is news/
. The final route to the comments method would become news/comments/<news_id>/<comment_id>
.
But then who stops us from changing that?
from flask import Flask, request, jsonify
import json
from flask_classy import FlaskView
app = Flask(__name__)
class MyFlaskView(FlaskView):
@classmethod
def build_rule(cls, rule, method=None):
path = super(MyFlaskView, cls).build_rule(rule, method)
parts = path.split("/")
if len(parts) >= 3 and parts[-1].startswith("<") and parts[-2].startswith("<"):
parts[-3], parts[-2] = parts[-2], parts[-3]
return "/".join(parts)
return path
class NewsView(MyFlaskView):
def comments(self, news_id, comment_id):
return "This is GET /news\n"
def get(self, news_id):
return "This is GET /news2\n"
if __name__ == "__main__":
NewsView.register(app, route_base="news/")
app.run(debug=True)
This overridden method will register your route as /news/<news_id>/comments/<comment_id>
Upvotes: 4