之前半年时间,来到项目的时候,已经有一些东西,大致就是IIS+MYSQL+PHP.
所以接着做,修修补补,Android/iOS与服务器数据库交换用PHP, Web那边则是JS+PHP,也没有前后端之分。本身并不是计算机方向的,所以也没有对这个框架做改动。可能本身没有用PHP的一些框架,总觉得写起来不是很爽快。
接下来的项目开始略有变化,因为我先开始做的一块,并不是直接做到C,而是后面可能会与其他部分存在数据交换(主要是从我这边获取数据),基于兴趣,也基于前后端分离的概念,因为后面可能会有有移动端和Web端都需要,所以我决定做一个RESTful的后端。
经过简单的学习就直接上手,利用Python Flask+Mysql+SqlAlchemy搭建一个后端(后面根据需要可能加上Redis),目前也还在完善中,写下来笔记先,错漏和理解错误在所难免,继续学习。
越来越觉得,Google/Baidu的搜索功能下,很多细节我不太愿意记录。很多时候的问题在于,你想实现一个功能的时候不太会描述你的问题(keyword),当然跨方向可能就是有这个问题,专业词汇不熟悉。所以我努力记录下一些概念,思路和关键词。
1.前后端分离
之前做过的小项目里面,最早时候直接PHP直接对mysql操作,组织混乱(随意在需要的地方增加代码),改了一个地方可能很多地方都受影响:
比如说一张表的结构发生变化,那么可能整个代码里面对于该表有操作的地方,都需要找出来修改,这实在是非常危险的行为,也付出了不少代价。我后来将所有对于Mysql的操作都整理到一个php文件里面来调用稍微缓解了一下这个问题,不过依然不太满意。不过这个本身可能是我php代码现学现用,很多时间都在赶进度造成的问题.
同时项目开始的时候也没有很统一的异常、错误处理规范,项目本身已经非常小,两三个人做起来沟通都非常麻烦。
同时这种简单组织的方式,在iOS,Android,和Web同时做起来的时候,也感觉一团乱麻。
所以最终,在这个机会,我稍微学习(继续学习ing)想对新的这一部分,完全做到前后分离。
因为目前来讲,项目的并发压力不大,所以决定利用轻量级的Flask搭建一个后端来处理所有数据交互,那么到底用什么样的方式交互呢?
2.Why RESTful
RESTful是一种风格,定义如何利用HTTP本身的方法GET/POST/PUT/DELTE/PATCH等来定义行为(CRUD),而用层级的资源表示(URI)来明确的标明服务器资源之间的关系。客户端无论是iOS/Web/Android, 遵循这个规范对资源进行访问,既保证了安全性同时十分容易管理。
当然RESTful用什么都可以,比如说Node.js, 虽然我本身有Java经验但是对于js的掌握程度一般,所以没有采用。
更多详细参考: http://www.pythondoc.com/flask-restful/first.html
http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api#hateoas
http://www.scienjus.com/my-restful-api-best-practices/
3. HATEOAS
除了上面的非常简单的说明,其实RESTful还有个重要的概念叫做 HATEOAS( Hypermedia As The Engine Of Application State ), 大致意思,是客户端与服务器的交互,其实我们平时可以看到,很多公司提供RESTful API, 则会有API文档,详细定义了API的endpoint, 规则等。那么假如修改API,则需要修订API文档,所有利用该API的服务可能都需要修改,所以有时候v1/v2这样子来管理不同版本的API, 但是HATEOAS则推崇利用超本文实现资源的导航,大部分时候不需要去查询文档就能使用API,你只需要知道一个根API.
GitHub的API就很高程度的实现这种类型的API.(参见: https://api.github.com),是不是不需要文档也基本能找到自己想要的资源在哪里,非常值得参考。
这样的动态资源获取,当你的API改变的时候,也能减小影响范围。
{
"current_user_url": "https://api.github.com/user",
"current_user_authorizations_html_url": "https://github.com/settings/connections/applications{/client_id}",
"authorizations_url": "https://api.github.com/authorizations",
"code_search_url": "https://api.github.com/search/code?q={query}{&page,per_page,sort,order}",
"commit_search_url": "https://api.github.com/search/commits?q={query}{&page,per_page,sort,order}",
"emails_url": "https://api.github.com/user/emails",
"emojis_url": "https://api.github.com/emojis",
"events_url": "https://api.github.com/events",
"feeds_url": "https://api.github.com/feeds",
"followers_url": "https://api.github.com/user/followers",
"following_url": "https://api.github.com/user/following{/target}",
"gists_url": "https://api.github.com/gists{/gist_id}",
"hub_url": "https://api.github.com/hub",
"issue_search_url": "https://api.github.com/search/issues?q={query}{&page,per_page,sort,order}",
"issues_url": "https://api.github.com/issues",
"keys_url": "https://api.github.com/user/keys",
"notifications_url": "https://api.github.com/notifications",
"organization_repositories_url": "https://api.github.com/orgs/{org}/repos{?type,page,per_page,sort}",
"organization_url": "https://api.github.com/orgs/{org}",
"public_gists_url": "https://api.github.com/gists/public",
"rate_limit_url": "https://api.github.com/rate_limit",
"repository_url": "https://api.github.com/repos/{owner}/{repo}",
"repository_search_url": "https://api.github.com/search/repositories?q={query}{&page,per_page,sort,order}",
"current_user_repositories_url": "https://api.github.com/user/repos{?type,page,per_page,sort}",
"starred_url": "https://api.github.com/user/starred{/owner}{/repo}",
"starred_gists_url": "https://api.github.com/gists/starred",
"team_url": "https://api.github.com/teams",
"user_url": "https://api.github.com/users/{user}",
"user_organizations_url": "https://api.github.com/user/orgs",
"user_repositories_url": "https://api.github.com/users/{user}/repos{?type,page,per_page,sort}",
"user_search_url": "https://api.github.com/search/users?q={query}{&page,per_page,sort,order}"
}
当然,我想这种方式可能对于获取资源特别有用,但是对于 更新和创建资源,还是要参考文档的,因为涉及到较多的参数传递。说道参数传递,我看到的基本都用json来进行数据交换。
更多参考: https://jozdoo.github.io/rest/2016/09/22/REST-HATEOAS.html
http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
4.SQLAlchemy
之前利用php mysql对数据库进行直接操作,数据一致性检查和处理对我来讲都不太友好。转到Python后测试SQLalchemy之后简直如发现了新大陆,对数据库的操作和结构修改都容易了很多。虽说有人诟病其效率,但是我目前的项目需求来讲,完全不构成问题。
SQLAlchemy是ORM( Object Relational Mapper)的数据库操作包,假如你对数据结构的一对多,多对多,一对一等基本关系理解深刻,配合SLQAlchemy使用则如鱼得水,大大简化对数据库的操作和安全检查。
更多参考: http://www.sqlalchemy.org/
5.认证和权限管理
设计一个API,当然要考虑权限管理保证安全性需要,至于是用户/密码认证还是token, 利用python的decorator都能容易的实现。当然,如果设计到RBAC(Role based access control)来区分用户对于具体资源的操作权限进行限制可能稍微麻烦一些。
更多参考: http://www.pythondoc.com/flask-restful/third.html
6.Flask-Restful
本身利用Flask做restful API也ok, 但是Flask-Restful提供了更好用更简单的框架,让你更加轻易的实现你的Restful API. 官方文档也非常的简短易读。我本身特别喜欢的是其利用Output Fields 对你的资源输出进行管理的方式。