Skip to content

Instantly share code, notes, and snippets.

@vzsg
Created March 3, 2019 11:19
Using SwiftProtobuf with Vapor 3
import Vapor
import SwiftProtobuf
import Foundation
extension Request {
public func decodeMessage<M: SwiftProtobuf.Message>(_ type: M.Type = M.self) throws -> M {
let data = http.body.data ?? Data()
if http.contentType == MediaType.json {
return try M(jsonUTF8Data: data)
}
return try M(serializedData: data)
}
}
extension SwiftProtobuf.Message {
fileprivate func toHTTPResponse(json: Bool = false) throws -> HTTPResponse {
var http = HTTPResponse(status: .ok)
if json {
http.contentType = MediaType.json
http.body = try jsonUTF8Data().convertToHTTPBody()
} else {
http.contentType = MediaType(type: "application", subType: "x-protobuf")
http.body = try serializedData().convertToHTTPBody()
}
return http
}
public func toResponse(on req: Request) throws -> Response {
let json = req.http.accept.contains(where: { $0.mediaType == MediaType.json })
return Response(http: try toHTTPResponse(json: json), using: req)
}
}
extension Future {
public func toResponse<M>(_ type: M.Type = M.self, on req: Request) -> Future<Response> where Expectation: SwiftProtobuf.Message {
return map { try $0.toResponse(on: req) }
}
}
router.get("test") { req -> Response in
var profile = Proto_UserProfile()
var user = Proto_User()
user.nickname = "FooBar"
user.firstName = "Foo"
user.lastName = "Bar"
profile.user = user
return try profile.toResponse(on: req)
}
// Calling without an accept header: curl localhost:8080/test
// --> returns binary message
// Calling with accept header: curl localhost:8080/test -H "Accept: application/json"
// --> returns JSON
// {"user":{"nickname":"FooBar","firstName":"Foo","lastName":"Bar"}}
@3a4oT
Copy link

3a4oT commented Jan 25, 2020

Thanks for sharing! It is clever!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment