title: Vapor实现Swift的Server搭建
type: categories
date: 2016-12-29 10:19:06
categories: Swift

tags: [Swift服务器, Vapor,Postgres]

利用开源框架Vapor搭建Swift语言的服务器。

本文翻译自:https://www.bignerdranch.com/blog/server-side-swift-with-vapor/

一、准备工作

1、Xcode 和 Swift

第一件事就是下载最新的Xcode版本,其支持Swift3。

2、Vapor

第二件事就是安装Vapor和它的toolbox;

Vapor的官方文档:https://vapor.github.io/documentation/getting-started/install-swift-3-macos.html

具体的安装指令:

curl -sL check.vapor.sh | bash
curl -sL toolbox.vapor.sh | bash

注意:

第一条指令是为了验证Xcode的安装是否正确,可能会提醒设置Xcode的 Command Line Tools

第二条指令是为了安装toolbox工具,Xcode一定要处于打开状态,不然会有类似No such file or directory的报错。

3、Postgres

使用Postgres作为数据库。

如果已经安装了Homebrew,则可以执行下面的指令安装Postgres数据库;

brew install postgres

4、Heroku

在Heroku上面部署自己的云服务器。

需要注册,官网地址:https://dashboard.heroku.com/apps;

下载安装Heroku的Command Line: 地址:https://devcenter.heroku.com/articles/heroku-cli

二、创建Vapor项目

以下指令创建了一个名为 Friends 的App,创建过程较慢,耐心等待。

vapor new Friends

App创建成功之后,cd 到 Hello文件,执行以下指令,便可在Xcode中打开并运行项目。这个过程更加漫长。。。

vapor xcode -y

1、打开默认文件路径: http://localhost:8080

在打开的工程中,导航至 Sources/App/main.swift, 看到的代码如下:

import Vaporlet drop = Droplet()drop.get { req inreturn try drop.view.make("welcome", ["message": drop.localization[req.lang, "welcome", "title"]])
}drop.resource("posts", PostController())drop.run()

这个文件导入了Vapor框架,初始化一个Droplet类型对象,和添加了一个默认路径;

配置Xcode,如下,并Command+R运行:

在浏览器中打开 http://localhost:8080,

2、创建一个新的访问路径: http://localhost:8080/friends

同样实在main.swift文件中操作,具体添加后的代码如下:

import Vaporlet drop = Droplet()drop.get { req inreturn try drop.view.make("welcome", ["message": drop.localization[req.lang, "welcome", "title"]])
}drop.get("friends") { req inreturn try JSON(node: ["friends": [["name": "Sarah", "age": 33],["name": "Steve", "age": 31],["name": "Drew", "age": 35]]])
}drop.resource("posts", PostController())drop.run()

friends路径接受get请求,返回一组json数据。浏览器访问效果如下:

3、创建一个Friend类型的Model

Sources/App/Models下创建一个Friend.swift文件:

struct Friend {let name: Stringlet age: Intlet email: Stringinit(name: String, age: Int, email: String) {self.name = nameself.age = ageself.email = email}
}

注意:添加了一个email属性

Vapor提供了Model协议来保存model类型,同时也提供了方法来实现model到json的转换。为了结构体Friend遵从Model协议,我们需要导入在Friend.swift中导入Vapor库。

导入Vapor库的同时也意味着导入了Fluent库 。Fluent是针对Swift,处理众多数据库的对象关系映射工具(object relational mapping)。在这里我们使用它来处理我们的Postgres数据库。

注意:当看到Xcode导入Vapor库之后,可能会看到报错,此时返回终端,重新执行 vapor xcode -y;

最终的Friend.swift文件应该是下面的样子:

import Foundation
import Vaporstruct Friend: Model {var exists: Bool = falsevar id: Node?let name: Stringlet age: Intlet email: Stringinit(name: String, age: Int, email: String) {self.name = nameself.age = ageself.email = email}// NodeInitializableinit(node: Node, in context: Context) throws {id = try node.extract("id")name = try node.extract("name")age = try node.extract("age")email = try node.extract("email")}// NodeRepresentablefunc makeNode(context: Context) throws -> Node {return try Node(node: ["id": id,"name": name,"age": age,"email": email])}// Preparationstatic func prepare(_ database: Database) throws {try database.create("friends") { friends infriends.id()friends.string("name")friends.int("age")friends.string("email")}}static func revert(_ database: Database) throws {try database.delete("friends")}
}

第一件事是我们要实现Model协议。意味着,我们需要一个Node?类型的id属性;id的值在保存到数据库之前是nil。Friend同时有一个默认值为falseexists的属性,这个属性展示的是从数据库中是否获取到实例对象(This property details whether or not the instance was retrieved from the database and should not be interacted with directly.)。

同时,我们还需要实现其他的协议。NodeInitializableNodeRepresentablePreparation。其中,前两个协议 的实现是因为 Model协议继承于Entity协议。第一个协议告诉我们怎样从数据库中初始化model;第二个协议是怎样保存model到数据库中。第三个协议是怎样创建数据库。

接下来,我们在main.swift中利用上面的Friend,在新的路径 friends下创建一个json,如下:

drop.get("friends") { req inlet friends = [Friend(name: "Sarah", age: 33, email:"sarah@email.com"),Friend(name: "Steve", age: 31, email:"steve@email.com"),Friend(name: "Drew", age: 35, email:"drew@email.com")]let friendsNode = try friends.makeNode()let nodeDictionary = ["friends": friendsNode]return try JSON(node: nodeDictionary)
}

我们创建了一个包含三个Friend对象的friends数组。之后数组调用makeNode()方法转换成一个Node。之后的字典和json结果。

重新运行Command+R,在浏览器中访问http://localhost:8080/friends,即可看到效果。

4、配置Postgres数据库

设置Postgres涉及几个步骤:

  1. Package.swift中为Postgres添加一个provider;
  2. 在main.swift中导入provider,用Droplet来使用它;
  3. 配置我们的app使用Postgres;
获取一个provider

postgres-provider是一个优秀的provider。在Package.swift添加这个依赖。

import PackageDescriptionlet package = Package(name: "Friends",dependencies: [.Package(url: "https://github.com/vapor/vapor.git", majorVersion: 1, minor: 1),.Package(url: "https://github.com/vapor/postgresql-provider", majorVersion: 1, minor: 0)],exclude: ["Config","Database","Localization","Public","Resources","Tests",]
)

之后,在终端执行 vapor xcode -y

导入provider

打开main.swift,准备使用数据库Postgres。当然需要先安装Postgres。

Postgres地址:https://github.com/vapor/postgresql

MacOS上的Postgres安装使用指令:

brew install postgresql
brew link postgresql
brew services start postgresql// to stop
brew services stop postgresql

注:我在Mac上brew install postgresql时出现404报错,导致Postgres安装失败,所以接下来的内容就没办法跟着原文继续实现。

首先,导入 VaporPostgreSQL;

其次,为Droplet的preparations添加Friend.self ;

最后,drop.addProvider(VaporPostgreSQL.Provider.self),添加porvider到drop以使用数据库。

在工程中配置Progres

在工程的Config文件夹下创建 secrets文件夹,并在secrets下创建 postgresql.json。最终的路径应该是这样的 Config/secrets/postgresql.json;而postgresql.json中内容如下:

{"host": "127.0.0.1","user": "DubbaDubs","password": "","database": "friends","port": 5432
}

注意:user要用你自己的;friends只是我们生命的一个数据库,仍旧需要创建它。

使用Protgres

接下来,我们创建一个新的路径,执行POST方法,将Friend数据保存到数据库;

import Vapor
import VaporPostgreSQLlet drop = Droplet()
drop.preparations.append(Friend.self)do {try drop.addProvider(VaporPostgreSQL.Provider.self)
} catch {print("Error adding provider: \(error)")
}drop.get { req inreturn try drop.view.make("welcome", ["message": drop.localization[req.lang, "welcome", "title"] ])
}drop.get("friends") { req inlet friends = [Friend(name: "Sarah", age: 33, email:"sarah@email.com"),Friend(name: "Steve", age: 31, email:"steve@email.com"),Friend(name: "Drew", age: 35, email:"drew@email.com")]let friendsNode = try friends.makeNode()let nodeDictionary = ["friends": friendsNode]return try JSON(node: nodeDictionary)
}drop.post("friend") { req invar friend = try Friend(node: req.json)try friend.save()return try friend.makeJSON()
}drop.resource("posts", PostController())drop.run()

这个POST路径的body,类似下面:

{"name": "Some Name","age": 30,"email": "email@email.com"
}

我们尝试用req.json创建一个Friend类型的实例对象,作为POST请求发送出去;

之后,调用friend.save()将对象保存到数据库;

关于friend为什么用 Var .save()的理解:friend中有一个在保存到数据库之前是nil的id属性,这里的作用就是当成功保存到数据后,在回调中修正这个id的值。

我们仍旧需要创建数据库

postgres -D /usr/local/var/postgres/

在终端执行上面的指令,Protgres 服务将在本地运行;一旦服务开始运行,我们就可以创建数据库。

在新的终端窗口,执行

createdb friends
psql

之后,可以输入 \l来查看数据库列表,应该就可以看到你的friends数据库。

最后,你可以利用POSTMAN等工具发送一个post请求,测试一下。

然后用 psql来确认你发送数据到数据库了。

You can test this new route by building and running your app within Xcode as you did above and using curl or a tool like Postman. You can use psql to verify that you are posting data to the database. From inside the command line interface, type \c friends to connect to your friends database. Next, type SELECT * FROM friends; and hit enter. You should see the information for the friend that you just POSTed to the "friend" route.

Removing Hardcoded Data

GET requests to our "friends" currently return hardcoded data. But we can POSTfriends to our database now! Go ahead and POST a few more friends to your database to fill it out a little more.

Back in main.swift, let’s update our "friends" route to return the data in our database. That method should now look like this:

drop.get("friends") { req inlet friends = try Friend.all().makeNode()let friendsDictionary = ["friends": friends]return try JSON(node: friendsDictionary)
}

Visit http://localhost:8080/friends in your browser or send a GET request via Postman and you should see your friends returned to you.

GETting by id

Add a new route to main.swift that will use a user’s id to find an entry in the database.

drop.get("friends", Int.self) { req, userID inguard let friend = try Friend.find(userID) else {throw Abort.notFound}return try friend.makeJSON()
}

The above will match a route that will end in something like, .../friends/1, where the integer at the end is the friend’s id. Notice that we use Int.self as the second argument in the path. This means that we can have type safe parameters in our routes! In Vapor, there is no need to cast this parameter from a String to an Int. We can express exactly what we need. The userID parameter in the closure will match the integer passed at the end of the route.

Also, through the power of Fluent, we can simply find(_:) the instance of our model by its id. Since this lookup can fail, we must try. If we fail to find a Friend, we’ll throw the error Abort.notFound. Otherwise, we makeJSON() from the friend we found and return. Go ahead and try it out!

部署到 Heroku

All that is left to do is to deploy to Heroku. Vapor makes this process very easy.

Heroku works with Git, so you should make sure that you have that installed as well. Create a Git repository and commit your files.

git init
git add .
git commit -m "Initial commit"

Now, all you need to do is create a Heroku instance and push to it.

vapor heroku init

The Heroku CLI will ask four questions:

Would you like to provide a custom Heroku app name? Answer ‘n’ and hit enter if you don’t have a custom name.

Would you like to provide a custom Heroku buildpack? Answer ‘n’ and hit enter if you would like to use the default buildpack that Heroku provides.

Are you using a custom Executable name? Answer ‘n’ and hit enter here if you aren’t using a custom executable name.

Would you like to push to Heroku now? Answer ‘n’ and hit enter.

We need to answer ‘no’ because we need to configure our database to work online. We’ll do that below.

Before you plug the URL you see in your Terminal output into your browser of choice, we need to provision a Postgres add-on on Heroku. Type the following in your Terminal to add Postgres to your app.

heroku addons:create heroku-postgresql:hobby-dev

Adding the database can take up to five minutes to provision. Once it is ready, you can type heroku config in Terminal to see your database’s URL to confirm that the add-on was provisioned.

Now, we need to update our app’s Procfile, which was created via vapor heroku init, to use the DATABASE_URL environment variable that was created by Heroku. Open the Procfile in your text editor and update it so that looks like the below.

web: App --env=production --workdir="./"
web: App --env=production --workdir=./ --config:servers.default.port=$PORT --config:postgresql.url=$DATABASE_URL

Notice that we added a new configuration so that Heroku knows to use our database’s URL on the web and not the instance we have been running locally: --config:postgresql.url=$DATABASE_URL.

Save the Procfile and type git push heroku master in Terminal to deploy your app.

Deploying will take a few minutes. Heroku needs to build your application, install Swift on your Heroku instance, and so on. After some time, your app will be live on the web.

Note that we didn’t push up the data from the local database to the remote database. You will have to exercise your app’s API to add some data to your database on Heroku.

Making Changes

Making changes is easy! Simply write your code, commit the changes, and push them up to Heroku.

git commit -am "Adds new code"
git push heroku master

Wrapping Up

This post covered a lot of ground: We downloaded a number of tools. Introduced Vapor. Wrote a small web app. Developed an API to read and write some data to Postgres. Finally, we deployed the app to Heroku.

This post is intended to you get started with server-side Swift. To that end, we introduced Vapor and explored some of its features. But this introduction just scratches the surface; there is a lot more to Vapor. What’s exciting is that server-side Swift is moving fast! Stay tuned here for more posts on the subject.

Challenges

If you’re looking for more to do on your own, try your hand at these extra challenges.

  • Create a route to DELETE a friend from the database.
  • Create a route to PATCH a friend on the database.

Vapor实现Swift的Server搭建相关推荐

  1. Lync server 2013 之office web apps server 搭建步骤

    office web apps server 搭建步骤: 一. .NET Framework 4.5 节点下的HTTP 激活 .NET Framework 3.5 Windows Identity F ...

  2. TortoiseSVN与VisualSVN Server搭建SVN版本控制系统

    本片主要介绍如何搭建SVN版本控制系统,主要使用工具: 1 客户端:TortoiseSVN (小乌龟) 2 服务端:VisualSVN Server 搭建出图形化管理,以及右键菜单版本控制管理的SVN ...

  3. Ubuntu 12.04 Server 搭建DNS服务器

    这边简单介绍一下,在Ubuntu 12.04 Server 搭建简单的DNS 服务器 #apt-get -y install bind9 bind9utils 这里我以 hasee.com 域名为例 ...

  4. windows 下使用 Filezilla server 搭建 ftp 服务器

    windows 下使用 Filezilla server 搭建 ftp 服务器 1. Filezilla server 免费,开源, ftp 服务端 2. 下载安装, windows  https:/ ...

  5. Ubuntu Server搭建FTP服务器(2) --本地用户FTP服务器架设

    Ubuntu Server搭建FTP服务器(2) --本地用户FTP服务器架设 参考:ubuntu中文wiki百科,网址:wiki.ubuntu.org.cn 环境:Ubuntu 9.04 Serve ...

  6. TortoiseSVN与VisualSVN Server搭建SVN版本控制系统【转】

    转自:http://www.cnblogs.com/xing901022/p/4399382.html 本片主要介绍如何搭建SVN版本控制系统,主要使用工具: 1 客户端:TortoiseSVN (小 ...

  7. FileZilla Server 搭建FTP服务器

    FileZilla Server 搭建FTP服务器 1. 背景: 在免费(此类工具免费者很多)中,我的选择是FileZilla,因为它小巧.非常强大.也比较易用,且为开源软件,发展前景不错.用户也比较 ...

  8. 用FileZilla Server搭建ftp服务器

    用FileZilla Server搭建ftp服务器 1.先在浏览器搜索 filezilla server 2.点开FileZilla软件的官网,下载该软件 3.下载完成后,按照操作流程一步步完成安装 ...

  9. raspberry ubuntu 修改源为清华_Ubuntu 下 Janus Server 搭建笔记

    1 Ubuntu 下 Janus Server 搭建笔记 QQ交流群 782508536 FFmpeg/WebRTC/RTMP音视频流媒体高级开发 https://ke.qq.com/course/4 ...

最新文章

  1. usaco contact
  2. php鼠标经过显示文本,CSS_HTML和CSS做网页实例教程:鼠标滑过文字改变,关于HTML+CSS的实例效果很多, - phpStudy...
  3. SDO_GEOMETRY结构说明
  4. python调用api做用户登录认证_(二)Python调用Zabbix api之从入门到放弃——登录并获取身份验证令牌...
  5. matlab usewhitebg,Matlab的:geo​​show的網格和框架
  6. 浪擎全融合灾备云获大数据安全领域最佳创新奖
  7. 用CSV文件读写数据的两种方式(转)
  8. matlab只加盐噪声,我用matlab中的imnoise函数给图像加椒盐噪声为什么产生的噪声不是黑白的?...
  9. 《机器学习实战:基于Scikit-Learn、Keras和TensorFlow第2版》-学习笔记(1)
  10. Irrlicht引擎源码剖析——第十三天
  11. KEIL 5的背景色设置。
  12. Navicat的常用的使用技巧
  13. H5 video 自动播放(autoplay)不生效解决方案
  14. Verdi命令行调用选项用法
  15. Win 10 卡在登陆界面转圈
  16. java工程师面试经验分享1-面试准备
  17. 什么是uni-app
  18. “藤”缠“树”,腾讯安全与青藤云安全发力主机安全
  19. 基于javaweb(springboot)汽车配件管理系统设计和实现以及文档报告
  20. C语言实现PID之应用

热门文章

  1. 禁用主板报警 禁用主板报警 解决win8mysql权限的问题
  2. 信阳新闻网:《观察+思考+努力=创新——访南京大数据研究院院长刘鹏》
  3. 中国裁判网-爬虫-2018.09.28
  4. Cocos2d开发系列 一
  5. thymeleaf的使用
  6. 今年丰水期S9还能挖,减半前算力不会大涨 | 非正式会谈
  7. 在python子程序中、使用关键字_python函数(四)
  8. 阿里巴巴创业论坛--创业要点!
  9. 三菱PLC FX5u结构化4轴伺服1个机器人程序
  10. 负数在计算机中的存储——补码