CRUD with Actix-Web + Diesel + Postgres
TL;DR
I want types -- real types, not Python's Typing. So I've been getting started with Actix-web. For now, let's try doing CRUD with Diesel.
Basically, we'll reproduce the Diesel Getting Started guide using Actix-web.
Setup
First, install Diesel. Since we're using PostgreSQL this time, we only enable the postgres feature. We need libpq-dev for PostgreSQL, so install that first.
Start PostgreSQL. We'll use docker-compose this time.
docker-compose.yaml
Create an .env file for environment variables.
Create the project and run migrations.
A directory called migrations/${date}_create_posts should have been created containing up.sql and down.sql. up.sql is used when running migration run, and down.sql is used when running migration redo. Modify them as follows.
up.sql
down.sql
Run the migration.
That completes the setup.
Writing Rust
Let's add the dependencies we'll use. We use Diesel as the ORM, serde for JSON handling, and anyhow for error handling.
Cargo.tml
Hello, World
First, let's do a Hello World with Actix-Web.
Directory Structure
The directory structure above is what we'll be using. The roles are as their names suggest -- I just created a directory for routing. We'll implement PUT in the publish module.
Database Setup
First, write the configuration for connecting to the database. We'll also give shorter names to long types.
database.rs
Write the models. They need to be Serialize/Deserialize for JSON when returning via GET or receiving via POST. Add Queryable to types used with queries, and Insertable to types used with POST.
models.rs
Implementing CRUD
First, let's write the mod.rs files.
routes/mod.rs
routes/posts/mod.rs
Then add the following to main.rs.
main.rs
Implementing GET and POST
Return all Posts. Since Diesel doesn't support tokio, we use web::block.
routes/posts/get.rs
Since we haven't inserted anything yet, GET will only return an empty list, so let's implement POST as well.
routes/posts/post.rs
Update main.rs. Add routing and the database connection.
main.rs
Let's try it out.
Implementing PUT
Implement PUT to change the publish status. For simplicity, sending a request to /posts/publish/$post_id will set the post to published.
web::Path<T> becomes T when calling to_owned.
routes/posts/publish.rs
After adding the routing to main.rs, let's run it.
Implementing DELETE
DELETE at /posts/$post_id.
Add the routing and run it.
CRUD is complete.
Conclusion
The implementation is available below. It has a few more features added.