加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

swift – 使Vapor API响应符合JSON API规范

发布时间:2020-12-14 04:49:51 所属栏目:百科 来源:网络整理
导读:我有一个用Vapor编写的API.我想按照 JSON API规范. 我正在努力理解如何以正确的格式创建我的响应对象. 例如,我希望我的回复结构如此…… { "links": { "self": "http://example.com/dish","next": "http://example.com/dish?page=2","last": "http://example
我有一个用Vapor编写的API.我想按照 JSON API规范.

我正在努力理解如何以正确的格式创建我的响应对象.

例如,我希望我的回复结构如此……

{
  "links": {
    "self": "http://example.com/dish","next": "http://example.com/dish?page=2","last": "http://example.com/dish?page=10"
  },"data": [{
    "title": "Spag Bol","course": "main","description": "BasGetti","price": 3.9900000000000002
  },{
    "title": "Ice Cream","course": "desert","description": "Vanilla","price": 0.98999999999999999
  }]
}

如果POST到此端点,我可以非常简单地返回数据的内容(伪代码)

router.post(Dish.self,at: "api/dish") { req,data -> Future<Dish> in
    return Future.map(on: req,{ () -> Dish in
        data.id = 001
        return data
    })
}

我尝试创建一个ApiResponse类并传入??数据,以便我可以构造响应,但这不适用于错误无法将类型’ApiResonse’的返回表达式转换为返回类型’Dish’

router.post(Dish.self,data -> Future<Dish> in
        return Future.map(on: req,{ () -> Dish in
            data.id = 001
            return ApiResonse(links: Links(self: "http://google.com",next: "http://google.com",last: "http://google.com"),data: data)
        })
    }

我不知道怎么能这样做.这些是尝试过的课程

final class Dish: Content {
    var id: Int?
    var title: String
    var description: String
    var course: String
    var price: Double

    init(title: String,description: String,course: String,price: Double) {
        self.title = title
        self.description = description
        self.course = course
        self.price = price
    }
}

struct Links {
    var `self`: String?
    var next: String?
    var last: String?
}

class ApiResonse {
    var links: Links?
    var data: Any

    init(links: Links,data: Any) {
        self.links = links
        self.data = data
    }
}

我是否需要使用泛型来设置响应类?有人能提供一个例子吗?

解决方法

>复合对象ApiResponse中的每个类或结构都需要符合内容协议. Content协议包括用于JSON解码和编码的Codable协议.
>请注意,Any不符合Codable协议,因此Any不能用作Response的任何组成部分.有关更多详细信息,请参见 Vapor Docs: “Using Content”.

In Vapor 3,all content types (JSON,protobuf,URLEncodedForm,Multipart,etc) are treated the same. All you need to parse and serialize content is a Codable class or struct.

>完全符合Content的对象或复合对象可用作ResponseEncodable响应.
>当每个路由端点解析为特定的符合内容协议的类型时,ApiResponse模型可以是通用的.

以下代码的示例项目位于GitHub: VaporExamplesLab/Example-SO-VaporJsonResponse.

示例模型

struct Dish: Content {
    var id: Int?
    var title: String
    var description: String
    var course: String
    var price: Double

    init(id: Int? = nil,title: String,price: Double) {
        self.id = id
        self.title = title
        self.description = description
        self.course = course
        self.price = price
    }
}

struct Links: Content {
    var current: String?
    var next: String?
    var last: String?
}

struct ApiResponse: Content {
    var links: Links?
    var dishes: [Dish]

    init(links: Links,dishes: [Dish]) {
        self.links = links
        self.dishes = dishes
    }
}

示例POST:返回ApiResponse

router.post(Dish.self,at: "api/dish") { 
    (request: Request,dish: Dish) -> ApiResponse in
    var dishMutable = dish
    dishMutable.id = 001

    var links = Links()
    links.current = "http://example.com"
    links.next = "http://example.com"
    links.last = "http://example.com"

    return ApiResponse(links: links,dishes: [dishMutable])
}

示例POST:返回Future< ApiResponse>

router.post(Dish.self,at: "api/dish-future") { 
    (request: Request,dish: Dish) -> Future<ApiResponse> in
    var dishMutable = dish
    dishMutable.id = 002

    var links = Links()
    links.current = "http://example.com"
    links.next = "http://example.com"
    links.last = "http://example.com"

    return Future.map(on: request,{ 
        () -> ApiResponse in
        return ApiResponse(links: links,dishes: [dishMutable])
    }) 
}

收到JSON响应

上述代码的Response主体产生以下内容:

{
  "links": {
    "current": "http://example.com","next": "http://example.com","last": "http://example.com"
  },"dishes": [
    {
      "id": 1,"title": "Aztec Salad","description": "Flavorful Southwestern ethos with sweet potatos and black beans.","course": "salad","price": 1.82
    }
  ]
}

通用模型

struct ApiResponseGeneric<T> : Content where T: Content { 
    var links: Links?
    var data: T

    init(links: Links,data: T) {
        self.links = links
        self.data = data
    }
}

具体路线终点

router.post(Dish.self,at: "api/dish-generic-future") { 
    (request: Request,dish: Dish) -> Future<ApiResponseGeneric<[Dish]>> in
    var dishMutable = dish
    dishMutable.id = 004

    var links = Links()
    links.current = "http://example.com"
    links.next = "http://example.com"
    links.last = "http://example.com"

    return Future.map(on: request,{ 
        () -> ApiResponseGeneric<[Dish]> in
        return ApiResponseGeneric<[Dish]>(links: links,data: [dishMutable])
    }) 
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读