给你一小摞煎饼或者是一大摞煎饼,你想要哪个呢?正确是答案总是我想要更多的煎饼。在这篇文章里,我们将给你更多的煎饼。来吧,抓住福利,让我们打造一个全栈的MEAN.此系列一共三篇文章,这是第一篇。
开始之前,先介绍下MEAN:
对于那些不熟悉MEAN的人来说,MEAN类似于很流行的LAMP(Linux, Apache, MySQL, PHP).他是JavaScript开发人员中最流行的应用开发集之一。MEAN即MognoDB, Express, AngularJS, Node.js. 这四种技术组合而成的。快速地分析一下这四种技术:
MongoDB: NoSQL数据库、持久化
Express: HTTP请求路由、API框架
AngularJS: 应用、MVC 框架
Node.Js: 服务器端的执行环境
很长时间以来,MEAN已经是开发web apps应用中很流行的默认开发工具集了,主要是因为他使开发人员能够一直使用JS和JSON在整个应用程序中,从后端的服务器到前端的UI。虽然这是很多原因中相当酷的一个,但最大的一个原因是他从已经很复杂的系统中移除了很多的复杂设计。我们不仅可以只用一种语言(JS)写所有的代码,而且应用中每一层的数据通讯,数据交换都可以用单一的数据格式,共同的风格和对象类型。这种连续性 能有效地减少错误以及很容易地进行协调开发。
好,够了。开始我们的App吧!
项目设置,Git, Heroku 以及 后端Node.js
接下来,我们将要用Typescript和RESTful api来创建一个简单的Ionic2 App。我们还将建立一个Node.js写的后端,用Express来做Api以及用MongoDB来做数据存储。当我们完成所有这些操作后,我们将用Git把应用推送到Heroku.在那里进行发布。
这个应用的代码在GitHub可以得到。
项目设置
我们将用TS来写app的前端,因此你应该为你的编辑器先去下载一个TS编译器。这将让你的生活更美好~
首先,使用Ionic2的start命令创建一个blank应用,随便给你的app起个名字。我叫我的应用为todo-ionic2-heroku:
$ > ionic start todo-ionic2-heroku blank --v2
这将在当前目录下创建一个新的项目目录,名字和项目名一致。目录结构大致如下:
Paste_Image.png
让我们来看看。 cd到新创建的目录and启动服务吧!
$ > cd todo-ionic2-heroku
$ /todo-ionic2-heroku > ionic serve
serve命令会执行一系列的gulp任务去构建你的应用,然后在你的浏览器里打开他。(我正在用chrome的开发者工具中的手机模式来检查查看应用,样子如下):
Paste_Image.png相当酷吧,对不对? 好吧,也许没有,但它是一个良好的开始。
Node.js后端
如果这是你第一次使用Heroku创建Node.js应用,请先在Heroku开发中心看Heroku上创建Node.js的教程
如果你不听话还想继续搞下去,确保你已经安装了以下的这几项:
- Heroku toolbelt创建和管理Heroku应用的Heroku命令行工具
- Node.js
初始化Git和创建Heroku
给我们的app初始化一个Git仓库:
$ /todo-ionic2-heroku > git init
然后用Heroku设置应用。(注:你必须先从命令行登录到你的Heroku账户)
$ /todo-ionic2-heroku > heroku create
此命令将创建一个名叫heroku的远程Git,我们将把我们的代码推到那里。他也会为我们的应用生成一个随机的名字,我的这个例子是evening-everglades-42641
设置MongoDB
现在我们有一个空的Ionic应用,然后我们已经把他关联到Heroku,然后让我们来提供一个MongoDB实例吧。我们能设置一个MongoDB的本地实例,但是因为我们在用Heroku,所以我们会用到MongoLab的mLab插件。通过Heroku让这种"数据库即服务"的方式使得他能很简单地提供一个MongoDB数据库。此外,对于我们这种小项目还是免费的哦。
Paste_Image.png注意:如果你不想用MongoLab,还有其他的Heroku数据存储选项.
使用Heroku命令行来安装你的数据库:
$ /todo-ionic2-heroku > heroku addons:create mongolab
这条命令创建一个沙盒数据库并且连接到了我们上一步创建的Heroku应用上了,他还生成了一个配置变量在你的Heroku环境中:MONGODB_URI。接下来我们将用他来连接到我们的数据库。
创建一个连接到MongoDB的Express App
我们创建的第一个Ionic项目,大部分的通讯管道已经和Node应用集成了。非常地棒。
唯一剩下要做的就是为我们的服务器下载node_modules并且--save保存他们到已存在的package.json文件中。
$ /todo-ionic2-heroku > npm install express mongodb cors body-parser --save
为了和我们提供的mLab数据库交互,我们会用到Node.js官方支持的mongodb node module
(注:对于更复杂的数据模型的项目,你可以去看看Mongoose,他提供了一个“优雅的Node.js MongoDB对象模型”)
在项目的根目录下,创建一个叫server.js的文件,把下面的代码粘进去:
//server.js (todo-ionic2-heroku/server.js)
var express = require('express');
var bodyParser = require('body-parser');
var cors = require('cors');
var app = express();
var mongodb = require('mongodb'),
mongoClient = mongodb.MongoClient,
ObjectID = mongodb.ObjectID, // Used in API endpoints
db; // We'll initialize connection below
app.use(bodyParser.json());
app.set('port', process.env.PORT || 8080);
app.use(cors()); // CORS (Cross-Origin Resource Sharing) headers to support Cross-site HTTP requests
app.use(express.static("www")); // Our Ionic app build is in the www folder (kept up-to-date by the Ionic CLI using 'ionic serve')
var MONGODB_URI = process.env.MONGODB_URI;
// Initialize database connection and then start the server.
mongoClient.connect(MONGODB_URI, function (err, database) {
if (err) {
process.exit(1);
}
db = database; // Our database object from mLab
console.log("Database connection ready");
// Initialize the app.
app.listen(app.get('port'), function () {
console.log("You're a wizard, Harry. I'm a what? Yes, a wizard, on port", app.get('port'));
});
});
// Todo API Routes Will Go Below
获取MONGODB_URI作为本地开发时备用
在我们开发应用的时候,我们希望他能在本地运行,想要实现这点,我们注意到在server.js文件中的第17行:
var MONGODB_URI = process.env.MONGODB_URI;
process.env.MONGODB_URI告诉我们的服务器当应用在Heroku上运行时数据库在哪里,但是如果你想要通过node server.js启动你的服务器,你将会得到像下面这样的错误:
TypeError: Parameter 'url' must be a string, not undefined
要修复这个问题,你需要用heroku config命令从Heroku里获取到数据库的URI:
$ /todo-ionic2-heroku > heroku config | grep MONGODB_URI
从输出内容中,复制以mongodb://heroku开头并接着一串类似于乱码字符串的那条。他看起来如下:
mongodb://heroku_g24xsxd8:ur8k708rh1qqga17luq6saqtat@ds045622.mlab.com:45122/heroku_g24xsxd8
然后更新server.js的第17行:
var MONGODB_URI = process.env.MONGODB_URI || 'your_mongodb_uri_goes_in_these_quotes';
注意:不要分享你的DB URI到任何公开的地方,因为这会让知道怎么使用他的人有全部的权限去访问他。
此时,你应该可以启动服务器,并且打开你的应用啦 http://localhsot:8080
$ /todo-ionic2-heroku > node server.js
Database connection ready
You're a wizard, Harry. I'm a what? Yes, a wizard, on port 8080
注意:展望未来,这是在终端中打开的非常有用的三个标签,一个是正在运行的后端Express服务器,一个是正在运行的可以监听到Ionic变化的并且重新编译的前端服务ionic serve,和一个用于运行附加插件的命令。
设置你的 RESTful API端点
现在我们的服务器已经启动并运行起来了,让我们继续前进去创建一个简单的RESTful API终端以便我们能通过他来为我们的应用进行前后端的数据通讯。我们将创建两个终端来支持以下的CRUD(create, read, update, delete)操作。
Paste_Image.png最后,仅供参考,我们的TODO应用的数据库纲要是非常简单的:
{
"_id": <ObjectID>,
"description": <string>,
"isComplete": <boolean>
}
增加API终端到Server.js
创建我们的端点,让我们添加以下内容到server.js
//server.js
...
/*
* Endpoint --> "/api/todos"
*/
// GET: retrieve all todos
app.get("/api/todos", function(req, res) {
db.collection("todos").find({}).toArray(function(err, docs) {
if (err) {
handleError(res, err.message, "Failed to get todos");
} else {
res.status(200).json(docs);
}
});
});
// POST: create a new todo
app.post("/api/todos", function(req, res) {
var newTodo = {
description: req.body.description,
isComplete: false
}
db.collection("todos").insertOne(newTodo, function(err, doc) {
if (err) {
handleError(res, err.message, "Failed to add todo");
} else {
res.status(201).json(doc.ops[0]);
}
});
});
/*
* Endpoint "/api/todos/:id"
*/
// GET: retrieve a todo by id -- Note, not used on front-end
app.get("/api/todos/:id", function(req, res) {
db.collection("todos").findOne({ _id: new ObjectID(req.params.id) }, function(err, doc) {
if (err) {
handleError(res, err.message, "Failed to get todo by _id");
} else {
res.status(200).json(doc);
}
});
});
// PUT: update a todo by id
app.put("/api/todos/:id", function(req, res) {
var updateTodo = req.body;
delete updateTodo._id;
db.collection("todos").updateOne({_id: new ObjectID(req.params.id)}, updateTodo, function(err, doc) {
if (err) {
handleError(res, err.message, "Failed to update todo");
} else {
res.status(204).end();
}
});
});
// DELETE: delete a todo by id
app.delete("/api/todos/:id", function(req, res) {
db.collection("todos").deleteOne({_id: new ObjectID(req.params.id)}, function(err, result) {
if (err) {
handleError(res, err.message, "Failed to delete todo");
} else {
res.status(204).end();
}
});
});
// Error handler for the api
function handleError(res, reason, message, code) {
console.log("API Error: " + reason);
res.status(code || 500).json({"Error": message});
}
部署到Heroku并测试你的API
在开始我们的Ionic应用之前,让我们把所有的一切都部署到Heroku上并且用curl命令测试我们的API.
更新.gitignore文件
默认情况下,Ionic框架放www/build条目在.gitignore文件里,因为我们通常情况下并不想跟踪他,但现在我们需要他在支持Heroku的部署,因此我们将其删除,删除后,.gitignore长这个样子:
#.gitignore
node_modules/
platforms/
plugins/
.DS_Store
提交更改并推到Heroku
接下来,提交你所有的更改到git仓库并推到Heroku中:
$ /todo-ionic2-heroku > git add -A
$ /todo-ionic2-heroku > git commit -m "First commit"
$ /todo-ionic2-heroku > git push heroku master
Heroku将确认你的应用已经被部署,但是要打开你的应用,你至少需要运行一个Heroku的实例,用以下命令来激活你的应用:
$/todo-ionic2-heroku > heroku ps:scale web=1
然后打开你的应用:
$/todo-ionic2-heroku > heroku open
这将会打开你这个简单的空的Ionic应用在your-app-name.heroku-app.com
接下来,让我运行以下curl命令增加一项新的TODO条目来测试一下API。
$/todo-ionic2-heroku > curl -H "Content-Type: application/json" -d '{"description":"Order a tall stack of pancakes, just because."}' https://your-app-name.herokuapp.com/api/todos
你能在todos集合中查询到你刚添加的那条记录,运行以下代码打开他。
$/todo-ionic2-heroku > heroku addons:open mongolab
结语
有了这些,后端就一切准备就绪了。下一步我们将打造出我们应用的前端,在下一篇文章,我们会写一些Angular2的代码来检索出我们刚刚添加到数据库中的todo记录,并且显示在Ionic2应用中。
网友评论