Rust program is not inserting inserting row into Postgres

Rust program is not inserting inserting row into Postgres
typescript
Ethan Jackson

Am following a Rust tutorial online which consists of creating a minimal Rust HTTP server which uses a Postgres database in a Docker container. Am running this inside my macOS Sequoia via Docker Desktop.

rust-crud-api/cargo.toml:

[package] name = "rust-crud-api" version = "0.1.0" edition = "2021" [dependencies] postgres = "0.19.10" serde = "1.0.219" serde_json = "1.0.140" serde_derive = "1.0.219"

rust-crud-api/main.rs:

use postgres::Error as PostgresError; use postgres::{Client, NoTls}; use std::env; use std::io::{Read, Write}; use std::net::{TcpListener, TcpStream}; #[macro_use] extern crate serde_derive; #[derive(Serialize, Deserialize)] struct User { id: Option<i32>, name: String, email: String, } const DB_URL: &str = env!("DATABASE_URL"); const OK_RESPONSE: &str = "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n"; const NOT_FOUND: &str = "HTTP/1.1 404 NOT FOUND\r\n\r\n"; const INTERNAL_SERVER_ERROR: &str = "HTTP/1.1 500 INTERNAL SERVER ERROR\r\n\r\n"; fn main() { if let Err(e) = set_database() { println!("Error: {}", e); return; } let listener = TcpListener::bind(format!("0.0.0.0:8080")).unwrap(); println!("Server started at port 8080"); for stream in listener.incoming() { match stream { Ok(stream) => { handle_client(stream); } Err(e) => { println!("Error: {}", e); } } } } fn handle_client(mut stream: TcpStream) { let mut buffer = [0; 1024]; let mut request = String::new(); match stream.read(&mut buffer) { Ok(size) => { request.push_str(String::from_utf8_lossy(&buffer[..size]).as_ref()); let (status_line, content) = match &*request { r if r.starts_with("POST /users") => handle_post_request(r), r if r.starts_with("GET /users") => handle_get_all_request(r), _ => (NOT_FOUND.to_string(), "404 Not Found".to_string()), }; stream .write_all(format!("{}{}", status_line, content).as_bytes()) .unwrap(); } Err(e) => { println!("Error: {}", e); } } } fn handle_post_request(request: &str) -> (String, String) { match ( get_user_request_body(&request), Client::connect(DB_URL, NoTls), ) { (Ok(user), Ok(mut client)) => { client .execute( "INSERT INTO users (name, email) VALUES ($1, $2)", &[&user.name, &user.email], ) .unwrap(); (OK_RESPONSE.to_string(), "User created".to_string()) } _ => (INTERNAL_SERVER_ERROR.to_string(), "Error".to_string()), } } fn handle_get_all_request(request: &str) -> (String, String) { match Client::connect(DB_URL, NoTls) { Ok(mut client) => { let mut users = Vec::new(); for row in client.query("SELECT * FROM users", &[]).unwrap() { users.push(User { id: row.get(0), name: row.get(1), email: row.get(2), }); } ( OK_RESPONSE.to_string(), serde_json::to_string(&users).unwrap(), ) } _ => (INTERNAL_SERVER_ERROR.to_string(), "Error".to_string()), } } fn get_id(request: &str) -> &str { request .split("/") .nth(2) .unwrap_or_default() .split_whitespace() .next() .unwrap_or_default() } fn get_user_request_body(request: &str) -> Result<User, serde_json::Error> { serde_json::from_str(request.split("\r\n\t\n").last().unwrap_or_default()) } fn set_database() -> Result<(), PostgresError> { let mut client = Client::connect(DB_URL, NoTls)?; client.batch_execute( "CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, name VARCHAR NOT NULL, email VARCHAR NOT NULL )", )?; Ok(()) }

rust-crud-api/Dockerfile:

FROM rust:1.86.0 as builder WORKDIR /app ARG DATABASE_URL ENV DATABASE_URL=$DATABASE_URL COPY . . RUN cargo build --release FROM ubuntu:25.04 WORKDIR /usr/local/bin COPY --from=builder /app/target/release/rust-crud-api . CMD ["./rust-crud-api"]

rust-crud-api/docker-compose.yml:

services: rustapp: container_name: rustapp image: francescoxx/rustapp:1.0.0 build: context: . dockerfile: Dockerfile args: DATABASE_URL: postgres://postgres:postgres@db:5432/postgres ports: - '8080:8080' depends_on: - db db: container_name: db image: postgres:12 environment: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: postgres ports: - '5432:5432' volumes: - pgdata:/var/lib/postgresql/data volumes: pgdata: {}

  1. Setup the database using docker compose:

docker compose up -d db

  1. Built and ran the Rust app:

docker compose up rustapp

When I go to Postman and hit the http://localhost:8080/users endpoint, I get the following:

HTTP 200 OK

Response body is an empty JSON array (since no users have been created/inserted):

[]

  1. When I try doing a HTTP POST against the http://localhost:8080/users endpoint with the following JSON request body/payload:
{ "name": "joe", "email": "

Receive an HTTP 500 with Error for the Response body.

There are no errors written to stdout, however...

  1. When I go inside the Postgres instance the users table is created but empty:

docker exec -it db psql -U postgres

postgres=# \dt List of relations Schema | Name | Type | Owner --------+-------+-------+---------- public | users | table | postgres (1 row) postgres=# SELECT * FROM users; id | name | email ----+------+------- (0 rows)

What am I possibly doing wrong? Thanks in advance!

Answer

The problem was the \t escape sequence inside this function:

fn get_user_request_body(request: &str) -> Result<User, serde_json::Error> { serde_json::from_str(request.split("\r\n\t\n").last().unwrap_or_default()) }

Fix was replacing that \t with a \r:

serde_json::from_str(request.split("\r\n\r\n").last().unwrap_or_default())

Related Articles