Flask-RESTful custom routes other than GET,PUT,POST,DELETE
Question:
In Flask-RESTful we add an api route like the below
api.add_resource(CuteKitty,'/api/kitty')
class CuteKitty(Resource):
def get(self): return {}
def post(self): return {}
def put(self): return {}
def delete(self): return None, 204
so that GET /api/kitty
–> to CuteKitty.get()
method; like this for all HTTP verbs
Lets say that I need to provide my api consumers with a cute api like
POST /api/kitty/drink/milk ---> CuteKitty.drink(what="milk")
POST /api/kitty/meow ---> CuteKitty.meow()
How can i achive the above routing with api.add_resource
class CuteKitty(Resource):
def get(self): return {}
def post(self): return {}
def put(self): return {}
def delete(self): return None, 204
def drink(self,what="milk"): return {}
def meow(self): return {}
Like wise how to add route like /api/kitty/<int:kitty_id>/habits
–> CuteKitty.habits(kitty_id)
Answers:
Flask-RESTful is designed to implement RESTful APIs specifically by interpreting the HTTP Request method. Drink and Meow are not standard HTTP methods so Flask-RESTful isn’t concerned with the drink
and meow
methods in the resource.
The solution to this is to define multiple API routes:
api.add_resource(CuteKitty, '/kitty/<int:kitty_id>/')
api.add_resource(DrinkingKitty, '/kitty/<int:kitty_id>/drink/<what>')
api.add_resource(MeowingKitty, '/kitty/<int:kitty_id>/meow/')
The less intuitive (and imo far worse) way is by creating a frankenresource:
# still allow requests to hit just get/post/etc without invoking anything else
api.add_resource(CuteKitty, '/kitty/<int:kitty_id>/')
api.add_resource(CuteKitty, '/kitty/<int:kitty_id>/<task>/<path:args>/')
And then break the args with split('/')
and call task with them. Alternatively, you could set these as URL arguments (/endpoint/?task=drink&what=milk
) — which is still a valid RESTful architecture.
You could also subclass the Resource class and implement the desired functionality yourself — in this case, I’d recommend looking at how Flask-Classy implements this. Or you could pick up Flask-Classy and toy with it and see how you like that, too; however, for a straight up API I think RESTful brings a lot more to the table than Classy.
Step 1: Write the Resource class.
class CuteKitty(Resource):
def get(self): return {}
def post(self): return {}
def put(self): return {}
def delete(self): return None, 204
def meow(self): return {}
Step 2: Below the class, or after obtaining the callable,
api.add_resource(CuteKitty,'/api/kitty/meow',endpoint='meow',methods=['GET'])
This can help; saves you the stress of unnecessarily writing new classes whose methods should belong to a single class
from flask_restful import (
Resource,
request
)
import logging
class AuthViews(Resource):
logging.basicConfig(level=logging.INFO)
logging.info("Entered the auth views...")
def login(self):
print("nt Login route....")
def register(self):
print("nt Register route....")
def post(self):
print("nt post-Data: ", request.data)
print("nt url-Data: ", request.url)
url = request.url
if "login" in url:
login = self.login()
elif "register" in url:
register = self.register()
elif "forgot-password" in url:
forgot_password = self.register()
else:
...etc
When you’re done, you could define all the routes concerned with this class as
auth_routes = ["/auth/login", "/auth/register", "/auth/forgot-password"]
Then in your app instantiation, you’d say;
app = Flask(__name__)
api = Api(app)
api.add_resource(AuthViews, *auth_routes)
In Flask-RESTful we add an api route like the below
api.add_resource(CuteKitty,'/api/kitty')
class CuteKitty(Resource):
def get(self): return {}
def post(self): return {}
def put(self): return {}
def delete(self): return None, 204
so that GET /api/kitty
–> to CuteKitty.get()
method; like this for all HTTP verbs
Lets say that I need to provide my api consumers with a cute api like
POST /api/kitty/drink/milk ---> CuteKitty.drink(what="milk")
POST /api/kitty/meow ---> CuteKitty.meow()
How can i achive the above routing with api.add_resource
class CuteKitty(Resource):
def get(self): return {}
def post(self): return {}
def put(self): return {}
def delete(self): return None, 204
def drink(self,what="milk"): return {}
def meow(self): return {}
Like wise how to add route like /api/kitty/<int:kitty_id>/habits
–> CuteKitty.habits(kitty_id)
Flask-RESTful is designed to implement RESTful APIs specifically by interpreting the HTTP Request method. Drink and Meow are not standard HTTP methods so Flask-RESTful isn’t concerned with the drink
and meow
methods in the resource.
The solution to this is to define multiple API routes:
api.add_resource(CuteKitty, '/kitty/<int:kitty_id>/')
api.add_resource(DrinkingKitty, '/kitty/<int:kitty_id>/drink/<what>')
api.add_resource(MeowingKitty, '/kitty/<int:kitty_id>/meow/')
The less intuitive (and imo far worse) way is by creating a frankenresource:
# still allow requests to hit just get/post/etc without invoking anything else
api.add_resource(CuteKitty, '/kitty/<int:kitty_id>/')
api.add_resource(CuteKitty, '/kitty/<int:kitty_id>/<task>/<path:args>/')
And then break the args with split('/')
and call task with them. Alternatively, you could set these as URL arguments (/endpoint/?task=drink&what=milk
) — which is still a valid RESTful architecture.
You could also subclass the Resource class and implement the desired functionality yourself — in this case, I’d recommend looking at how Flask-Classy implements this. Or you could pick up Flask-Classy and toy with it and see how you like that, too; however, for a straight up API I think RESTful brings a lot more to the table than Classy.
Step 1: Write the Resource class.
class CuteKitty(Resource):
def get(self): return {}
def post(self): return {}
def put(self): return {}
def delete(self): return None, 204
def meow(self): return {}
Step 2: Below the class, or after obtaining the callable,
api.add_resource(CuteKitty,'/api/kitty/meow',endpoint='meow',methods=['GET'])
This can help; saves you the stress of unnecessarily writing new classes whose methods should belong to a single class
from flask_restful import (
Resource,
request
)
import logging
class AuthViews(Resource):
logging.basicConfig(level=logging.INFO)
logging.info("Entered the auth views...")
def login(self):
print("nt Login route....")
def register(self):
print("nt Register route....")
def post(self):
print("nt post-Data: ", request.data)
print("nt url-Data: ", request.url)
url = request.url
if "login" in url:
login = self.login()
elif "register" in url:
register = self.register()
elif "forgot-password" in url:
forgot_password = self.register()
else:
...etc
When you’re done, you could define all the routes concerned with this class as
auth_routes = ["/auth/login", "/auth/register", "/auth/forgot-password"]
Then in your app instantiation, you’d say;
app = Flask(__name__)
api = Api(app)
api.add_resource(AuthViews, *auth_routes)