Flask-RESTful API: multiple and complex endpoints

Asked
Active3 hr before
Viewed126 times

8 Answers

multiple
90%

With Flask-RESTful you will need to define a new Resource subclass for that, for example:,To implement the URL that gets users by city you add yet another Resource subclass:,Connect and share knowledge within a single location that is structured and easy to search.,you can do the id/name thing without duplicating the resource:

In your API you may want to expose the /api/users and /api/cities as top-level APIs. The URLs to individual cities and users will be included in the responses. For example, if I invoke http://example.com/api/users to get the list of users I may get this response:

{
   "users": [{
         "url": "http://example.com/api/user/1",
         "name": "John Smith",
         "city": "http://example.com/api/city/35"
      },
      {
         "url": "http://example.com/api/user/2",
         "name": "Susan Jones",
         "city": "http://example.com/api/city/2"
      }
   ]
}

With Flask-RESTful you will need to define a new Resource subclass for that, for example:

    class CitiesByNameAPI(Resource):
    def __init__(self):
    # ...
    def get(self, name):
    # ...

    api.add_resource(CitiesByNameAPI, '/api/cities/<name>', endpoint = 'cities_by_name')

When the client asks for a city it should get a response that includes a URL to get the users in that city. For example, let's say that from the /api/users response above I want to find out about the city of the first user. So now I send a request to http://example/api/city/35, and I get back the following JSON response:

{
   "url": "http://example.com/api/city/35",
   "name": "San Francisco",
   "users": "http://example/com/api/city/35/users"
}

To implement the URL that gets users by city you add yet another Resource subclass:

    class UsersByCityAPI(Resource):
    def __init__(self):
    # ...
    def get(self, id):
    # ...

    api.add_resource(UsersByCityAPI, '/api/cities/<int:id>/users', endpoint = 'users_by_city')
load more v
88%

Elsewhere in the documentation, we’ve described how to use the reqparse example in detail. Here we’ll set up a resource with multiple input parameters that exercise a larger amount of options. We’ll define a resource named “User”.,Intermediate Usage Project Structure Use With Blueprints Full Parameter Parsing Example Passing Constructor Parameters Into Resources ,The basic idea is to split your app into three main parts: the routes, the resources, and any common infrastructure.,That covers the inputs. We also defined some interesting field types in the user_fields dictionary to showcase a couple of the more exotic types.

myapi /
   __init__.py
app.py # this file contains your app and routes
resources /
   __init__.py
foo.py # contains logic
for / Foo
bar.py # contains logic
for / Bar
common /
   __init__.py
util.py # just some common infrastructure
load more v
72%

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:,Question How can I have two @GET endpoints in same resource class?,and then to register the resource,You can't have two different GET endpoints on one resource class.

GET / users / uuid /
   # returns user

GET / users / uuid / financialmonthdetails
# returns a map like {
   'time_from': some_time,
   'time_to': some_time,
   'remaining_days': some_days
}
load more v
65%

Let's learn how to develop RESTful APIs with Python and Flask.,"Flask allows Python developers to create lightweight RESTful APIs.",Creating a RESTful Endpoint with Flask,Although well structured, our API is not that useful yet. Among the things that we can improve, we are going to cover the following topics in the next article:

Then use it in our endpoints:

# Controllers API

# This doesn 't need authentication
@app.route("/ping")
@cross_origin(headers = ['Content-Type', 'Authorization'])
def ping():
   return "All good. You don't need to be authenticated to call this"

# This does need authentication
@app.route("/secured/ping")
@cross_origin(headers = ['Content-Type', 'Authorization'])
@requires_auth
def secured_ping():
   return "All good. You only get this message if you're authenticated"
75%

原文 标签 python rest flask flask-restful restapi , python - flask restplus型号 ,关于python - Flask-RESTful API : multiple and complex endpoints,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20715238/ ,在我的 Flask-RESTful API 中,假设我有两个对象,用户和城市。这是一个一对多的关系。现在,当我创建 API 并向其添加资源时,我似乎所能做的就是将非常简单且通用的 URL 映射到它们。这是代码(不包括无用的东西):

在我的 Flask-RESTful API 中,假设我有两个对象,用户和城市。这是一个一对多的关系。现在,当我创建 API 并向其添加资源时,我似乎所能做的就是将非常简单且通用的 URL 映射到它们。这是代码(不包括无用的东西):

class UserAPI(Resource): # The API class that handles a single user
def __init__(self):
# Initialize

def get(self, id):
# GET requests

def put(self, id):
# PUT requests

def delete(self, id):
# DELETE requests

class UserListAPI(Resource): # The API class that handles the whole group of Users
def __init__(self):

def get(self):

def post(self):

api.add_resource(UserAPI, '/api/user/<int:id>', endpoint='user')
   api.add_resource(UserListAPI, '/api/users/', endpoint='users')

   class CityAPI(Resource):
   def __init__(self):

   def get(self, id):

   def put(self, id):

   def delete(self, id):

   class CityListAPI(Resource):
   def __init__(self):

   def get(self):

   def post(self):

   api.add_resource(CityListAPI, '/api/cities/', endpoint='cities')
   api.add_resource(CityAPI, '/api/city/<int:id>', endpoint='city')
load more v
40%

Flask-RESTful routing,Flask-RESTful documentation,GET - get information about the addressed product,"storage:delete" - a control to delete the addressed product, see previous task

[{
   "handle": "donkey plushie",
   "weight": 1.20,
   "price": 20.0
}]
load more v
22%

60%

The add_resource function registers the routes with the framework using the given endpoint. If an endpoint isn't given then Flask-RESTful generates one for you from the class name, but since sometimes the endpoint is needed for functions such as url_for I prefer to make it explicit.,Here I have to make sure the data given with the request is valid before using it, and that makes the function pretty long.,This is the third article in which I explore different aspects of writing RESTful APIs using the Flask microframework. Here is the first, and the second.,In my first RESTful server example (source code here) I have used regular Flask view functions to define all the routes.

Flask-RESTful provides a Resource base class that can define the routing for one or more HTTP methods for a given URL. For example, to define a User resource with GET, PUT and DELETE methods you would write:

from flask import Flask
from flask_restful import Api, Resource

app = Flask(__name__)
api = Api(app)

class UserAPI(Resource):
def get(self, id):
pass

def put(self, id):
pass

def delete(self, id):
pass

api.add_resource(UserAPI, '/users/<int:id>', endpoint = 'user')

My ToDo API defines two URLs: /todo/api/v1.0/tasks for the list of tasks, and /todo/api/v1.0/tasks/<int:id> for an individual task. Since Flask-RESTful's Resource class can wrap a single URL this server will need two resources:

class TaskListAPI(Resource):
def get(self):
pass

def post(self):
pass

class TaskAPI(Resource):
def get(self, id):
pass

def put(self, id):
pass

def delete(self, id):
pass

api.add_resource(TaskListAPI, '/todo/api/v1.0/tasks', endpoint = 'tasks')
api.add_resource(TaskAPI, '/todo/api/v1.0/tasks/<int:id>', endpoint = 'task')

When I implemented this server in the previous article I did my own validation of the request data. For example, look at how long the PUT handler is in that version:

@app.route('/todo/api/v1.0/tasks/<int:task_id>', methods = ['PUT'])
@auth.login_required
def update_task(task_id):
    task = filter(lambda t: t['id'] == task_id, tasks)
    if len(task) == 0:
        abort(404)
    if not request.json:
        abort(400)
    if 'title' in request.json and type(request.json['title']) != unicode:
        abort(400)
    if 'description' in request.json and type(request.json['description']) is not unicode:
        abort(400)
    if 'done' in request.json and type(request.json['done']) is not bool:
        abort(400)
    task[0]['title'] = request.json.get('title', task[0]['title'])
    task[0]['description'] = request.json.get('description', task[0]['description'])
    task[0]['done'] = request.json.get('done', task[0]['done'])
    return jsonify( { 'task': make_public_task(task[0]) } )

First, for each resource I define the arguments and how to validate them:

from flask_restful
import reqparse

class TaskListAPI(Resource):
   def __init__(self):
   self.reqparse = reqparse.RequestParser()
self.reqparse.add_argument('title', type = str, required = True,
   help = 'No task title provided', location = 'json')
self.reqparse.add_argument('description', type = str,
   default = "", location = 'json')
super(TaskListAPI, self).__init__()

#...

   class TaskAPI(Resource):
   def __init__(self):
   self.reqparse = reqparse.RequestParser()
self.reqparse.add_argument('title', type = str, location = 'json')
self.reqparse.add_argument('description', type = str, location = 'json')
self.reqparse.add_argument('done', type = bool, location = 'json')
super(TaskAPI, self).__init__()

#...

Now that the request parsers are initialized, parsing and validating a request is pretty easy. For example, note how much simpler the TaskAPI.put() method becomes:

    def put(self, id):
       task = filter(lambda t: t['id'] == id, tasks)
    if len(task) == 0:
       abort(404)
    task = task[0]
    args = self.reqparse.parse_args()
    for k, v in args.iteritems():
       if v != None:
       task[k] = v
    return jsonify({
       'task': make_public_task(task)
    })

My original REST server generates the responses using Flask's jsonify helper function. Flask-RESTful automatically handles the conversion to JSON, so instead of this:

        return jsonify({
           'task': make_public_task(task)
        })

I can do this:

        return {
           'task': make_public_task(task)
        }

Flask-RESTful also supports passing a custom status code back when necessary:

        return {
           'task': make_public_task(task)
        }, 201

But there is more. The make_public_task wrapper from the original server converted a task from its internal representation to the external representation that clients expected. The conversion included removing the id field and adding a uri field in its place. Flask-RESTful provides a helper function to do this in a much more elegant way that not only generates the uri but also does type conversion on the remaining fields:

from flask_restful
import fields, marshal

task_fields = {
   'title': fields.String,
   'description': fields.String,
   'done': fields.Boolean,
   'uri': fields.Url('task')
}

class TaskAPI(Resource):
   #...

   def put(self, id):
   #...
   return {
      'task': marshal(task, task_fields)
   }

Since the Resouce class inherits from Flask's MethodView, it is possible to attach decorators to the methods by defining a decorators class variable:

from flask_httpauth
import HTTPBasicAuth
#...
   auth = HTTPBasicAuth()
#...

   class TaskAPI(Resource):
   decorators = [auth.login_required]
#...

   class TaskAPI(Resource):
   decorators = [auth.login_required]
#...
load more v

Other "multiple-undefined" queries related to "Flask-RESTful API: multiple and complex endpoints"