Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vapor 3 - Returning a different Future when a search fails?

Tags:

swift

vapor

I'm using Vapor 3 and linking to a FoundationDB database, so Im not using Fluent. I have a method that searches for a record, but it will obviously crash if it does not return a record (because I force unwrap the value).

I want to guard the reading from the database and return a response if no record is found. This will however not be the record as was expected in the Future. I was thinking that I should return a different response, but am unsure how to change the result that is expected.

//creates a specific country
func getCountry( req: Request) throws -> Future<Country> {
    // get Country name from get parameter string
    let countryString = try req.parameters.next(String.self)


    // get record from Database. This could fail and so needs to be guarded. What response should be returned as the Future requires a Country datatype?

       let record =  FDBConnector().getRecord(path: Subspace("iVendor").subspace(["Countries", countryString]))



    let newCountry = try JSONDecoder().decode(Country.self, from: record!)
    // return Country Struct
    return Future.map(on: req) {return newCountry }

}
like image 849
salongley Avatar asked Jan 28 '23 16:01

salongley


1 Answers

There are a couple of options here.

First, if you throw an error from the method:

guard let record =  FDBConnector().getRecord(path: Subspace("iVendor").subspace(["Countries", countryString])) else {
    throw Abort(.notFound, reason: "No country found with name \(countryString)")
}

The error will get converted to a 404 (Not Found) response with "No country found with name \(countryString)" as the error message.

If you want more control over the resulting response, you can change the route hander's return type to Future<Response>. You can then encode the Country object to the response or create a custom error response. This method does take some extra work though.

let response = Response(using: req)
guard let record =  FDBConnector().getRecord(path: Subspace("iVendor").subspace(["Countries", countryString])) else {
    try response.content.encode(["message": "Country not found"])
    response.http.status = .notFound
    return response
}

try response.content.encode(record)
return response

Note that you will have to conform Country to Content if you want that snippet to work.

like image 192
Caleb Kleveter Avatar answered Feb 16 '23 16:02

Caleb Kleveter