Skip to content
This repository has been archived by the owner on Apr 20, 2024. It is now read-only.

Model with property not present in Request #18

Open
hsharghi opened this issue Jun 6, 2018 · 3 comments
Open

Model with property not present in Request #18

hsharghi opened this issue Jun 6, 2018 · 3 comments

Comments

@hsharghi
Copy link

hsharghi commented Jun 6, 2018

I have a simple Post model

// Post.swift
final class Post: MySQLModel, Content, Parameter {

    var id: Int?
    var title: String
    var body: String
    var userId: User.ID
}
extension Post: Submittable {
    convenience init(_ create: Post.Create) throws {
        self.init(id: nil, title: create.title, body: create.body, userId: create.userId)
    }
    
    func update(_ update: Post.Submission) throws {
        self.title = update.title ?? self.title
        self.body = update.body ?? self.body
    }
    
    
    struct Submission: SubmissionType {
        let title: String?
        let body: String?
    }
    
    struct Create: Decodable {
        let title: String
        let body: String
        let userId: User.ID
    }
}
extension Post.Submission {
    func fieldEntries() throws -> [FieldEntry<Post>] {
        return try [
            makeFieldEntry(keyPath: \.title, label: "Title", validators: [.count(5...)], isRequired: true),
            makeFieldEntry(keyPath: \.body, label: "Body", validators: [.count(10...)], isRequired: true),
        ]
    }
    
    init(_ post: Post?) {
        title = post?.title
        body = post?.body
    }
}
// PostController.swift
...
  func create(_ req: Request) throws -> Future<Either<Post, SubmissionValidationError>> {       
        let user = try req.authenticated(User.self)
        let userId = user?.id
        return try req.content.decode(Post.Submission.self)
            .createValid(on: req)
            .save(on: req)
            .promoteErrors()
    }

...

userId property needs to be added after a User obtained from token. It can not be sent in request parameters. It was the code before using Submissions

    func create(_ req: Request) throws -> Future<Post> {        
        let user = try req.authenticated(User.self)
        let userId = user?.id
        let postData = try req.content.syncDecode(Post.CreatePost.self)
        return Post(title: postData.title, body: postData.body, userId: userId!).save(on: req)
    }

Not all the properties of a model are sent via the request, some of them have to be calculated or fetched from DB and then use to create/save the model. Something like willCreate or willSave hook will be useful for these kind of situations.

@siemensikkema
Copy link
Contributor

Your situation seems like one that will be common. What if the Request would be passed into the init(_ create: Create) and update(_ update: Update) methods? Then you could authenticate there (or do any other database lookup) and set the user id. Would that solve your problem?

@hsharghi
Copy link
Author

hsharghi commented Jun 6, 2018

@siemensikkema Thanks, that would solve the problem.
But I think it will cause some inconsistency in codes, as the Request would pass to init, all the code that should be written in Controller section, have to be written in Model, or some duplicate code will be present in Model.
Is it possible to append optional parameters to create and update methods?
Like this:

 init(_ create: Post.Create, userId: userId) 

or pass a dictionary like in NotificationCenter's userInfo

@siemensikkema
Copy link
Contributor

siemensikkema commented Jun 7, 2018

How about the following:

let userID = try req.authenticated(User.self).requireID()
return try req.content
    .decode(Post.Submission.self)
    .validate(inContext: .create, on: req)
    .map { submission in
        Create(submission: submission, userId: userID)
    }
    .map(T.S.init)

For update you can simply change the user after updateValid and before save.

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

No branches or pull requests

2 participants