Vapor实现Swift的Server搭建

来源:互联网 发布:虚拟专用网络vpn 软件 编辑:程序博客网 时间:2024/05/16 01:58

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 in    return 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 in    return try drop.view.make("welcome", [        "message": drop.localization[req.lang, "welcome", "title"]    ])}drop.get("friends") { req in    return 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: String    let age: Int    let email: String    init(name: String, age: Int, email: String) {        self.name = name        self.age = age        self.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 Foundationimport Vaporstruct Friend: Model {    var exists: Bool = false    var id: Node?    let name: String    let age: Int    let email: String    init(name: String, age: Int, email: String) {        self.name = name        self.age = age        self.email = email    }    // NodeInitializable    init(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")    }    // NodeRepresentable    func makeNode(context: Context) throws -> Node {        return try Node(node: ["id": id,                                      "name": name,                                      "age": age,                                      "email": email])    }    // Preparation    static func prepare(_ database: Database) throws {        try database.create("friends") { friends in            friends.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 in    let 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 postgresqlbrew link postgresqlbrew 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 Vaporimport VaporPostgreSQLlet drop = Droplet()drop.preparations.append(Friend.self)do {    try drop.addProvider(VaporPostgreSQL.Provider.self)} catch {    print("Error adding provider: \(error)")}drop.get { req in    return try drop.view.make("welcome", [        "message": drop.localization[req.lang, "welcome", "title"] ])}drop.get("friends") { req in    let 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 in    var 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 friendspsql

之后,可以输入 \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 in    let 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 in    guard 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 initgit 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.
2 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 tcl安卓系统电视反应慢怎么办 狼人杀警长竞选一直平票怎么办 去驾校投诉教练被教练报复怎么办 哈尔滨机场大巴六点的飞机怎么办 山东德州恩城镇的农民怎么办养老险 我的世界联机平台房间进不去怎么办 验车时间过了3天怎么办 在携程订的机票和酒店不能退怎么办 千牛工作台中旺旺登录失败怎么办 掌通家园换手机号了忘了更改怎么办 qq注销了后绑定的全民k歌怎么办 小米账号绑定的手机号注销了怎么办 微信账号注销后绑定的手机号怎么办 微信账号不想用了注销不了怎么办 苹果手机掉了捡到不还怎么办 在工作中把和别人结下梁子了怎么办 在阿里巴巴上买的货物没发货怎么办 做了下颌角一边脸反复肿怎么办 玩广东11选5输50万怎么办 玩广东11选5输了十几万怎么办 新办公楼装修好就要搬进去怎么办 oppo手机上的黄页删了怎么办 小米不小心把手机联系人删了怎么办 58同城小区名输不了怎么办 e路发注册直接有积分怎么办 大众速腾的不锈钢圈被碰花了怎么办 公司卡着生育险不给怎么办 济南图书馆借书超过期限了怎么办 淘宝解绑支付宝支付密码不对怎么办 微博支付宝支付密码忘记了怎么办 图虫签约师通过了认证标识怎么办 签证做假工作证明资料被拒怎么办 在广州办个建设厅电工证怎么办 水利考的五大员证到有效期怎么办 额头注射玻尿酸吸收后不平怎么办 施工员证书挂靠拿不回来怎么办 森林公安未转政法编制的人员怎么办 北京的限行新政策外地车怎么办 报考二级建造师工作年限不够怎么办 郑州航院图书馆密码忘了怎么办 无锡妇幼预约挂号过号了怎么办