The implementation of flash restful API and the basic permission control based on flash httpauth

Posted by cmzone on Wed, 13 May 2020 14:22:53 +0200

This tutorial series is divided into three phases

1.flask restful web service

2. Flash restful API (to be updated)

3. Flash httpauth implements permission control (to be updated)

4.uwsgi management flash application (to be updated)

Article excerpted from http://www.pythodoc.com/flask-restful/

I corrected some of the procedural problems arising from the update of bug and its version, and removed the dross and extracted the essence.

Flask is a popular web development framework in python, so after using flask to do large and small projects, I want to make a blog. On the one hand, it is used to record key knowledge, on the other hand, it is also used by those who want to get started or understand python and flask.

----

This article requires the reader to have a certain foundation of python

----

  1. A flash applet (developed with pycharm)
from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
        return 'hello world'

if __name__ == (__main__):
        app.run(debug=True)

Description of some parameters above:

  1. From flash import
  2. App = flag (\\\\\\\\\
  3. @App. Route ('/') flag route annotator

    Run the above program to start a flash program. At this time, visit http://localhost:5000 to access the flash program.
    If you want to customize the port of the program, modify it in the last line as follows:

    app.run('0.0.0.0', 8080)
    Note: this method is only applicable to the python flash_app.py method. If you use the flash run method, it will not take effect. If you need to query the data yourself, the subsequent production environment will not use any direct operation method, but will use the agent management procedures such as uwsgi. We will introduce the related use of uwsgi later.

At this time, the program will start on the local port 8080;

What is REST?

Six design specifications define the characteristics of a REST system:

Client server: the client and server are isolated, the server provides services, and the client consumes.
Stateless: each request from the client to the server must contain the information necessary to understand the request. In other words, the server does not store the information the client requested the last time for the next time.
Cacheable: the server must indicate whether client requests can be cached.
Layered system: the communication between the client and the server should be in a standard way, that is, when the middle layer replaces the server to respond, the client does not need to make any changes.
Unified interface: the communication method between server and client must be unified.
On demand coding: the server can provide executable code or scripts for clients to execute in their environment. This constraint is the only one that is optional.

Using flash to implement restful services

The first entry to web services

#!flask/bin/python
from flask import Flask, jsonify

app = Flask(__name__)

tasks = [
    {
        'id': 1,
        'title': u'Buy groceries',
        'description': u'Milk, Cheese, Pizza, Fruit, Tylenol',
        'done': False
    },
    {
        'id': 2,
        'title': u'Learn Python',
        'description': u'Need to find a good Python tutorial on the web',
        'done': False
    }
]

@app.route('/todo/api/v1.0/tasks', methods=['GET'])
def get_tasks():
    return jsonify({'tasks': tasks})

if __name__ == '__main__':
    app.run(debug=True)

The above tasks list is our simulated data attribute. The interface return must be in json or str format, otherwise an error will be reported.
In @ app.route, we define the route of web URL access and the way of http request resources (methods). This involves a knowledge point, http request method. The common http request resource methods are listed below:

==========  ===============================================  =============================
HTTP method   URL                                              action
==========  ===============================================  ==============================
GET         http://[hostname]/todo/api/v1.0/tasks retrieve task list
GET         http://[hostname] / todo / API / v1.0 / tasks / [task [ID] retrieve a task
POST        http://[hostname]/todo/api/v1.0/tasks create a new task
PUT         http://[hostname]/todo/api/v1.0/tasks/[task_id] update task
DELETE      http://[hostname] / todo / API / v1.0 / tasks / [task [ID] delete task
==========  ================================================ =============================

Let's perform the next restful according to the common http request resource mode In the above example, we have implemented the first GET method to GET all the data in the task list, but most of the time, we don't need to show all the data on the page, just show part of the data, and then GET as many times as necessary. Then we use the second GET method, which should be GET route parameters.

Note: in the browser, all requests are GET methods. The HTTP methods are divided into the above several kinds. Most of the time, the front-end uses ajax/axios and other technical requests to obtain data and then renders the data to the page. Therefore, when testing restful services, it is recommended to use curl or use postman tools to do professional development tests.
Note: when using postman to call service, add content type: application / JSON to the request header

Here we use curl to access the tasks function we just created:

$ curl -i http://localhost:5000/todo/api/v1.0/tasks
# Result:
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 294
Server: Werkzeug/0.8.3 Python/2.7.3
Date: Mon, 20 May 2013 04:53:53 GMT
{
  "tasks": [
    {
      "description": "Milk, Cheese, Pizza, Fruit, Tylenol",
      "done": false,
      "id": 1,
      "title": "Buy groceries"
    },
    {
      "description": "Need to find a good Python tutorial on the web",
      "done": false,
      "id": 2,
      "title": "Learn Python"
    }
  ]
}


It can be seen that the tasks function just returns the tasks dictionary without any change. Next, we will try other operations on the data:
Get specified data, modify data, delete data

Get single task data:

@app.route('/todo/api/v1.0/tasks/<int:id>', methods=['GET'])
def get_task():
    task = list(filter(lambda t: t['id'] == task_id, tasks))
    if len(task) == 0:
                # abort(404)
        return jsonify({'error': 'no such data.'})
    return jsonify({'task': task[0]})


Here we use the filter() higher-order function and lambda to implement dictionary filtering, and map() function will be used later;

Note: in python3, you need to convert the filter() and map() functions to < list > before you can assign values. Otherwise, an error is reported.


To access the get task method:

# Access data with < ID > 2
$ curl -i http://localhost:5000/todo/api/v1.0/tasks/2
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 151
Server: Werkzeug/0.8.3 Python/2.7.3
Date: Mon, 20 May 2013 05:21:50 GMT
{
  "task": {
    "description": "Need to find a good Python tutorial on the web",
    "done": false,
    "id": 2,
    "title": "Learn Python"
  }
}

# Access to non-existent < ID > Data
$ curl -i http://localhost:5000/todo/api/v1.0/tasks/3
HTTP/1.0 404 NOT FOUND
Content-Type: text/html
Content-Length: 238
Server: Werkzeug/0.8.3 Python/2.7.3
Date: Mon, 20 May 2013 05:21:52 GMT

{'error': 'no such data.'}


In the above test, we conducted 2 visits, one for the data with <id> = 2 in the dictionary, and the other for the data with <id> = 3. We will see that the data return is user-friendly custom exception return. The abort method used in the original text is not recommended by the author. In practical application, we may have multiple interfaces that can not access the data and return 404 You don't want all 404 returns to be the following:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>404 Not Found</title>
<h1>Not Found</h1>

This is not friendly, and does not help us to effectively find problems in front-end development or self-test, so we can return the exception problems we defined through the return method.
Of course, here we also implement the custom abort exception method as follows:

from flask import make_response

@app.errorhandler(404)
def not_found(error):
    print(error)
    return make_response(jsonify({'error': 'Not found'}), 404)

explain:

@app.errorhandler(404) is the exception decorator in flask

The parameter error in the def not found (error) function definition cannot be left blank. The reason is very simple. The decorator will capture traceback and pass in the not found function. You can view the error and print the specific information by yourself.
The make? Response function returns a method for the flash service.


The corresponding abort return information is:

$ curl -i http://localhost:5000/todo/api/v1.0/tasks/3
HTTP/1.0 404 NOT FOUND
Content-Type: application/json
Content-Length: 26
Server: Werkzeug/0.8.3 Python/2.7.3
Date: Mon, 20 May 2013 05:36:54 GMT

{
  "error": "Not found"
}


The method of obtaining single data and exception handling of flask are described above. Next is POST method, which is generally used for data addition, update, form submission, etc. the methods are as follows:

from flask import request  #http request processing module to obtain request header, parameters, submission data and other information

@app.route('/todo/api/v1.0/tasks', methods=['POST'])
def create_task():
    if not request.json or not 'title' in request.json:
        return jsonify({'error': 'args not matching'})
    task = {
        'id': tasks[-1]['id'] + 1,
        'title': request.json['title'],
        'description': request.json.get('description', ""),
        'done': False
    }
    tasks.append(task)
    return jsonify({'task': task}), 201


Request the method:

$ curl -i -H "Content-Type: application/json" -X POST -d '{"title":"Read a book"}' http://localhost:5000/todo/api/v1.0/tasks
HTTP/1.0 201 Created
Content-Type: application/json
Content-Length: 104
Server: Werkzeug/0.8.3 Python/2.7.3
Date: Mon, 20 May 2013 05:56:21 GMT

{
  "task": {
    "description": "",
    "done": false,
    "id": 3,
    "title": "Read a book"
  }
}

Note: if you are running Cygwin's version of curl on Windows, the above command will not have any problems. However, if you use native curl, the commands are a little different:

curl -i -H "Content-Type: application/json" -X POST -d "{"""title""":"""Read a book"""}" http://localhost:5000/todo/api/v1.0/tasks


Request the GET method we just started to request data again, and check the data change:

$ curl -i http://localhost:5000/todo/api/v1.0/tasks
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 423
Server: Werkzeug/0.8.3 Python/2.7.3
Date: Mon, 20 May 2013 05:57:44 GMT

{
  "tasks": [
    {
      "description": "Milk, Cheese, Pizza, Fruit, Tylenol",
      "done": false,
      "id": 1,
      "title": "Buy groceries"
    },
    {
      "description": "Need to find a good Python tutorial on the web",
      "done": false,
      "id": 2,
      "title": "Learn Python"
    },
    {
      "description": "",
      "done": false,
      "id": 3,
      "title": "Read a book"
    }
  ]
}


At this time, you can see that in the original tasks dictionary defined by us, there are more new data with < ID > 3, indicating that our POST data adding interface is normal.

As for the remaining update and deletion methods, we will not explain them one by one, and the implementation methods are listed as follows:

@app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['PUT'])
def update_task(task_id):
    task = list(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': task[0]})

@app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['DELETE'])
def delete_task(task_id):
    task = list(filter(lambda t: t['id'] == task_id, tasks))
    if len(task) == 0:
        abort(404)
    tasks.remove(task[0])
    return jsonify({'result': True})


The above is the way that flash implements restful web services. Of course, flash can achieve much more than that. Here, it is just a good example. In the follow-up work and development, you will gradually find the charm and power of flash.

In the original text, the basic authentication of web services is introduced immediately. After thinking about it, the author decides not to explain it here. In the subsequent httpauth of restful services, the system will be introduced.


Write at the end:
Technology is a process of continuous improvement and learning. We must think and practice more while learning other people's things, so that we can become our own knowledge for subsequent realization.

Topics: Python JSON curl Lambda