marked-down
marked-down

Reputation: 10418

Concise method of updating a model to match a request body with Swift?

Given a controller method which accepts a request body which conforms to some or all of the properties in an entity in Vapor, is there a means of updating the entity without manually assigning all of it's properties? Currently, I'm having to do this:

func update(_ req: Request) throws -> Future<Mission> {
    let mission = try req.parameters.next(Mission.self)
    let content = try req.content.decode(Mission.self)

    return flatMap(to: Mission.self, mission, content) { (mission, content) in
       mission.propertyA = content.propertyA
       mission.propB = content.propB
       mission.propC = content.propC
       return mission.save(on: req)
    }
}

This isn't very scalable as it requires me to manually assign each property. What I'm looking for is something like this:

func update(_ req: Request) throws -> Future<Mission> {
    let mission = try req.parameters.next(Mission.self)
    let content = try req.content.decode(Mission.self)

    return mission.save(on: content)
}

However this yields the error Argument type 'EventLoopFuture<Mission>' does not conform to expected type 'DatabaseConnectable'.

What is a good solution here?

Upvotes: 0

Views: 329

Answers (2)

Vince
Vince

Reputation: 132

That error that you're receiving is because you're trying to save(on: content), you need to save on the request:

return mission.save(on: req)

That being said, what you really want is this:

func update(_ req: Request) throws -> Future<Mission> {

    let updatedMission = try req.content.decode(Mission.self)

    return updatedMission.update(on: req)
}

This decodes a Mission object that is in the request body and then updates the Mission with the corresponding id in the database. So make sure when you're sending Mission JSON in the body that it has an id.

Upvotes: 1

siemensikkema
siemensikkema

Reputation: 56

With Submissions you should be able to do:

func create(req: Request) throws -> Future<Either<Mission, SubmissionValidationError>> {
    return try req.content.decode(Mission.Submission.self)
        .updateValid(on: req)
        .save(on: req)
        .promoteErrors()
}

It takes some setting up but it's flexible and allows you to validate your input. The promoteErrors function + Either in the result help create useful error response but you could do without them.

Upvotes: 1

Related Questions