Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

如何实现其它语言的APIJSON? #38

Open
TommyLemon opened this issue Jun 20, 2018 · 21 comments
Open

如何实现其它语言的APIJSON? #38

TommyLemon opened this issue Jun 20, 2018 · 21 comments
Assignees
Labels

Comments

@TommyLemon
Copy link
Member

@TommyLemon TommyLemon commented Jun 20, 2018

一开始不要贪大求全,实现基础的功能就好,功能后面再完善、性能后面再优化。

可以参考Java版的实现,建议从这个版本做起
https://github.com/TommyLemon/APIJSON/tree/636fe2263c01acce4ad32751cbb8a579830d9f29

这个是最简单的实现,只有7个类,将JSON转换为SQL,但也能够实现最核心的 引用赋值、单表查询、数组分页查询 了。
先完成这个,后面再优化。如果直接实现复杂功能,很可能导致一大堆问题然后坚持不下去。

@TommyLemon
Copy link
Member Author

@TommyLemon TommyLemon commented Jun 20, 2018

image

建议步骤:

1.实现单表查询

{
    "User": {
        "sex": 1
    }
}

转换为

SELECT * FROM User WHERE sex = '1' LIMIT 1 OFFSET 0

ResultSet取第0条(总数最多1条),取出所有字段对应的值,封装为一个表对象返回:

{
    "id": 82002,
    "sex": 1,
    "name": "Happy~",
    "tag": "iOS",
    "head": "http://static.oschina.net/uploads/user/1174/2348263_50.png?t=1439773471000",
    "contactIdList": [
        82005,
        82001,
        38710
    ],
    "pictureList": [],
    "date": "2017-02-01 19:21:50.0"
}

替换原来的

{
    "sex": 1
}

2.实现数组查询

{
    "[]": {
        "count": 10,
        "page": 1,
        "User": {
            "sex": 1
        }
    }
}

转换为

SELECT * FROM User WHERE sex = '1' LIMIT 10 OFFSET 10

ResultSet取所有,封装为一个包含表对象的数组返回:

[
    {
        "User": {
            "id": 82005,
            "sex": 1,
            "name": "Jan",
            "tag": "AG",
            "head": "http://my.oschina.net/img/portrait.gif?t=1451961935000",
            "contactIdList": [
                82001,
                38710
            ],
            "pictureList": [],
            "date": "2017-02-01 19:21:50.0"
        }
    },
    {
        "User": {
            "id": 82006,
            "sex": 1,
            "name": "Meria",
            "head": "http://static.oschina.net/uploads/user/998/1997902_50.jpg?t=1407806577000",
            "contactIdList": [],
            "pictureList": [],
            "date": "2017-02-01 19:21:50.0"
        }
    }
]

替换原来的

{
    "count": 10,
    "page": 1,
    "User": {
        "sex": 1
    }
}

3.实现两张表 一对一 关联查询

{
    "Comment": {},
    "User": {
        "id@": "Comment/userId"
    }
}

先解析Comment,转换为

SELECT * FROM Comment LIMIT 1 OFFSET 0

ResultSet取第0条(总数最多1条),取出所有字段对应的值,封装为一个Comment表对象返回:

{
    "id": 4,
    "toId": 0,
    "userId": 38710,
    "momentId": 470,
    "date": "2017-02-01 19:20:50.0",
    "content": "This is a Content...-4"
}

然后解析User,解析到

"id@": "Comment/userId"

时,从Comment中取出userId,把以上键值对改为

"id": 38710

然后把User转换为

SELECT * FROM User WHERE id = '38710' LIMIT 1 OFFSET 0

ResultSet取第0条(总数最多1条),取出所有字段对应的值,封装为一个User表对象返回:

{
    "id": 38710,
    "sex": 0,
    "name": "TommyLemon",
    "tag": "Android&Java",
    "head": "http://static.oschina.net/uploads/user/1218/2437072_100.jpg?t=1461076033000",
    "contactIdList": [
        82003,
        82005,
        70793
    ],
    "pictureList": [
        "http://static.oschina.net/uploads/user/1218/2437072_100.jpg?t=1461076033000",
        "http://common.cnblogs.com/images/icon_weibo_24.png"
    ],
    "date": "2017-02-01 19:21:50.0"
}

4.实现两张表 一对多 关联查询

{
    "Moment": {},
    "[]": {
        "Comment": {
            "momentId@": "Moment/id"
        }
    }
}

5.实现两张表在数组内 一对一 关联查询

{
    "[]": {
        "Comment": {},
        "User": {
            "id@": "[]/Comment/userId"
        }
    }
}

其中

"id@": "[]/Comment/userId"

要根据Comment在数组中的位置index来动态变为

"id@": "[]/0/Comment/userId"
"id@": "[]/1/Comment/userId"

...

6.实现两张表在数组内 一对多 关联查询

7.实现SQL的 column, order by, group by等功能。

8.实现增、删、改

@TommyLemon
Copy link
Member Author

@TommyLemon TommyLemon commented Jun 20, 2018

由于不限制嵌套层级和组合方式,所以必须用递归实现,从数据库查到结果(一开始可模拟测试数据,省去连接数据库的过程)后替换掉原来的内容再返回。

递归时由于不知道键值对key:value中的key和value,所以需要判断key和value的格式。

{
    "[]": { // value 类型为 JSONObject  &&  key 以 [] 结束
        "User": { // value 类型为 JSONObject  &&  key 符合正则表达式  ^[A-Za-z]+$
            "sex": 1 // value 类型不为 JSONObject
        }
    }
}
@TommyLemon
Copy link
Member Author

@TommyLemon TommyLemon commented Jun 20, 2018

最简单的解析过程可以是:

1.Parser递归遍历 请求JSON,提取出每个 表对象JSON
2.Parser用 表对象JSON 封装SQLConfig,交给SQLExecutor
3.SQLExecutor用SQLConfig封装SQL语句,并连接数据库执行
4.SQLExecutor返回执行结果给Parser
5.Parser替换对应请求JSON中的对象

@TommyLemon
Copy link
Member Author

@TommyLemon TommyLemon commented Jul 4, 2018

APIJSON-C# Server:
创作不易,给热心的作者右上角点 Star 支持下吧 ^_^
https://github.com/liaozb/APIJSON.NET

@zeromake
Copy link

@zeromake zeromake commented Aug 9, 2018

@TommyLemon

上回说的python初步完成了 https://github.com/zeromake/restful_model 刚刚把单元测试写好。
json 的表现层完全自定义,都是为了对应 sql

import sqlalchemy as sa
from sanic import Sanic
from restful_model import DataBase
from restful_model.extend.sanic import ApiView

metadata = sa.MetaData()
# 这个model可以直接用工具连接数据库生成
User = sa.Table(
    'user',
    metadata,
    sa.Column(
        'id',
        sa.Integer,
        autoincrement=True,
        primary_key=True,
        nullable=False,
    ),
    sa.Column(
        'account',
        sa.String(16),
        nullable=False,
    ),
    sqlite_autoincrement=True,
)
# python 可以动态生成 class 后面想批量注册model到view也很简单
class UserView(ApiView):
    __model__ = User
    # 请求方法过滤
    # __method__ = ["get", "post"]
    # 过滤 where 或者查询字段,支持全局或单个方法过滤
    #__filter_keys__ = {"get": [["id"]]}
    # 中间件模式
    async def auth_filter(self, context: Context, next_filter):
        return await next_filter()
app = Sanic(__name__)
db = DataBase("sqlite:///db.db")
app.db = db

@app.listener('before_server_start')
async def setup_db(app, loop):
    if app.db.loop is None:
        app.db.loop = loop
        app.db.engine = await app.db.create_engine(echo=True)
        if not await app.db.exists_table(User.name):
            await app.db.create_table(User)

userView = UserView.as_view(app.db)
app.add_route(userView, "/user", HTTP_METHODS)
app.add_route(userView, "/user/<id:int>", HTTP_METHODS)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8000)
$ # create
$ curl -X POST http://127.0.0.1:8000/user \
-H 'content-type: application/json' \
-d '{ "account": "test1" }'
> {
    "status": 201,
    "message": "Insert ok!",
    "meta": {"count":1}
}
$ # select
$ curl -X GET http://127.0.0.1:8000/user
> {
    "status": 200,
    "message": "Query ok!",
    "data": [{
        "id": 1,
        "account": "test1"
    }]
}
$ # update
$ curl -X PUT http://127.0.0.1:8000/user \
-H 'content-type: application/json' \
-d '{"where": {"id": 1}, "values": {"account": "test2"}}'
> {
    "status": 201,
    "message": "Update ok!",
    "meta":{
        "count": 1
    }
}
$ curl -X GET http://127.0.0.1:8000/user
> {
    "status": 200,
    "message": "Query ok!",
    "data": [
        {"id": 1,"account": "test2"}
    ]
}
$ # delete
$ curl -X DELETE http://127.0.0.1:8000/user \
-H 'content-type: application/json' \
-d '{"id": 1}'
> {
    "status": 200,
    "message": "Delete ok!",
    "meta": {"count":1}
}
$ curl -X GET http://127.0.0.1:8000/user
> {
    "status": 200,
    "message": "Query ok!",
    "data": []
}

现在还是觉得权限管理不太给力,虽然用中间件模式,什么样的权限都做的了。

以及多表连接在想是提供一个 class 然后把多张表设置上去,url 和权限独立,还是像你的 APIJSON 全局注册所有表随意连接任意表。
我这个库就是一个 python 库,然后不对任意一个 web 框架强绑定。
现在写了 Sanic, Tornado 的支持。

后面有心情再考虑把 json 的表现层抽出来,做了 APIJSON 的 json 表现层。
现在还有个问题就是 Date 的格式化函数 sqlite, mysql, pg 每个都不一样,现在想要么都不用,全用 python 的格式..

@TommyLemon
Copy link
Member Author

@TommyLemon TommyLemon commented Aug 9, 2018

@zeromake 赞,已Star。
不过URL里不要加user等符号哦,应该放到请求JSON里面,方便传任意表名

{
    "User": {
        "id": 70793
    }
}
{
    "Moment": {
        "id": 12
    }
}

...
还能自由组合

{
    "Moment": {
        "id": 12
    },
    "User": {
        "id": 70793
    }
}

不知道User.id的情况下可以通过 引用赋值 得到

{
    "Moment": {
        "id": 12
    },
    "User": {
        "id@": "Moment/userId" // User.id = Moment.userId
    }
}
{
    "Moment": {
        "id": 12
    },
    "[]": {
        "User": {
            "id{}@": "Moment/praiseUserIdList" // json_contains(Moment.praiseUserIdList, User.id)
        }
    }
}

参考上面的 建议步骤设计规范

@TommyLemon
Copy link
Member Author

@TommyLemon TommyLemon commented Aug 9, 2018

@zeromake 你改好后我就在APIJSON主页加上这个项目的链接哈,和 C#版 一样
https://github.com/TommyLemon/APIJSON

@zeromake
Copy link

@zeromake zeromake commented Aug 9, 2018

@TommyLemon 我这个只是为了做基础控件的,对应某个表操作,全局可连接任意表的应当后面做一个单独的控制 view,全部由使用的人来选择是注册一个全局 url 进行控制,还是挂几个表view。后面都会做对应的包括单表和 APIJSON 的相同的全局可连接任意表。

@TommyLemon
Copy link
Member Author

@TommyLemon TommyLemon commented Aug 9, 2018

@zeromake 这样啊,非常期待,记得通知我哦,有问题欢迎找我交流

@zeromake
Copy link

@zeromake zeromake commented Aug 10, 2018

@TommyLemon
issues交流比较麻烦,base64解密防搜索引擎
加我 wx:YWZseTM5MA== ;或者qq:MzkwNzIwMDQ2

@TommyLemon
Copy link
Member Author

@TommyLemon TommyLemon commented Aug 10, 2018

@zeromake 可以

@TommyLemon
Copy link
Member Author

@TommyLemon TommyLemon commented Sep 27, 2018

APIJSON Node.js 版,基于 typeorm ,使用 TypeScript 实现。

创作不易,给热心的作者右上角点 Star 支持下吧 ^_^
https://github.com/TEsTsLA/apijson

@yuu2lee4
Copy link

@yuu2lee4 yuu2lee4 commented Sep 27, 2018

已赞 @TommyLemon

@TommyLemon
Copy link
Member Author

@TommyLemon TommyLemon commented Oct 22, 2018

已经有热心的开发者实现了 PHP 版的 APIJSON 🎉
创作不易,给作者点 Star 支持下吧^_^
https://github.com/orchie/apijson

@never615
Copy link

@never615 never615 commented Dec 8, 2018

@TommyLemon 这个PHP版没有实现吧...

@never615
Copy link

@never615 never615 commented Dec 10, 2018

建议出一个功能清单.md,放在每个语言实现的代码库里,实现的功能就划掉,这样比较清晰.

@yuhongshuai
Copy link

@yuhongshuai yuhongshuai commented Dec 12, 2018

有没有打算做非关系数据库mongodb的

@TommyLemon
Copy link
Member Author

@TommyLemon TommyLemon commented Dec 19, 2018

@yuhongshuai 暂时没有计划,后续可能支持。

@TommyLemon
Copy link
Member Author

@TommyLemon TommyLemon commented Dec 19, 2018

已经有热心的开发者实现了 Python 版的 APIJSON 🎉
经测试,除了基本的查询(分页、排序等),还实现了自动化的权限控制。
最近作者又新增了自动化 API post。

创作不易,给作者点 Star 支持下吧^_^
https://github.com/zhangchunlin/uliweb-apijson

@TommyLemon TommyLemon pinned this issue Jan 25, 2019
@TommyLemon TommyLemon self-assigned this Mar 2, 2019
@TommyLemon
Copy link
Member Author

@TommyLemon TommyLemon commented Mar 30, 2019

@never615
另一个 PHP 版 APIJSON,看起来功能比原来那个多不少,可以试试,点 Star 支持下吧^_^
https://github.com/qq547057827/apijson-php

@TommyLemon
Copy link
Member Author

@TommyLemon TommyLemon commented Jun 4, 2019

APIJSON Go 语言版 APIJSON
https://github.com/crazytaxi824/APIJSON

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
5 participants
You can’t perform that action at this time.