Comments (24)
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.
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.
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.
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.
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 GET
s?
from flask-restful.
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 GET
s for a given resource because that's not supported in REST.
from flask-restful.
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.
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.
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.
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 andUser
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.
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.
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.
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.
@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.
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.
I think I understand you now, Thank you @dougblack
from flask-restful.
Great points! Thanks @frankstratton.
from flask-restful.
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.
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.
How can I create POST, GET, PUT on one resource in flask restful??
from flask-restful.
@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.
@neelay-shah,You solved the issue ?
from flask-restful.
What if I have PATCH request. And all wanting to do separate things.
from flask-restful.
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 andUser
for the second. I feel this is not only redundant but breaks encapsulation and good modularity.
I have hacked around this by doingclass 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)
- Potential memory leak in flask_restful.reqparse ??? HOT 1
- how to get request.files attribute after flask send_from_directory?
- Return custom error code HOT 1
- Swagger doc like FastAPI HOT 2
- Did not attempt to load JSON data because the request Content-Type was not 'application/json'. HOT 6
- Is expected behavior of flask_restful abort() correct ? HOT 1
- Question: optional/wildcard url parameter HOT 1
- Flask 2.3 Incompatibility: app.propagate_exceptions is depreciated HOT 1
- test_client.get() with query_string doesn't work HOT 1
- The app.propagate_exceptions will be deprecated in Flask 2.3
- Using reqparse.add_argument() with default location parameter to parse requests with Content-Type other than "application/json" raises an exception when using Werkzeug>=2.1.0 HOT 3
- @api.resource is used in blueprint that it is not working HOT 1
- test_redirect failure HOT 1
- sdist is missing `tox.ini`
- This is alive? HOT 1
- response header "Server' cannot modified
- Is flask-restful dead? HOT 2
- Questions about Copilot + Open Source Software Hierarchy
- Documentation out of date for compatible Python versions
- Flask-RESTful breaks with Flask 2.3 and newer HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from flask-restful.