13

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)

cackharot
  • 688
  • 1
  • 6
  • 13

3 Answers3

22

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.

justanr
  • 700
  • 7
  • 13
  • This clears a lot of confusion I had, but I just thought that if by any chance I can have all the code belonging to `CuteKitty` in a single file/class, it seems the REST-ful does not allow that. I also don't what to write lot of boiler plate code myself for `/endpoint///`. I guess I will stick with writing many class as of now. Thanks @justanr! – cackharot Sep 15 '14 at 04:33
3

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'])
Henshal B
  • 1,540
  • 12
  • 13
0

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("\n\t Login route....")


    def register(self):
        print("\n\t Register route....")
        

    def post(self):
        print("\n\t post-Data: ", request.data)
        print("\n\t 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)
Chukwunazaekpere
  • 906
  • 1
  • 6
  • 13