So I'm trying to create a basic actix-web application that will allow me to create a very basic blog system. It is handling my GET requests, but it's not handling my POST requests.
main.rs:
use actix_web::{HttpServer, App, web};
use sqlx::postgres::PgPool;
use dotenv::dotenv;
mod posts;
mod database;
#[actix_web::main]
pub async fn main() -> std::io::Result<()>{
dotenv().ok();
let pool = PgPool::connect(&dotenv::var("DATABASE_URL").unwrap()).await.unwrap();
HttpServer::new(move || {
// The scope for all post services
let posts = web::scope("/posts").service(posts::get_all_posts).service(posts::create_post);
App::new()
.data(pool.clone())
.service(web::scope("/api").service(posts))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
posts/routes.rs:
use super::*;
use database::{NewPost, model::Post};
use actix_web::{get, post, Responder, HttpResponse};
#[get("/")]
pub async fn get_all_posts(pool: web::Data<PgPool>) -> impl Responder {
println!("New GET request for all posts!");
let result = Post::find_all(pool.get_ref()).await;
match result {
Ok(posts) => HttpResponse::Ok().json(posts),
_ => HttpResponse::BadRequest().body("Error trying to read all the posts from the database")
}
}
#[post("/new")]
pub async fn create_post(post: web::Json<NewPost>, pool: web::Data<PgPool>) -> impl Responder {
println!("New POST request to create a post!");
let result = Post::new_post(post.into_inner(), pool.as_ref()).await;
match result {
Ok(post) => HttpResponse::Ok().json(post),
_ => HttpResponse::BadRequest().body("Error trying to create a new post")
}
}
database/model.rs:
use serde::{Serialize, Deserialize};
use sqlx::{FromRow, PgPool, Row, postgres::PgRow};
use uuid::Uuid;
use chrono::prelude::*;
/// Struct to represent database record.
#[derive(Serialize, FromRow, Debug)]
pub struct Post {
pub id: Uuid,
pub content: String,
pub created_at: chrono::NaiveDateTime
}
/// Struct to receive user input.
#[derive(Serialize, Deserialize)]
pub struct NewPost {
pub content: String
}
impl Post {
pub async fn find_all(pool: &PgPool) -> std::io::Result<Vec<Post>> {
let mut posts = Vec::new();
let recs = sqlx::query_as!(Post, r#"SELECT id, content, created_at FROM post ORDER BY id"#)
.fetch_all(pool)
.await
.unwrap();
for rec in recs {
posts.push(Post {
id: rec.id,
content: rec.content,
created_at: rec.created_at
});
}
Ok(posts)
}
pub async fn new_post(post: NewPost, pool: &PgPool) -> std::io::Result<Post> {
let mut tx = pool.begin().await.unwrap();
let post = sqlx::query("INSERT INTO post (id, content, created_at) VALUES ($1, $2, $3) RETURNING id, content, created_at")
.bind(Uuid::new_v4())
.bind(post.content)
.bind(Utc::now())
.map(|row: PgRow| {
Post {
id: row.get(0),
content: row.get(1),
created_at: row.get(2)
}
})
.fetch_one(&mut tx)
.await
.unwrap();
tx.commit().await.unwrap();
Ok(post)
}
}
Currently, I am using curl to test out the API. When I want to send a GET request I use the command:
curl localhost:8080/api/posts/
When I run this command my rust application prints out the statement: "New GET request for all posts!" as I expected it to.
When I want to send a POST request I use the command:
curl -H "Content-Type: application/json" -X POST -d '{ \
"content": "This is my first post" \
}' localhost:8080/api/posts/new
After running this curl command I don't get any output at all, there is nothing from the curl terminal nor any output from my rust program.