F8App-ReactNative项目源码分析2-服务器端

近期开始研究Facebook f8app项目,目标是理解Facebook官方React Native f8app的整体技术架构,给公司目前几个的React Native项目开发提供官方经验借鉴,并对原生开发和React Native开发进行框架层面的融合。
研究了f8app的项目结构后,发现f8app服务器端的代码比较少,并且弄清楚数据模型和接口协议,对于后面理解客户端的实现有帮助,所以先分析服务器端。第二篇文章会详细分析f8app服务端的技术实现,并进行一些修改实验。f8app服务器端是基于Node.js,Express,Parse和GraphQL实现的,数据存储是MongoDB NoSql数据库。

安装推荐开发工具nuclide

我们一般使用Atom进行js开发,首先安装facebook推荐的开发工具nuclide。Mac和Linux下的安装命令如下,暂不支持windows。

apm install nuclide

F8app工程结构

下面先用tree -L 2 命令看下目录结构,只显示二级目录

├── LICENSE
├── README.md
├── android  安卓项目目录
│   ├── app
│   ├── build.gradle
│   ├── gradle
│   ├── gradle.properties
│   ├── gradlew
│   ├── gradlew.bat
│   └── settings.gradle
├── index.android.js
├── index.ios.js
├── ios   iOS项目目录
│   ├── Default-568h@2x.png
│   ├── F8Scrolling.h
│   ├── F8Scrolling.m
│   ├── F8v2
│   ├── F8v2.xcodeproj
│   ├── F8v2.xcworkspace
│   ├── F8v2Tests
│   ├── PodFile
│   ├── Podfile.lock
│   ├── Pods
│   ├── Settings.bundle
│   ├── Splash@2x.png
│   └── build
├── js    React native js源代码目录
│   ├── F8App.js
│   ├── F8Navigator.js
│   ├── FacebookSDK.js
│   ├── Playground.js
│   ├── PushNotificationsController.js
│   ├── actions
│   ├── common
│   ├── env.js
│   ├── filter
│   ├── flow-lib.js
│   ├── login
│   ├── rating
│   ├── reducers
│   ├── setup.js
│   ├── store
│   └── tabs
├── logs
├── node_modules
│       下面有900多个js模块
├── npm-shrinkwrap.json
├── package.json
├── scripts   一些脚本
│   ├── import-data-from-parse.js
│   ├── optimize-images.sh
│   └── store-ip.sh
└── server  服务器端目录,基于Parse和GraphiQL
    ├── cloud
    ├── cloud.js
    ├── schema
    └── server.js

服务器端技术介绍

f8app的服务器代码都在server目录下,由于使用了Node.js,Express,Parse,GraphQL等先进框架,代码量比较小,一共只有10个js文件,996行js代码。下面先介绍下f8app服务器端使用的技术,Node.js和Express这类常见技术就不介绍了。
服务器端是基于Facebook的Parse云平台,Parse服务将于January 28, 2017停止服务,现在官方提供了迁移指南。
现在Parse Server已经开源了,git地址是parse-server,开源Parse Server是基于node.js和Express框架的,支持的数据库是MongoDB和MongoRocks。
script/import-data-from-parse.js实现了从https://api.parse.com/1/classes/ 导入数据到本地MongoDB数据库的功能,通过npm run import-data 可以导入数据。

MongoRocks: What and Why?

MongoRocks是Facebook在2015年开发的基于RocksDB的MongoDB存储引擎实现,一般情况下Parse应用都应该用MongoRocks。
MongoDB3.0允许用户替换默认的default memory mapped (MMAP) 存储引擎。MongoRocks比MMAP存储引擎在性能方面有很多好处,
MongoRocks更多介绍可以参考MongoRocks链接

Parse Server简单介绍

Parse 的愿景是让开发者摆脱服务器,随心所欲地开发各种移动应用程序。对于比较复杂的应用程序,开发者有时需要不在移动设备上运行的逻辑。Cloud Code 正好可以实现这一目标。
由于f8app已经带了Parse Server,所以我就不需要用npm安装了,直接在f8app目录下运行npm start,测试下添加数据

    curl -X POST \
    -H "X-Parse-Application-Id: oss-f8-app-2016" \
    -H "Content-Type: application/json" \
    -d '{"score":1337,"playerName":"Sean Plott","cheatMode":false}' \
    http://localhost:8080/parse/classes/GameScore

在终端运行上面的命令后,服务端返回 {"objectId":"S8mgRPVgwU","createdAt":"2016-05-17T08:31:10.802Z"} 表示添加成功
在浏览器,可以看到刚才添加了一条Game score数据。

在终端运行下面命令可以查询新添加的那条数据

    curl -X GET \
     -H "X-Parse-Application-Id: oss-f8-app-2016" \
     http://localhost:8080/parse/classes/GameScore/S8mgRPVgwU

返回结果 {"objectId":"S8mgRPVgwU","score":1337,"playerName":"Sean Plott","cheatMode":false,"updatedAt":"2016-05-17T08:31:10.802Z"
Parse提供各种语言的SDK,包括Android,iOS,js等,可以很方便的在移动端使用。

Relay和GraphQL

Relay 是 app 中的一个数据框架,GraphQL 是 Relay 用来做数据表示的查询语言。GraphQL 同时还有一个 npm 包,可在服务器上运行,提供可以和 Relay 交互的数据源.

Relay 不是从 Flux 架构分化来的,它只和 GraphQL 有关。这也就是说,这和 Redux 的模型有着巨大的区别。

在 Relay + GraphQL 的模型中,每个组件指定自己需要的数据。Relay 调用数据,数据更新时,提供给组件最新的数据,并在客户端做缓存。app 需要更新数据时,在 Action 中创建一个 GraphQL 变更,这和 Redux 类似。

GraphQL是Facebook开发的一个针对描述复杂数据模型需求的一个数据查询语言标准,目前是工作草案。可以使用多种语言实现,目前Facebook提供了node.js版本的参考实现GraphQL.js..

服务器端代码分析

server.js是服务器的入口类,基于Express框架默认在8080端口提供了/parse,/dashboard,/graphql三个url入口,根目录默认跳转到/graphql。
下面是/parse url入口的代码,很简单,直接new ParseServer,把相关的参数传进去,mongodb数据库地址DATABASE_URI可以取环境变量的值const DATABASE_URI = process.env.DATABASE_URI || 'mongodb://localhost:27017/dev'; ,其它的参数也都可以直接在环境变量里面设置,通过export XXX="xxx"即可修改。

    server.use(
      '/parse',
      new ParseServer({
        databaseURI: DATABASE_URI,
        cloud: path.resolve(__dirname, 'cloud.js'),
        appId: APP_ID,
        masterKey: MASTER_KEY,
        fileKey: 'f33fc1a9-9ba9-4589-95ca-9976c0d52cd5',
        serverURL: `http://${SERVER_HOST}:${SERVER_PORT}/parse`,
      })
    );

cloud.js很简单,只是引用了cloud目录下文件,代码如下:

    require('./cloud/friends');
    require('./cloud/surveys');
    require('./cloud/tests');

cloud/friends.js 提供通过OAuth在Facebook登录后,获取好友和日程的功能。

/dashboard是ParseDashboard的入口,很简单不说了,就是Parse的Web管理控制台,通过http://localhost:8080/dashboard 可以访问,对Mongodb中数据进行管理,操作很方便。

/graphql是通过express-graphql插件实现的一个graphql入口,前端UI是通过graphiql.js插件实现的。graphql这块占代码量比较大,schema目录下的文件都是和graphql相关的。
GraphQL.js. 提供2个主要能力:构建type schema; 根据type schema类型提供查询能力。
schema.js是graphql查询的入口,只支持查询schedule,node(接口类型,只有id),viewer,这点可以从下面的代码看出来,只指定了F8QueryType。我们在浏览器graphql控制台http://localhost:8080/graphql 里面也只能做schedule的查询,否则会提示错误,这个控制台还是很智能的,支持查询代码提示。

    export var Schema = new GraphQLSchema({
      query: F8QueryType,
      mutation: F8MutationType,
    });

F8QueryType 定义如下:

    var F8QueryType = new GraphQLObjectType({
      name: 'Query',
      fields: () => ({
        node: nodeField,
        viewer: {
          type: F8UserType,
          resolve: (rootValue) => rootValue, // TODO: Authenticate user
        },
        schedule: {
          type: new GraphQLList(F8SessionType),
          description: 'F8 agenda',
          resolve: (user, args) => new Parse.Query(Session)
            .ascending('startTime')
            .find(),
        },
      }),
    });
修改下试试,让它能支持查询演讲者,在schedule:{这行上面加入下面代码:
    speaker: {
      type: new GraphQLList(F8SpeakerType),
      resolve: (speaker, args) => new Parse.Query(Speaker)
        .find(),
    },
在graphql控制台输入查询条件
    {
       speaker{
      id
      name
      title
      }
    }

可以查到所有演讲者的列表。
schema.graphql直观的展示了全部的type scheme查询类型,可以看到有interface和type 2种定义方法,interface其实就是类似Java里面的接口,type可以实现interface。Node是interface,包含一个主键id,其它很多类型都实现了Node,例如type Speaker implements Node。通过这个文件我们可以轻松地理解整个服务器的数据结构,还是很清晰的。graphiql.js控制台第一次访问会请求schema.json,用于查询框智能语法提示。
updateSchema.js可以重新生成schema.graphql和schema.json。在f8app目录下运行npm run update-schema 命令可以重新生成这2个文件。
按照上面的做法修改文件后运行命令,可以发现 schema.graphql多了一行 speaker: [Speaker]

babelRelayPlugin.js代码很少,是提供scheme数据给Relay的。
具体可以参考babel-relay-plugin

本文介绍了f8app的项目架构,分析了f8app服务器端的技术实现,整个数据流是Parse Cloud 通过脚本导入-> MongoDB -> ParseServer -> GraphQL -> Redux -> ReactNative,用到了Express,Parse Server,Parse dashboard,GraphQL.js,GraphiQL.js, Ralay等js模块,代码量比较小,但技术栈挺复杂的。

下篇文章分析React Native Android端的技术实现。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容