【Swift-Vapor服务器】系列
【Swift-Vapor服务器】0001、Swift-Vapor入门-环境搭建
【Swift-Vapor服务器】0002、Swift-Vapor的基本使用-搭建一个属于自己歌曲的API
技术:Swift5.7、Vapor4.0、服务器、本地服务器、Vapor基本使用
运行环境:
Swift5.7 + Xcode14 + MacOS12.6 + Docker Desktop 4.12.0 (85629) + Azure Data Studio Version: 1.39.1 + Postman 9.24.2
Homebrew、Vapor 、Postman、Azure Data Studio 、DBeaver 、Docker Desktop
本次的目的是
- 使用Swift的Vapor搭建一个本地服务器
- 并且通过
Docker启动数据库
? 为什么要使用Docker启动数据库
因为Xcode启动Vapor项目 只是运行API 没有对数据库进行启动- 使用
Azure Data Studio查看PostgreSQL类型的数据库- 能够使用本地的localhost去访问 获取、添加数据
创建一个歌曲的API的Vapor项目 - 其中
Music-Vapor-API表示项目名称
vapor new表示 创建一个vapor 项目vapor new Music-Vapor-API

终端指令为 以下
vapor xcode如果无法启动Xcode 。那么手动将Xcode进行打开Vapor项目
打开之后等待项目将默认的依赖包安装完毕
Command + R 启动项目 ,并且使用postman进行测试接口是否正常Vapor 默认提供了一个Todo项目来启动
主要目的是项目 通过下面的路由进行获取对应数据http://127.0.0.1:8080 表示根route - 路由
http://127.0.0.1:8080/songs这个是我们主要目的 根据此路由获取 歌曲数据
postman检测接口是否能正常调试
我们可以看到Xcode的控制台 每次访问一次接口 下面都会输出一个信息
说明我们每访问指定的接口 就会输出一次



在route里面编写我们的代码
但是如果一个项目庞大 我们是需要单独进行抽取。跟默认创建Vapor项目自带的todo类型
所以我们需要创建控制器、模型、迁移
New File 选择Swift File 创建一个控制器 命名为SongController


New File 选择Swift File 创建一个迁移 命名为CreateSongs
我们先解释一下 Migrations 是干什么用的
我们数据库什么时候使用到迁移比如 我们Xcode里面有Git版本控制时候 。
当我们输入新的代码时候并且更改Xcode的时候。我们使用Git来告诉我们更改了什么
我们可以恢复迁移到某个时间点我们使用数据库迁移 就类似使用Xcode的Git一样




如何使用表中的数据 我们需要创建Model
New File 选择Swift File 创建一个模型命名为Song



configure设置真正创建数据库
routes设置歌曲控制器的创建
- 先是执行
configure进行创建数据库- 然后执行route里面的内容

主要作用 : 增删改查。让数据 添加\删除\修改 到我们数据库里面
注意提示 : 不建议在route里面进行 操作 。这个会使用route非常的庞大。
最好把逻辑分离。让控制器做这个事情。在route里面只需要注册控制器即可
//
// SongController.swift
//
//
// Created by 李宇鸿 on 2022/9/29.
//
import Fluent
import Vapor
// 继承RouteCollection - 路由集合
struct SongController : RouteCollection {
// boot 把它想象成一个初始化函数即可
func boot(routes: Vapor.RoutesBuilder) throws {
// 这里放什么?
// 这里表示
// 当我们去根路由 - 127.0.0.1
// 分组下的 创建一个新功能
let songs = routes.grouped("songs")
// 表示当使用 127.0.0.1/songs get方法的时候
// 然后去就使用index这个函数
// get 一般是获取数据
songs.get(use: index)
// post 一般是发布数据
songs.post(use:create)
}
// songs route
func index(req: Request) throws -> EventLoopFuture<[Song]>{
// 在这里 我们需要返回歌曲查询. 这意味着 这指的是我们
// 因为我们使用的 Fluent 在执行所有功能与我们的数据库对话
// 所以我们做歌曲查询 意味着 我们想要在请求数据上获取我们想要的数据
return Song.query(on: req.db).all()
}
// 返回 http状态
func create(req:Request) throws -> EventLoopFuture<HTTPStatus> {
// decode 类似 iOS里面的 json decode一样
// 解码之后 我们将歌曲类型保存到一个song的变量中
// 然后保存到我们的数据库中
// Song的这个Model.它天生有这个功能.可以用来与数据库对话.
let song = try req.content.decode(Song.self)
return song.save(on: req.db).transform(to: .ok)
}
}
主要作用 : 使用Fluent创建表 和更改删除表的操作
//
// CreateSongs.swift
//
//
// Created by 李宇鸿 on 2022/9/29.
//
//import Foundation
// Fluent是一个框架
// 一个Orm,所以它是一个对象关系映射器或者对象关系映射
// 我们将使用它进行迁移.
// 因此.迁移将跟我们数据库之间添加的内容的差异.
import Fluent
// 所以首先让我们创建一个名为 CreateSongs的结构体
// 它继承自迁移 Migration
// Migration 可以处理数据库迁移,包括添加新表,或者更改现有的变
// 所以这很像让它跟踪我们所有的变化 - 但不是针对我们的xcode.而是针对我们的数据库
struct CreateSongs : Migration {
// 默认它会为我们提供这两个函数 prepare \ revert
// 所以我们说迁移变化
// 下面表示 准备该怎么做,恢复更改该怎么做
// 准备
func prepare(on database: FluentKit.Database) -> NIOCore.EventLoopFuture<Void> {
// 第一件事情 就是使用它创建我们的表 - 表名为 Songs
// 表里面有行\列使我们数据不同的属性
// id \ 通过field函数(字段名\类型\是否必填)创建 其他字段 比如标题等
return database.schema("songs")
.id() // 唯一标识
.field("title", .string, .required) // 其他字段
.create() // 创建表
}
// 恢复更改
func revert(on database: FluentKit.Database) -> NIOCore.EventLoopFuture<Void> {
// 如果想还原 和 准备的所有更改
return database.schema("songs").delete()
}
// 以上就是进行对表的迁移
}
主要作用是: 创建表的数据
//
// Song.swift
//
//
// Created by 李宇鸿 on 2022/9/29.
//
// 导入Fluent表示 我要从数据库中查询数据的方式
import Fluent
import Vapor
// 它继承于 Model 和 Content
final class Song : Model,Content {
// 所以把它想象成我们在iOS项目中创建的普通类
// 这是我们所有的模型 意思是我们在找那个表
static let schema = "songs"
// 这张表里面包含哪些属性
// 我们需要添加一些内容 以帮助Fluent地是识别表中的所有内容
// 当我们添加 @ID(key: .id), @Field(key: "title") 他会告诉Fluent的ID的这个属性匹配我们表中的ID属性
@ID(key: .id)
var id : UUID?
@Field(key: "title")
var title : String
// 初始化程序 - 提供一个空的初始化程序 和一个 带有id\title的初始化
init(){
}
init(id: UUID? = nil,title:String)
{
self.id = id
self.title = title
}
// 所以这个歌曲类 代表我们数据库中的数据
}
import Fluent
import FluentPostgresDriver
import Vapor
// configures your application
public func configure(_ app: Application) throws {
// uncomment to serve files from /Public folder
// app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
// 这个是一个Postgres数据库
// 然后这是尝试为我们的主机获取环境变量,端口,用户名,密码,然后是数据库名称
// 单不是现在创建环境文件,如果找不到,它只会使用这个localhost
// 所以默认情况下,我们的数据库主机是localhost
// 账号密码\数据库表名为 vapor_username,vapor_password,vapor_database 通用的
app.databases.use(.postgres(
hostname: Environment.get("DATABASE_HOST") ?? "localhost",
port: Environment.get("DATABASE_PORT").flatMap(Int.init(_:)) ?? PostgresConfiguration.ianaPortNumber,
username: Environment.get("DATABASE_USERNAME") ?? "vapor_username",
password: Environment.get("DATABASE_PASSWORD") ?? "vapor_password",
database: Environment.get("DATABASE_NAME") ?? "vapor_database"
), as: .psql)
// 真正创建数据库
// 我们输入应用程序迁移
app.migrations.add(CreateSongs())
// 进行自动迁移
// 这意味着 我们拥有的所有迁移.我们想要实际运行它们.这将为我们创建一个数据库
// 它将等待自动完成.然后再执行其他所有操作.
try app.autoMigrate().wait()
// register routes
try routes(app)
}
主要作用是 : 设置每个接口的route返回的内容 以及控制器的创建
import Fluent
import Vapor
func routes(_ app: Application) throws {
// 其中这两个route 我们不会真正使用它们
app.get { req async in
"It works!"
}
app.get("hello") { req async -> String in
"Hello, world!"
}
// 创建歌曲控制器
try app.register(collection: SongController())
}
[ WARNING ] No custom working directory set for this scheme, using /Users/liyuhong/Library/Developer/Xcode/DerivedData/Music-Vapor-API-eebtsvgkhstmqwepwunlncfgmtey/Build/Products/Debug
Swift/ErrorType.swift:200: Fatal error: Error raised at top level: PostgresNIO.PSQLError(base: PostgresNIO.PSQLError.Base.connectionError(underlying: NIOPosix.NIOConnectionError(host: “localhost”, port: 5432, dnsAError: nil, dnsAAAAError: nil, connectionErrors: [NIOPosix.SingleConnectionFailure(target: [IPv6]localhost/::1:5432, error: connection reset (error set): Connection refused (errno: 61)), NIOPosix.SingleConnectionFailure(target: [IPv4]localhost/127.0.0.1:5432, error: connection reset (error set): Connection refused (errno: 61))])))
2022-09-29 16:22:21.468675+0800 Run[20886:24683826] Swift/ErrorType.swift:200: Fatal error: Error raised at top level: PostgresNIO.PSQLError(base: PostgresNIO.PSQLError.Base.connectionError(underlying: NIOPosix.NIOConnectionError(host: “localhost”, port: 5432, dnsAError: nil, dnsAAAAError: nil, connectionErrors: [NIOPosix.SingleConnectionFailure(target: [IPv6]localhost/::1:5432, error: connection reset (error set): Connection refused (errno: 61)), NIOPosix.SingleConnectionFailure(target: [IPv4]localhost/127.0.0.1:5432, error: connection reset (error set): Connection refused (errno: 61))])))
这上面说明它不能做某些事情
意味着数据库连接被拒绝
它无法连接到数据库
因为数据库实际上没有运行
我们需要做的事情是
查看docker-compose.xml文件 我们可以 docker-compose up db 指令进行单独启动数据库
Xcode运行应用程序 只是API方面的
我们通过Docker启动数据库



docker-compose up db 指令 等待启动 Docker桌面



我们发现 我们通过 http://127.0.0.1:8080/songs访问
返回状态是200
返回的内容[]
因为我们在数据库里面没有添加任何的数据。所以返回的是空数组
Azure Data Studio 查看数据库里面的数据。而无需使用APIPostgreSQL

PostgreSQL


添加歌曲数据在SongController 添加 create函数 最主要是将一条歌曲数据添加
并且重启Vapor项目
进行使用PostMan 请求方式改成Post
并且设置 Body为 raw 格式为Json
然后发送请求

Azure Data Studio 检查歌曲数据是否加入


control + C

当数据库显示灰色 表示停止运行
Azure Data Studio 是否关闭