MongoDB上手笔记3——写个简单的Restful API读写数据库

上一篇中设置好了db logs的两个用户,并尝试往collection gen1中写入了一条简单的document。使用上一篇中的同样的方法,又写入了新的两条document,现在gen1中有了三条document。

> db
logs
> db.gen1.find()
{ "_id" : ObjectId("56a0daabcf03a917cb662aef"), "time" : 1, "value" : 1 }
{ "_id" : ObjectId("56a0dab3cf03a917cb662af0"), "time" : 2, "value" : 2 }
{ "_id" : ObjectId("56a0dabacf03a917cb662af1"), "time" : 3, "value" : 3 }

在命令行中写js语句来操作mongoDB自然是可行的,可是有很多情况需要使用别的语言来读取数据库。js可能缺少某些别人造好的轮子,比如我想用python来做科学计算,数据存在mongoDB里面,我就需要用python的驱动来操作数据库。

提供这个功能的轮子已经有很多了,mongoEngine和pymongo之类的。但是代码变多之后,感觉维护变得比较麻烦。代码中往往操作数据库和进行计算的部分混合在一起,看着条理不是很清晰。

所以想是不是可以将两部分分开来做,中间用个什么东西连接起来。后来知道了很Fancy(大概?)的Restful API,于是想着可以把各个部分分开,中间用http连接起来。

于是用flask和做了个十分简单的Restful API,功能就只有读取db logs的collection gen1中的最新一条数据以及向其中写数据。

api的验证部分使用了最简单的basic http authentication。request header中的auth部分就只是使用了base64加密而已(都不能算得上加密吧),十分简陋,完全没有安全性。每次请求都会创建一个MongoClient,简单测试了一下,目前没看出来有什么性能影响。

# 创建MongoClient
mongo = MongoClient(host="localhost", port=27999)
# 使用创建的对象验证身份
mongo["logs"].authenticate(request.authorization.username, request.authorization.password)

以下就是所有的代码了,一共只有50行。

simple_restful.py

from flask import request
from flask_restful import Resource
from bson.json_util import loads, dumps
from flask_pymongo import MongoClient
from pymongo.errors import OperationFailure
from flask import Flask
from flask_restful import Api


class Data(Resource):
    def get(self):
        mongo = MongoClient(host="localhost", port=27999)
        try:
            mongo["logs"].authenticate(request.authorization.username, request.authorization.password)
            last_log = mongo["logs"]["gen1"].find().sort("_id", -1)[0]
            return {
                       "err": "False",
                       "message": "Successfully get data",
                       "result": {"data": dumps(last_log)}
            }
        except OperationFailure, err:
            return {
                "err": "True",
                "message": "Failed getting data",
                "result": err.details
            }

    def post(self):
        mongo = MongoClient(host="localhost", port=27999)
        try:
            mongo["logs"].authenticate(request.authorization.username, request.authorization.password)
            data = request.data
            l = loads(data)
            result = mongo["logs"]["gen1"].insert_one(l["data"])
            return {
                "err": "False",
                "message": "Successfully post data",
                "result": {"data": dumps(l["data"]), "ack": str(result.acknowledged)}
            }
        except OperationFailure, err:
            return {
                "err": "True",
                "message": "Failed post data",
                "result": err.details
            }

app = Flask(__name__)
api = Api(app)
api.add_resource(Data, '/data')
app.run(debug=True)

使用curl简单测试一下吧。

>curl -v -H "Content-Type: application/json" --user readwriter:123456 http://localhost:5000/data
* Adding handle: conn: 0x140cf10
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x140cf10) send_pipe: 1, recv_pipe: 0
* About to connect() to localhost port 5000 (#0)
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 5000 (#0)
* Server auth using Basic with user 'readwriter'
> GET /data HTTP/1.1
> Authorization: Basic cmVhZHdyaXRlcjoxMjM0NTY=
> User-Agent: curl/7.33.0
> Host: localhost:5000
> Accept: */*
> Content-Type: application/json
>
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Type: application/json
< Content-Length: 189
< Server: Werkzeug/0.11.3 Python/2.7.10
< Date: Thu, 21 Jan 2016 13:59:24 GMT
<
{
    "err": "False",
    "message": "Successfully get data",
    "result": {
        "data": "{\"_id\": {\"$oid\": \"56a0dabacf03a917cb662af1\"}, \"value\":
3.0, \"time\": 3.0}"
    }
}
* Closing connection 0

确实读出来了最新的一条document。再写入一条document试试。

C:\Users\Juiceyang\Desktop>curl -v -H "Content-Type: application/json" --user re
adwriter:123456 http://localhost:5000/data -X POST -d "{\"data\":{\"time\":4,\"v
alue\":4}}"
* Adding handle: conn: 0x85cf10
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x85cf10) send_pipe: 1, recv_pipe: 0
* About to connect() to localhost port 5000 (#0)
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 5000 (#0)
* Server auth using Basic with user 'readwriter'
> POST /data HTTP/1.1
> Authorization: Basic cmVhZHdyaXRlcjoxMjM0NTY=
> User-Agent: curl/7.33.0
> Host: localhost:5000
> Accept: */*
> Content-Type: application/json
> Content-Length: 29
>
* upload completely sent off: 29 out of 29 bytes
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Content-Type: application/json
< Content-Length: 210
< Server: Werkzeug/0.11.3 Python/2.7.10
< Date: Thu, 21 Jan 2016 14:02:58 GMT
<
{
    "err": "False",
    "message": "Successfully post data",
    "result": {
        "ack": "True",
        "data": "{\"_id\": {\"$oid\": \"56a0e512612bf10dcce366d7\"}, \"value\":
4, \"time\": 4}"
    }
}
* Closing connection 0

结果来看也确实写入成功了。