mirror of
https://github.com/eliasrenman/url-shortener.git
synced 2026-03-16 20:16:06 +01:00
feat: inital redirect api
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -165,6 +165,7 @@ dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-link",
|
||||
]
|
||||
@@ -1092,6 +1093,7 @@ dependencies = [
|
||||
"rocket_codegen",
|
||||
"rocket_http",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"state",
|
||||
"tempfile",
|
||||
"time",
|
||||
|
||||
10
Cargo.toml
10
Cargo.toml
@@ -2,11 +2,11 @@
|
||||
name = "url-shortener"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
build = "build.rs"
|
||||
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4.40"
|
||||
diesel = { version = "2.2.8", features = ["sqlite","chrono"] }
|
||||
chrono = { version = "0.4.40", features = ["serde"] }
|
||||
diesel = { version = "2.2.8", features = ["sqlite", "chrono"] }
|
||||
dotenvy = "0.15.7"
|
||||
rocket = "0.5.1"
|
||||
serde = "1.0.219"
|
||||
rocket = { version = "0.5.1", features = ["json"] }
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
|
||||
13
build.rs
13
build.rs
@@ -1,13 +0,0 @@
|
||||
use std::process::Command;
|
||||
|
||||
fn main() {
|
||||
let status = Command::new("bun")
|
||||
.args(["run", "build"])
|
||||
.current_dir("web") // Change working directory to "web"
|
||||
.status()
|
||||
.expect("Failed to run bun build");
|
||||
|
||||
if !status.success() {
|
||||
panic!("Bun build failed!");
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
-- This file should undo anything in `up.sql`
|
||||
DROP TRIGGER url_update_at_trigger;
|
||||
DROP TRIGGER urls_update_at_trigger;
|
||||
|
||||
DROP TABLE url;
|
||||
DROP TABLE urls;
|
||||
|
||||
@@ -14,6 +14,6 @@ UPDATE urls
|
||||
SET
|
||||
updated_at = STRFTIME ('%Y-%m-%d %H:%M:%f', 'NOW')
|
||||
WHERE
|
||||
URLS = NEW.URLS;
|
||||
url = NEW.url;
|
||||
|
||||
END;
|
||||
|
||||
@@ -2,7 +2,7 @@ use super::schema::urls;
|
||||
use chrono::NaiveDateTime;
|
||||
use diesel::prelude::*;
|
||||
|
||||
#[derive(Queryable, Selectable)]
|
||||
#[derive(Queryable, Selectable, AsChangeset)]
|
||||
#[diesel(table_name = urls)]
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
pub struct Urls {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use self::db::models::Urls;
|
||||
use crate::db::schema::urls::dsl::*;
|
||||
use super::schema::urls::dsl::*;
|
||||
use super::schema::urls::*;
|
||||
use crate::*;
|
||||
use chrono::NaiveDateTime;
|
||||
use diesel::{delete, dsl::insert_into, prelude::*, result::Error};
|
||||
@@ -15,7 +16,7 @@ pub fn upsert_entry(
|
||||
time_to_live: Option<NaiveDateTime>,
|
||||
) -> Result<usize, Error> {
|
||||
let connection = &mut establish_connection();
|
||||
insert_into(urls)
|
||||
insert_into(table)
|
||||
.values((url.eq(path), destination_url.eq(dest), ttl.eq(time_to_live)))
|
||||
.on_conflict(url)
|
||||
.do_update()
|
||||
|
||||
10
src/dto/mod.rs
Normal file
10
src/dto/mod.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
use chrono::NaiveDateTime;
|
||||
use rocket::serde::{Deserialize, Serialize};
|
||||
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct UpsertUrlDto<'r> {
|
||||
pub url: &'r str,
|
||||
pub destination_url: &'r str,
|
||||
pub ttl: Option<NaiveDateTime>,
|
||||
}
|
||||
@@ -1,8 +1,27 @@
|
||||
use rocket::{http::Status, response::Redirect};
|
||||
|
||||
use crate::db::url::get_entry;
|
||||
use crate::{
|
||||
db::url::{delete_entry, get_entry, upsert_entry},
|
||||
dto::UpsertUrlDto,
|
||||
};
|
||||
|
||||
pub fn handle_redirect(url: &str) -> Result<Redirect, (Status, &'static str)> {
|
||||
let row = get_entry(url).map_err(|_| (Status::NotFound, "Redirect Not found"))?;
|
||||
Ok(Redirect::to(row.destination_url))
|
||||
}
|
||||
|
||||
pub fn handle_upsert(dto: UpsertUrlDto<'_>) -> (Status, &'static str) {
|
||||
let row = upsert_entry(dto.url, dto.destination_url, dto.ttl);
|
||||
if row.is_err() {
|
||||
return (Status::BadRequest, "Failed to upsert redirect");
|
||||
}
|
||||
(Status::Ok, "Successfully upserted redirect")
|
||||
}
|
||||
|
||||
pub fn handle_delete(url: &str) -> (Status, &'static str) {
|
||||
let row = delete_entry(url);
|
||||
if row.is_err() {
|
||||
return (Status::BadRequest, "Failed to delete redirect");
|
||||
}
|
||||
(Status::Ok, "Successfully deleted redirect")
|
||||
}
|
||||
|
||||
22
src/main.rs
22
src/main.rs
@@ -1,9 +1,12 @@
|
||||
use db::establish_connection;
|
||||
use handlers::url::handle_redirect;
|
||||
use rocket::{http::Status, response::Redirect};
|
||||
mod db;
|
||||
mod dto;
|
||||
mod handlers;
|
||||
|
||||
use db::establish_connection;
|
||||
use handlers::url::{handle_delete, handle_redirect, handle_upsert};
|
||||
use rocket::fs::{FileServer, relative};
|
||||
use rocket::serde::json::Json;
|
||||
use rocket::{http::Status, response::Redirect};
|
||||
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
@@ -11,10 +14,21 @@ extern crate rocket;
|
||||
#[launch]
|
||||
fn rocket() -> _ {
|
||||
rocket::build()
|
||||
.mount("/", routes![shortner])
|
||||
.mount("/", routes![shortner,])
|
||||
.mount("/api", routes![upsert, delete])
|
||||
.mount("/", FileServer::from(relative!("web/dist")))
|
||||
}
|
||||
#[get("/<url>")]
|
||||
fn shortner(url: &str) -> Result<Redirect, (Status, &'static str)> {
|
||||
handle_redirect(url)
|
||||
}
|
||||
|
||||
#[post("/write", format = "json", data = "<upsert>")]
|
||||
fn upsert(upsert: Json<dto::UpsertUrlDto<'_>>) -> (Status, &'static str) {
|
||||
handle_upsert(upsert.0)
|
||||
}
|
||||
|
||||
#[delete("/<url>")]
|
||||
fn delete(url: &str) -> (Status, &'static str) {
|
||||
handle_delete(url)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user