在 Swift Vapor 中返回响应可表示对象集合的最佳方法是啥?
Posted
技术标签:
【中文标题】在 Swift Vapor 中返回响应可表示对象集合的最佳方法是啥?【英文标题】:What's the best way to return a collection of response representable objects in Swift Vapor?在 Swift Vapor 中返回响应可表示对象集合的最佳方法是什么? 【发布时间】:2017-04-09 20:56:52 【问题描述】:上下文:
最近,我决定从事 Swift 服务器端开发,因为我认为 Vapor 框架非常酷。我在实验过程中遇到了一些困难,想要一些关于用树叶和蒸汽做模板的建议。
关于渲染视图,我已经多次查看文档。使用变量渲染模板视图需要叶模板的名称和包含变量的 Response Representable 节点对象。
试图用模板和框架本身来设计一个场景(因为这是我学得最好的方式),我试图模拟一个博客格式。这是我的课程/获取请求:
// MARK: Blog Post Object
final class BlogPost: NodeRepresentable
var postId: Int
var postTitle: String
var postContent: String
var postPreview: String
func makeNode(context: Context) throws -> Node
return try Node(node: [
"postId":self.postId,
"postTitle":self.postTitle,
"postContent":self.postContent,
"postPreview":self.postPreview
])
init(_ postId: Int, _ postTitle: String, _ postContent: String)
self.postId = postId
self.postTitle = postTitle
self.postContent = postContent
self.postPreview = postContent.trunc(100)
// MARK: Blog view request; iterate over blog objects
drop.get("blog") request in
let result = try drop.database?.driver.raw("SELECT * FROM Posts;")
guard let posts = result?.nodeArray else
throw Abort.serverError
var postCollection = [BlogPost]()
for post in posts
guard let postId = post["postId"]?.int,
let postTitle = post["postTitle"]?.string,
let postContent = post["postPreview"]?.string else
throw Abort.serverError
let post = BlogPost(postId, postTitle, postContent)
postCollection.append(post)
// Pass posts to be tokenized
/* THIS CODE DOESN'T WORK BECAUSE "CANNOT CONVERT VALUE OF TYPE
* '[BLOGPOST]' TO EXPECTED DICTIONARY VALUE OF TYPE "NODE"
* LOOKING FOR THE BEST METHOD TO PASS THIS LIST OF OBJECTS
*/
drop.view.make("blog", [
"posts":postCollection
])
这是我的blog.leaf
文件:
#extend("base")
#export("head")
<title>Blog</title>
#export("body")
<h1 class="page-header">Blog Posts</h1>
<div class="page-content-container">
#loop(posts, "posts")
<div class="post-container">
<h3 style="post-title">#(posts["postTitle"])</h3>
<p style="post-preview">#(posts["postPreview"])</h3>
</div>
</div>
问题:
如您所见,我有点坚持寻找迭代对象并将其属性模板化到叶文件中的最佳方法。有人有什么建议吗?顺便说一下,很抱歉糟糕的编程约定。我在面向对象/协议的编程方面相当新。
【问题讨论】:
【参考方案1】:我最终做的是使 Post 模型符合 Model 协议。
import Foundation
import HTTP
import Vapor
// MARK: Post Class
final class Post: Model
var id: Node?
var title: String
var content: String
var date: Date
var isVisible: Bool
// TODO: Implement truncate extension for String and set preview
// to content truncated to 100 characters
var preview = "placeholder"
var exists: Bool = false
init(title: String, content: String, isVisible: Bool = true)
self.title = title
self.content = content
self.date = Date()
self.isVisible = isVisible
init(node: Node, in context: Context) throws
let dateInt: Int = try node.extract("date")
let isVisibleInt: Int = try node.extract("isVisible")
id = try node.extract("id")
title = try node.extract("title")
content = try node.extract("content")
date = Date(timeIntervalSinceNow: TimeInterval(dateInt))
isVisible = Bool(isVisibleInt as NSNumber)
exists = false
func makeNode(context: Context) throws -> Node
return try Node(node: [
"id": id,
"title": title,
"content": content,
"date": Int(date.timeIntervalSince1970),
"isVisible": Int(isVisible as NSNumber)
])
static func prepare(_ database: Database) throws
try database.create("Posts") posts in
posts.id()
posts.string("title", optional: false)
posts.string("content", optional: false)
posts.int("date", optional: false)
posts.int("isVisible", optional: false)
static func revert(_ database: Database) throws
try database.delete("posts")
然后返回/创建 Post 对象的实例:
import Vapor
import Foundation
import HTTP
final class BlogController
func addRoutes(_ drop: Droplet)
let blogRouter = drop.grouped("blog")
let blogAPIRouter = drop.grouped("api","blog")
blogRouter.get("posts", handler: getPostsView)
blogAPIRouter.get("posts", handler: getPosts)
blogAPIRouter.post("newPost", handler: newPost)
// MARK: Get Posts
func getPosts(_ request: Request) throws -> ResponseRepresentable
let posts = try Post.all().makeNode()
return try JSON(node: [
"Posts":posts
])
// Mark: New Post
func newPost(_ request: Request) throws -> ResponseRepresentable
guard let title = request.data["title"]?.string,
let content = request.data["content"]?.string else
throw Abort.badRequest
var post = Post(title: title, content: content)
try post.save()
return "success"
// Mark: Get Posts Rendered
func getPostsView(_ request: Request) throws -> ResponseRepresentable
return try getPosts(request)
【讨论】:
【参考方案2】:我还不是 Vapor 方面的专家,但我认为您需要使用 .makeNode()
以便将您的 postCollection
对象转换为您以后可以在模板上使用的东西。
类似这样的:
drop.view.make("blog", ["posts":postCollection.makeNode()])
【讨论】:
我最终做的是,我使后模型符合模型协议。然后我这样做是为了返回帖子对象:` // MARK: Get Posts func getPosts(_ request: Request) throws -> ResponseRepresentable let posts = try Post.all().makeNode() return try JSON(node: [ " Posts":posts ]) ` 这是节点可表示的,所以它可以用于视图的渲染。【参考方案3】:func list(_ req: Request) throws -> ResponseRepresentable
let list = try User.all()
let node = try list.makeNode(in: nil)
let json = try JSON(node: [ "list":node ])
return json
【讨论】:
以上是关于在 Swift Vapor 中返回响应可表示对象集合的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
哪个框架/包可用于 Swift Linux,也可用于 Vapor [关闭]