Skip to content
通过一套「访问控制规则」配置数据库访问,用一个 API 替代服务端 90% 的 APIs。
JavaScript TypeScript
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.github/workflows
examples
src
tests
.gitignore
.npmignore
README.md
package-lock.json
package.json
tsconfig.json

README.md

介绍

通过一套「访问控制规则」配置数据库访问,用一个 API 替代服务端 90% 的 APIs。

客户端使用 less-api 提供的 SDK,像操作数据库那样,直接读写相应的数据即可。

使用 less-api 可以让产品在 demo 期或发展初期的时候, 只投入极少的服务端工作,随着业务的发展,可以按需增加传统的 api 来代替,两者完全不冲突,取决于客户端调用方式。

场景

  • 用于快速开发 MVP,专注于客户端业务,极大程度减少服务端开发工作量
  • 用于云开发(BaaS)服务中,屏蔽云厂商的环境差异,亦方便由 BaaS 到自建 Server 的迁移

使用示例

    npm install less-api

服务端代码示例

const app = require('express')()
const { Entry, MongoAccessor } = require('less-api')
app.use(express.json())

// design the access control rules
const rules = {
    categories: {
        ".read": true,
        ".update": "$admin == true",
        ".add": "$admin == true",
        ".remove": "$admin == true"
    }
}

// init the less-api Entry & Db Accessor

const options = {
    useNewUrlParser: true,
    useUnifiedTopology: true,
    poolSize: 10
}
// @see https://mongodb.github.io/node-mongodb-native/3.3/reference/ecmascriptnext/connecting/
const accessor = new MongoAccessor('mydb', 'mongodb://localhost:27017', options)

const entry = new Entry(accessor)
entry.init()
entry.loadRules(rules)

app.post('/entry', async (req, res) => {
  const { admin, uid } = parseToken(req.headers['authorization'])

  // parse params
  const { action } = req.body
  const params = entry.parseParams(action, req.body)

  const injections = {
    $admin: admin,
    $userid: uid
  }

  // validate query
  const result = await entry.validate(params, injections)
  if (result.errors) {
    return res.send({
      code: 1,
      data: errors
    })
  }

  // execute query
  const data = await entry.execute(params)
  return res.send({
    code: 0,
    data
  })
})

app.listen(8080, () => console.log('listening on 8080'))

客户端使用

Less API Javascript Client SDK

    npm install less-api-client
const cloud = require('less-api-client').init({
    entryUrl: 'http://localhost:8080/entry',
    getAccessToken: () => localStorage.getItem('access_token')
})

const db = cloud.database()

// query documents
const cates = await db.collection('categories').get()

// query with options
const articles = await db.collection('articles')
    .where({})
    .orderBy({createdAt: 'asc'})
    .offset(0)
    .limit(20)
    .get()

// update document
const updated = await db.collection('articles').doc('the-doc-id').update({
    title: 'new-title'
})

参考客户端使用文档

数据访问安全规则示例

简单示例 1:简单博客
{
    "categories": {
        ".read": true,
        ".update": "$admin === true",
        ".add": "$admin === true",
        ".remove": "$admin === true"
    },
    "articles": {
        ".read": true,
        ".update": "$admin === true",
        ".add": "$admin === true",
        ".remove": "$admin === true"
    }
}
简单示例 2:多用户博客
{
    "articles": {
        ".read": true,
        ".update": "$userid && $userid === query.createdBy",
        ".add": "$userid && data.createdBy === $userid",
        ".remove": "$userid === query.createBy || $admin === true"
    }
}
复杂示例 1: 数据验证
{
    "articles": {
        ".add": {
            "condition": "$userid && data.createdBy === $userid",
            "data": {
                "title": {"length": [1, 64], "required": true},
                "content": {"length": [1, 4096]},
                "like": { "number": [0,], "default": 0}
            }
        },
        ".remove": "$userid === query.createBy || $admin === true"
    }
}
复杂示例 2:更高级的数据验证

场景介绍: 用户之间站内消息表访问规则

{
    "messages": {
        ".read": "$userid && ($userid === query.receiver || $userid === query.sender)",
        ".update": {
            "condition": "$userid && $userid === query.receiver",
            "data": {
                "read": {"in": [true, false]}
            }
        },
        ".add": {
            "condition": "$userid && $userid === data.sender",
            "data": {
                "content": {"length": [1, 20480], "required": true},
                "receiver": {"exists": {"collection": "users", "field": "_id"}},
                "read": { "in": [false], "default": false }
            }
        },
        ".remove": false
    }
}

运行测试

安装依赖

    npm i
    npm i mocha -g

单元测试

    mocha tests/units/*.test.js

数据库访问测试

使用 Docker 启动个测试数据库,等待mongo 启动成功

    docker pull mongo
    docker run -p 27017:27017 --name mongotest -d mongo

执行测试用例

    mocha tests/db/*.test.js

停止&删除 Mongo 实例

    docker rm -f mongotest

doing & todo

  • 实现「数据访问控制规则」 【Done】
  • 提供 JS 版客户端 SDK: less-api-client-js 【Done】
  • 实现服务端应用内数据操作事件,可订阅相应事件,触发更多自定义的业务逻辑
  • 基于 Mongo 的change watch, 实现客户端可订阅数据变更通知,服务端通过 websocket 向客户端实时推送数据变更
  • 提供 Android & iOS 客户端 SDK
  • 支持微信小程序云开发数据库
  • 支持 MySQL 等关系型数据库
You can’t perform that action at this time.