Episode #358

Creating, Updating, and Deleting Records with Fluent

Series: Server-side Swift with Vapor

19 minutes
Published on October 4, 2018

This video is only available to subscribers. Get access to this video and 584 others.

Now that we have Fluent set up, let’s see how we can use it to add, update, and delete records to the database. We’ll get a taste for how futures work in Vapor, and we will also see some of the builtin features that Vapor has to make loading records from your routes really simple.

Episode Links

Create a route to save a record

In the routes file:

router.get("_demo") { req -> Future<String> in 
    let post = Post(title: "Hello Fluent", body: "This is how you set up a database using Vapor Fluent", author: "Ben")
    post.publishedAt = Date()

    return post.save(on: req).map { post in 
        return "Created post with ID: \(post.id!)"
    }
}

Deleting a record

We'll first see the hard way of doing it (because that's a great way to learn the magic behind Vapor) and then we'll look at an easier way.

router.delete("posts", Int.parameter) { req -> Future<String> in 

    let postId = try req.parameters.next(Int.self)
    return Post.find(postId, on: req).flatMap { maybePost in

        guard let post = maybePost else {
            throw Abort(.notFound)
        }

        return post.delete(on: req).map {
            return "deleted post: \(post.id!)"
        }
    }   
}

As it turns out, fetching a record and performing an action on it is a really common operation, so Fluent has a great feature for making this easier.

Automatically fetching records as route parameters

Let's open up our Post.swift file and add this at the bottom:

extension Post : Parameter {}

We can then alter the route above like this:

router.delete("posts", Post.parameter) { req -> Future<String> in
    guard let futurePost = try? req.parameters.next(Post.self) else {
        throw Abort(.badRequest)
    }

    return futurePost.flatMap { post in
        return post.delete(on: req).map {
            return "deleted post: \(post.id!)"
        }
    }
}

This is a huge time saver and shows off the power of Vapor's integration with Fluent.

Updating Records

Let's finish up our example by creating a route that will publish a post. In this example I want to return the JSON of the post we are modifying.

Let's go back to Post.swift and add this at the bottom:

extension Post : Content {}

This tells Vapor that our model can be serialized. This uses Codable to return JSON representations of our models.

Now we can tell our route to simply return a Post (in the future).

// PUT /posts/1/publish
router.put("posts", Post.parameter, "publish") { req -> Future<Post> in

    try req.parameters.next(Post.self).flatMap { post in
        post.publishedAt = Date()
        return post.save(on: req)
    }
}

As you can see, once you get used to the Future syntax, manipulating records is fairly straightforward.

This episode uses Xcode 10.0, Fluentsqlite 3.0.0, Swift 4.2, Vapor 3.0.8.