Giter Club home page Giter Club logo

Comments (24)

dougblack avatar dougblack commented on June 22, 2024 53

Generally, RESTful APIs have List and Instance resources. It's uncommon for the List resource to have the same functionality as the Instance resource and thus they're recognized as two separate things. You can see this just by looking at your above example. You're supporting GET, PATCH, and DELETE on the Instance resource but only GET and POST on the List resource. Why didn't you add support for DELETE on /users? Because you correctly reasoned that deleting the List resource doesn't make sense. So we've got diverging functionality on a basic level--sounds like it's time to break things into classes! :)

Here's how I'd do what you're trying to accomplish.

class Users(Resource):
    def get(self):
        return users
    def post(self):
        #...

class User(Resource):
    def get(self, id=None):
        return find_user_by_id(id)
    def post(self):
        #...

api.add_resource(Users, '/users')
api.add_resource(User, '/users/<id>')

This is a perfectly normal way to build your API.

If you find yourself wanting support for multiple GET methods on a resource, chances are you're not being RESTful and should probably reevaluate your design.

from flask-restful.

dtheodor avatar dtheodor commented on June 22, 2024 48

What about the /users and /users/Tom urls, shouldn't they belong to the same resource? Following the flask-restful example you need to create two seperate resources to handle this situation, Users for the first url and User for the second. I feel this is not only redundant but breaks encapsulation and good modularity.

I have hacked around this by doing

class User(Resource):
    def get(self, id=None):
        if id is None:
            return users
        else:
            return user
    def post(self):
        #....

and then to register the resource

api.add_resource(User, '/users', methods=['GET', 'POST'])
api.add_resource(User, '/users/<id>', methods=['GET', 'PATCH', 'DELETE'])

but this breaks with Flask 0.10

from flask-restful.

dougblack avatar dougblack commented on June 22, 2024 42

You can't have two different GET endpoints on one resource class.

To support GETs on those two routes, you'll need to break them into two different resources. It seems like you want to have a User resource and a FinancialMonth resource.

from flask-restful.

frankstratton avatar frankstratton commented on June 22, 2024 40

Just to follow up on @dtheodor's comment.

Your way is fine if you're okay managing the optional parameter. The issue in flask 0.10 is having conflicting endpoint names registered. By default flask-restful uses the classname as the endpoint but you can overwrite it as follows:

api.add_resource(User, '/users', endpoint="users")
api.add_resource(User, '/users/<id>', endpoint="user")

Also note that you don't need to specify methods as they are taken care of by the method functions you write/don't write in your Resource class.

from flask-restful.

harit-sunrun avatar harit-sunrun commented on June 22, 2024 15

I see, Although I am not sure what the roadmap looks like for the project, but don't you think one resource should be able to support multiple GETs?

from flask-restful.

dougblack avatar dougblack commented on June 22, 2024 15

I don't. Flask-RESTful is designed to make it very easy for users to design RESTful APIs. REST APIs have just one URL for a given resource. In a RESTful API, the two URLs in the example you provided above would be two separate resources and therefore would map to two separate classes each with their own implementation of the get method. A User isn't the same thing as a FinancialMonth, so you'd want to have two separate classes.

Basically, Flask-RESTful won't support multiple GETs for a given resource because that's not supported in REST.

from flask-restful.

slisznia avatar slisznia commented on June 22, 2024 13

If you look at the JAX-RS v1.1 specification and implementation of it such as Apache Wink, you will notice that handling multiple GETs in a single resource class is allowed and makes complete sense.

Lacking support for this pattern is a major inconvenience.

from flask-restful.

dtheodor avatar dtheodor commented on June 22, 2024 12

I understand the different behavior between List and Instance resources, as you correctly point out. However, a Resource class in a real application (i.e. not example/tutorial material) is a unit of modularity that encapsulates much more than the HTTP verbs. It will use authentication, access lists, common database-related calls, exception handling, and more often than not these are identical among both List and Instance. Therefore, you are ending up duplicating code to apply it in both classes, and having to change things twice when changes are needed.

Anyway, things work as they are now, but this is an interesting discussion on design, which can always turn philosophical unless someone presents a concrete problem with the current design, which I don't really have at the moment.

from flask-restful.

neelay-shah avatar neelay-shah commented on June 22, 2024 12

what would you suggest to get user by id and email which belongs to same resource
/user/id/{user_id}
/user/email/{user_email}

from flask-restful.

rsanath avatar rsanath commented on June 22, 2024 9

What about the /users and /users/Tom urls, shouldn't they belong to the same resource? Following the flask-restful example you need to create two seperate resources to handle this situation, Users for the first url and User for the second. I feel this is not only redundant but breaks encapsulation and good modularity.

I have hacked around this by doing

class User(Resource):
    def get(self, id=None):
        if id is None:
            return users
        else:
            return user
    def post(self):
        #....

and then to register the resource

api.add_resource(User, '/users', methods=['GET', 'POST'])
api.add_resource(User, '/users/<id>', methods=['GET', 'PATCH', 'DELETE'])

but this breaks with Flask 0.10

Is there any other extension for Flask that respects this method?
I'm tired of searching for a good library to build restful API with Flask

from flask-restful.

binarytrails avatar binarytrails commented on June 22, 2024 7

I'm late to the party...

However, it is totally double! I admit that it wasn't clear. As you see below, you have to define many routes for one resource and then set None the arguments which vary:

...
self.api.add_resource(account.AccountsCodecs,
            '/accounts/<account_id>/codecs/',
            '/accounts/<account_id>/codecs/<codec_id>/',
...
class AccountsCodecs(Resource):
...
    def get(self, account_id, codec_id=None):
        if (codec_id is not None):
            ...
....

Good luck!

Taken from https://github.com/sevaivanov/ring-api/.

from flask-restful.

dougblack avatar dougblack commented on June 22, 2024 4

Sure, let's take a look.

Let's think about what those two routes might be for.

GET /object
GET /object/<type>/<name>

Based on your description it seems that object is actually a ListResource that returns multiple instances of some other object. It also sounds like the second route is used to filter the list by type and name. At Twilio, we accomplish this by using query parameters to define the filter. So instead of encoding the filter parameters type and name in the URL, you'd include them in the query parameters:

GET /object?type=mytype&name=myname

If all of the assumptions I've made are correct, this would solve your problem, and you'd still be able to only have one get method. It might look something like this:

from flask import Flask, request
from flask.ext import restful

class ObjectResource(restful.Resource):
    def get(self):
        obj_type = request.args.get('type', "")
        obj_name = request.args.get('name', "")
        objects = db.filter(type=obj_type, name=obj_name)

app = Flask(__name__)
api = restful.Api(app)
api.add_resource(ObjectResource, '/object')

Alternatively, if you really want to use the URL to capture those parameters, you could do something like this:

from flask import Flask, request
from flask.ext import restful

class ObjectResource(restful.Resource):
    def get(self, type, name):
        objects = db.filter(type=obj_type, name=obj_name)

app = Flask(__name__)
api = restful.Api(app)
api.add_resource(
    ObjectResource, 
    '/object', 
    '/object/<type>/<name>', 
    defaults={'type': '', 'name': ''}
)

Let me know if this looks okay.

from flask-restful.

JohnLockwood avatar JohnLockwood commented on June 22, 2024 2

To me it seems like the tail of Flask's add_url_rule implementation is wagging the dog of our definitions of RESTful design here. Granted the GET case is open to debate, since GET in the list case often needs query parameters or some sort of qualifier in the route to explain what's being gotten. But having worked with both Java and Ruby in the past, neither one of which follow this convention as far as I know, it really made sense to me to have PUT, POST, DELETE, and two flavors of GET in the same Resource. I've create a GIST for a proof of concept of the solution, https://gist.github.com/JohnLockwood/d9fa9393be269322df1a .

Cheers.

from flask-restful.

Rooni avatar Rooni commented on June 22, 2024 1

@rayest
It's not really a nice way to structure your endpoint.
If you just expect either an email or a username you're probably better off writing a simple check for it so it allows both.

also that comment is almost 4 years old now

from flask-restful.

tday avatar tday commented on June 22, 2024 1

If anyone's looking here for a solution, Flask can now do this out of the box with MethodView (which is recommended as a replacement to Flask-RESTful's Resource) .

from flask-restful.

harit-sunrun avatar harit-sunrun commented on June 22, 2024

I think I understand you now, Thank you @dougblack

from flask-restful.

dougblack avatar dougblack commented on June 22, 2024

Great points! Thanks @frankstratton.

from flask-restful.

enewhuis avatar enewhuis commented on June 22, 2024

I'd like to open this question up again. What should we do if there really are two names for the same resource?

GET /object/
GET /object/<type>/<name>

...assuming <type>+<name> is a unique constraint (composite key). Here we can access the same resource using two different URIs. It seems quite natural to implement two gets on the same class because we're dealing with the same object in the server, the same representation of its state, the same behavior.

from flask-restful.

enewhuis avatar enewhuis commented on June 22, 2024

Somehow the was dropped from my intended post.

The two routes are actually:

GET /object/
GET /object//

And both refer to a single object and not a list resource. is a unique key over all objects and + is a unique composite key over all objects. Therefore there are two ways to uniquely identify the same object--either by specifying an or by specifying both a and --and I would like to expose both ways through a RESTful URL since there are separate use cases for both.

I suspect this is quite common because many relational-object mappers will use an object ID even though there may be other natural keys or composite keys that also uniquely identify an object.

On Oct 14, 2013, at 10:42 PM, Doug Black <[email protected]mailto:[email protected]> wrote:

Sure, let's take a look.

Let's think about what those two routes might be for.

GET /object
GET /object//

Based on your description it seems that object is actually a ListResource that returns multiple instances of some other object. It also sounds like the second route is used to filter the list by type and name. At Twilio, we accomplish this by using query parameters to define the filter. So instead of encoding the filter parameters type and name in the URL, you'd include them in the query parameters:

GET /object?type=mytype&name=myname

If all of the assumptions I've made are correct, this would solve your problem, and you'd still be able to only have one get method. It might look something like this:

from flask import Flask, request
from flask.ext import restful

class ObjectResource(restful.Resource):
def get(self):
obj_type = request.args.get('type', "")
obj_name = request.args.get('name', "")
objects = db.filter(type=obj_type, name=obj_name)

app = Flask(name)
api = restful.Api(app)
api.add_resource(ObjectResource, '/object')

Alternatively, if you really want to use the URL to capture those parameters, you could do something like this:

from flask import Flask, request
from flask.ext import restful

class ObjectResource(restful.Resource):
def get(self, type, name):
objects = db.filter(type=obj_type, name=obj_name)

app = Flask(name)
api = restful.Api(app)
api.add_resource(
ObjectResource,
'/object',
'/object//',
defaults={'type': '', 'name': ''}
)

Let me know if this looks okay.


Reply to this email directly or view it on GitHubhttps://github.com//issues/114#issuecomment-26307332.


This message (including any attachments) contains confidential information intended for a specific individual and purpose, and is protected by law. If you are not the intended recipient, you should delete this message. Any disclosure, copying, or distribution of this message, or the taking of any action based on it, is strictly prohibited. Unless specifically indicated, this message is not an offer to sell or a solicitation of any investment products or other financial product or service, an official confirmation of any transaction, or an official statement of StoneCastle. There is no guarantee that e-mail transmissions are secure or error-free as such transmissions can be intercepted, corrupted, lost or destroyed, or can arrive late or incomplete or can contain viruses. The sender does not accept liability for any errors or omissions in the contents, or delay in receipt, of this e-mail message or its attachments which arise in the course of its transmission or receipt, and does not guarantee that the message contains no viruses.

from flask-restful.

vimox-shah avatar vimox-shah commented on June 22, 2024

How can I create POST, GET, PUT on one resource in flask restful??

from flask-restful.

binarytrails avatar binarytrails commented on June 22, 2024

@vimox-shah look at my example and add your post, get & put methods into a class representing your resource by inheriting from a Resource parent class then, add the resource to your api instance and map your url arguments to the methods signatures and voilà! 🎉

from flask-restful.

rayest avatar rayest commented on June 22, 2024

@neelay-shah,You solved the issue ?

from flask-restful.

anshupitlia avatar anshupitlia commented on June 22, 2024

What if I have PATCH request. And all wanting to do separate things.

from flask-restful.

CaptainCsaba avatar CaptainCsaba commented on June 22, 2024

What about the /users and /users/Tom urls, shouldn't they belong to the same resource? Following the flask-restful example you need to create two seperate resources to handle this situation, Users for the first url and User for the second. I feel this is not only redundant but breaks encapsulation and good modularity.
I have hacked around this by doing

class User(Resource):
    def get(self, id=None):
        if id is None:
            return users
        else:
            return user
    def post(self):
        #....

and then to register the resource

api.add_resource(User, '/users', methods=['GET', 'POST'])
api.add_resource(User, '/users/<id>', methods=['GET', 'PATCH', 'DELETE'])

but this breaks with Flask 0.10

Is there any other extension for Flask that respects this method? I'm tired of searching for a good library to build restful API with Flask

Have you managed to find the extension, or workaround?

from flask-restful.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.