|
| 1 | +use postgres::{Client, NoTls}; |
| 2 | +use postgres::Error as PostgresError; |
| 3 | +use std::net::{TcpListener, TcpStream}; |
| 4 | +use std::io::{Read, Write}; |
| 5 | +use std::env; |
| 6 | + |
| 7 | +#[macro_use] |
| 8 | +extern crate serde_derive; |
| 9 | + |
| 10 | +// model |
| 11 | +#[derive(Serialize, Deserialize)] |
| 12 | +struct User { |
| 13 | + id: Option<i32>, |
| 14 | + name: String, |
| 15 | + email: String, |
| 16 | +} |
| 17 | + |
| 18 | +const DB_URL: &str = !env("DATABASE_URL"); |
| 19 | +const RESPONSE_OK: &str = "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n"; |
| 20 | +const RESPONSE_NOT_FOUND: &str = "HTTP/1.1 404 NOT FOUND\r\n\r\n"; |
| 21 | +const RESPONSE_INTERNAL_SERVER_ERROR: &str = "HTTP/1.1 500 INTERNAL SERVER ERROR\r\n\r\n"; |
| 22 | + |
1 | 23 | fn main() {
|
2 |
| - println!("Hello, world!"); |
| 24 | + if let Err(e) = set_database() { |
| 25 | + println!("Error: {}", e); |
| 26 | + return; |
| 27 | + } |
| 28 | + |
| 29 | + let listener = TcpListener::bind(format!("0.0.0.0:8080")).unwrap(); |
| 30 | + println!("Server started at port 8080"); |
| 31 | + |
| 32 | + for stream in listener.incoming() { |
| 33 | + match stream { |
| 34 | + Ok(stream) => { |
| 35 | + handle_client(stream); |
| 36 | + } |
| 37 | + Err(e) => { |
| 38 | + println!("Error: {}", e); |
| 39 | + } |
| 40 | + } |
| 41 | + } |
| 42 | +} |
| 43 | + |
| 44 | +fn handle_client(mut stream: TcpStream) { |
| 45 | + let mut buffer = [0; 1024]; |
| 46 | + let mut request = String::new(); |
| 47 | + |
| 48 | + match stream.read(&mut buffer) { |
| 49 | + Ok(size) => { |
| 50 | + request.push_str(String::from_utf8_lossy(&buffer[..size]).as_ref()); |
| 51 | + |
| 52 | + let (status_line, content) = match &*request { |
| 53 | + r if request_with("POST /users") => handle_post_request(r), |
| 54 | + r if request_with("GET /users") => handle_get_request(r), |
| 55 | + r if request_with("GET /users") => handle_get_all_request(r), |
| 56 | + r if request_with("PUT /users") => handle_put_request(r), |
| 57 | + r if request_with("DELETE /users") => handle_delete_request(r), |
| 58 | + _ => (NOT_FOUND, "Not found".to_string()), |
| 59 | + }; |
| 60 | + |
| 61 | + stream.write_all(format!("{}{}", status_line, content).as_bytes()).unwrap(); |
| 62 | + } |
| 63 | + Err(e) => { |
| 64 | + println!("Error: {}", e); |
| 65 | + } |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +// controllers |
| 70 | + |
| 71 | +fn handle_post_request(request: &str) -> (String, String) { |
| 72 | + match (get_user_request_body(&request), Client::connect(DB_URL, NoTls)) { |
| 73 | + (Ok(user), Ok(mut client)) => { |
| 74 | + client.execute("INSERT INTO users(name, email) VALUES ($1, $2)", |
| 75 | + &[&user.name, &user.email] |
| 76 | + ).unwrap(); |
| 77 | + |
| 78 | + (RESPONSE_OK.to_string(), "User created".to_string()) |
| 79 | + } |
| 80 | + _ => (RESPONSE_INTERNAL_SERVER_ERROR.to_string(), "Error".to_string()), |
| 81 | + } |
| 82 | +} |
| 83 | + |
| 84 | +fn handle_get_request(request: &str) -> (String, String) { |
| 85 | + match (get_id(&request).parse::<i32>(), Client::connect(DB_URL, NoTls)) { |
| 86 | + (Ok(id), Ok(mut client)) => |
| 87 | + match client.query_one("SELECT * FROM users WHERE id = $1", &[&id]) { |
| 88 | + Ok(row) => { |
| 89 | + let user = User { |
| 90 | + id: row.get(0), |
| 91 | + name: row.get(1), |
| 92 | + email: row.get(2), |
| 93 | + }; |
| 94 | + |
| 95 | + (RESPONSE_OK.to_string(), serde_json::to_string(&user).unwrap()) |
| 96 | + } |
| 97 | + _ => (RESPONSE_NOT_FOUND.to_string(), "User not found".to_string()), |
| 98 | + } |
| 99 | + |
| 100 | + _ => (RESPONSE_INTERNAL_SERVER_ERROR.to_string(), "Internal error".to_string()), |
| 101 | + } |
| 102 | +} |
| 103 | + |
| 104 | +fn handle_get_all_request(_request: &str) -> (String, String) { |
| 105 | + match Client::connect(DB_URL, NoTls) { |
| 106 | + Ok(mut client) => { |
| 107 | + let mut users = Vec::new(); |
| 108 | + |
| 109 | + for row in client.query("SELECT id, name, email FROM users", &[]).unwrap() { |
| 110 | + users.push(User { |
| 111 | + id: row.get(0), |
| 112 | + name: row.get(1), |
| 113 | + email: row.get(2), |
| 114 | + }); |
| 115 | + } |
| 116 | + |
| 117 | + (RESPONSE_OK.to_string(), serde_json::to_string(&users).unwrap()) |
| 118 | + } |
| 119 | + _ => (RESPONSE_INTERNAL_SERVER_ERROR.to_string(), "Internal error".to_string()), |
| 120 | + } |
| 121 | +} |
| 122 | + |
| 123 | +fn handle_put_request(request: &str) -> (String, String) { |
| 124 | + match |
| 125 | + ( |
| 126 | + get_id(&request).parse::<i32>(), |
| 127 | + get_user_request_body(&request), |
| 128 | + Client::connect(DB_URL, NoTls), |
| 129 | + ) |
| 130 | + { |
| 131 | + (Ok(id), Ok(user), Ok(mut client)) => { |
| 132 | + client |
| 133 | + .execute( |
| 134 | + "UPDATE users SET name = $1, email = $2 WHERE id = $3", |
| 135 | + &[&user.name, &user.email, &id] |
| 136 | + ) |
| 137 | + .unwrap(); |
| 138 | + |
| 139 | + (RESPONSE_OK.to_string(), "User updated".to_string()) |
| 140 | + } |
| 141 | + _ => (RESPONSE_INTERNAL_SERVER_ERROR.to_string(), "Internal error".to_string()), |
| 142 | + } |
| 143 | +} |
| 144 | + |
| 145 | +fn handle_delete_request(request: &str) -> (String, String) { |
| 146 | + match (get_id(&request).parse::<i32>(), Client::connect(DB_URL, NoTls)) { |
| 147 | + (Ok(id), Ok(mut client)) => { |
| 148 | + let rows_affected = client.execute("DELETE FROM users WHERE id = $1", &[&id]).unwrap(); |
| 149 | + |
| 150 | + if rows_affected == 0 { //if rows affected is 0, user not found |
| 151 | + return (RESPONSE_NOT_FOUND.to_string(), "User not found".to_string()); |
| 152 | + } |
| 153 | + |
| 154 | + (RESPONSE_OK.to_string(), "User deleted".to_string()) |
| 155 | + } |
| 156 | + _ => (RESPONSE_INTERNAL_SERVER_ERROR.to_string(), "Internal error".to_string()), |
| 157 | + } |
| 158 | +} |
| 159 | + |
| 160 | +// Utility functions |
| 161 | + |
| 162 | +fn set_database() -> Result<(), PostgresError> { |
| 163 | + let mut client = Client::connect(DB_URL, NoTls)?; |
| 164 | + client.batch_execute( |
| 165 | + " |
| 166 | + CREATE TABLE IF NOT EXISTS users ( |
| 167 | + id SERIAL PRIMARY KEY, |
| 168 | + name VARCHAR NOT NULL, |
| 169 | + email VARCHAR NOT NULL |
| 170 | + ) |
| 171 | + " |
| 172 | + )?; |
| 173 | + Ok(()) |
| 174 | +} |
| 175 | + |
| 176 | +fn get_id(request: &str) -> &str { |
| 177 | + request.split("/") |
| 178 | + .nth(2) |
| 179 | + .unwrap_or_default() |
| 180 | + .split_whitespace() |
| 181 | + .next() |
| 182 | + .unwrap_or_default() |
| 183 | +} |
| 184 | + |
| 185 | +fn get_user_request_body(request: &str) -> Result<User, serde_json::Error> { |
| 186 | + serde_json::from_str(request.split("\r\n\r\n").last().unwrap_or_default()) |
3 | 187 | }
|
0 commit comments