Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handy JSON response #50

Open
gotev opened this issue Dec 9, 2022 · 2 comments
Open

Handy JSON response #50

gotev opened this issue Dec 9, 2022 · 2 comments

Comments

@gotev
Copy link

gotev commented Dec 9, 2022

JSON responses are common for a web server. With this extension (serializing dates as millis by default to ease JS clients):

extension HTTPResponse {
    static let jsonTimestampMillisEncoder: JSONEncoder = {
        let jsonEncoder = JSONEncoder()
        jsonEncoder.dateEncodingStrategy = .millisecondsSince1970

        return jsonEncoder
    }()

    static func json(_ encodable: Encodable, jsonEncoder: JSONEncoder = jsonTimestampMillisEncoder) throws -> HTTPResponse {
        HTTPResponse(statusCode: .ok, body: try jsonEncoder.encode(encodable))
    }
}

one can easily return a JSON ready to be consumed by another application:

struct Cat: Codable {
    let birthDate: Date
    let name: String
}

struct MyHandler : HTTPHandler {
    func handleRequest(_ request: HTTPRequest) async throws -> HTTPResponse {
        try .json(Cat(birthDate: Date(), name: "Loris"))
    }
}

If you think it's a valuable addition, feel free to add it in the library 🍻

@swhitty
Copy link
Owner

swhitty commented Mar 5, 2023

Thank you for the suggestion 🙏🏻.

I also use extensions similar to these in my own projects. As you have illustrated the difficulty is in choosing appropriate defaults for things like Date encoding and the status code to return.

@swhitty
Copy link
Owner

swhitty commented Oct 29, 2023

Hi @gotev I've been thinking a lot about your suggestion think there is a nice declarative solution SE-0389 Attached Macros available in Swift 5.9 and later.

I'm interested in your feedback, the implementation is currently available on the branch preview/macro where handlers can annotate functions with routes:

@HTTPHandler
struct MyHandler {

  static let jsonTimestampMillisEncoder: JSONEncoder = {
    let jsonEncoder = JSONEncoder()
    jsonEncoder.dateEncodingStrategy = .millisecondsSince1970
    return jsonEncoder
  }()

  @JSONRoute("/cat", encoder: Self.jsonTimestampMillisEncoder)
  func getCat() -> Cat {
    Cat(birthDate: Date(), name: "Loris")
  }
}

let server = HTTPServer(port: 80, handler: MyHandler())
try await server.start()

The macro synthesises conformance to HTTPHandler delegating handling to the first matching route.
Read more here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants