Rust: Serverless URL Shortener Pakai Rust dan Cloudflare Worker - ID

Pengenalan

Rust: Serverless URL Shortener Pakai Rust dan Cloudflare Worker - ID
Photo by Thomas Tastet on Unsplash

Pengenalan

Pada artikel kali ini, kita akan coba membuat suatu URL shortener seperti bit.ly menggunakan bahasa pemrograman Rust, Platform Serverless Cloudflare Worker, dan Key-Value Database KV.

Disclaimer: Saya tidak disponsori atau terkait dengan CloudFlare.

Sebelum memulai proyek ini, diharapkan Anda memiliki kemampuan dalam bahasa Rust.

Prasayarat

  1. Rust
  2. Wrangler
  3. Cloudflare Account
  4. KV Namespaces

Cloudflare Workers

Cloudflare Worker adalah sebuah platform yang digunakan untuk menjalankan kode JavaScript, Rust, Python, dan bahasa lainnya di edge network Cloudflare, memungkinkan Anda untuk melakukan pemrosesan dan manipulasi data secara langsung di server terdekat dengan pengguna Anda. Cloudflare Worker akan kita gunakan sebagai “tempat” menjalakan proyek URL Shortener kita.

Cloudflare KV

Cloudflare Workers KV adalah layanan penyimpanan data key-value yang terintegrasi dengan platform Cloudflare Workers. Pada dasarnya adalah tempat menyimpan data yang bisa diakses dan diambil dengan cepat oleh aplikasi web Anda yang berjalan di Cloudflare Workers.

System Design

Pada proyek sederhana ini, kita akan mempunyai 2 endpoint:

  1. Generate short link, dan simpan di Cloudflare KV
  2. Redirect ke URL asli menggunakan short link.

Login ke Cloudflare menggunakan Wrangler

Agar command-command seperti wrangler deploy dapat berjalan, maka diperlukan login ke cloudflare menggunakan perintah berikut:

npx wrangler login

Generate Proyek

Setelah login ke akun cloudflare, selanjutnya adalah generate proyek baru menggunakan perintah berikut:

npx wrangler generate lazy-shorter-link https://github.com/cloudflare/workers-sdk/templates/experimental/worker-rust 
cd lazy-shorter-link # Change directory to your project

Waktunya Coding!

Kita akan membuat 2 endpoint yaitu:

GET “/:url”: Endpoint dengan pola ini akan digunakan untuk mengambil informasi terkait URL yang telah disingkat sebelumnya.

POST “/short-link”: Endpoint ini akan digunakan untuk membuat URL yang sudah diperpendek.

Namun, sebelum kita implementasi kode, kita perlu membuat namespace KV yang akan gunakan untuk menyimpan data. Jalankan perintah berikut:

npx wrangler kv:namespace create "KV_URL"

Jika berhasil, maka akan menampilkan berikut:

Setelah mendapatkan binding dan id KV, kita akan menambahkan pada file konfigurasi sehingga dapat diakses pada environment dev dan prod.

Ubah konfigurasi wrangler.toml sesuai dengan output perintah diatas

wrangler.toml

Tambahkan library pendukung pada Cargo.toml sebagai berikut

Cargo.toml

lib.rs

Secara kesuluruhan, kode kita akan seperti ini:

use rand::distributions::Alphanumeric; 
use rand::prelude::*; 
 
use serde::{Deserialize, Serialize}; 
 
use worker::{kv::KvStore, *}; 
 
#[derive(Deserialize, Serialize)] 
struct GenericResponse { 
    status: u16, 
    message: String, 
} 
 
#[derive(Deserialize, Serialize)] 
struct ShortUrl { 
    url: String, 
} 
 
#[event(fetch)] 
async fn main(req: Request, env: Env, _ctx: Context) -> Result<Response> { 
    Router::new() 
        .get_async("/:url", |req, env| async move { 
            let key = req.path().clone(); 
            if let Some(p) = key.split("/").last() { 
                let kv = env.kv("KV_URL")?; 
                let actual_url = kv.get(p).text().await?; 
                if let Some(a) = actual_url { 
                    let furl = a.to_string(); 
                    return Response::redirect(Url::parse(&furl).unwrap()); 
                } else { 
                    return Response::error("Not found", 404); 
                } 
            } else { 
                return Response::error("Not found", 404); 
            } 
        }) 
        .post_async("/short-link", |mut req, ctx| async move { 
            let body = req.json::<ShortUrl>().await?; 
            let kv = ctx.env.kv("KV_URL")?; 
            if !is_valid_url(&body.url) { 
                return Response::from_json(&GenericResponse { 
                    status: 400, 
                    message: "Invalid URL".to_string(), 
                }); 
            } 
            let _key = generate_short_link(&body.url, kv).await?; 
            Response::from_json(&GenericResponse { 
                status: 200, 
                message: format!("https://{}{}{}", req.url()?.host_str().unwrap(), "/", _key), 
            }) 
        }) 
        .run(req, env) 
        .await 
} 
 
// validate url and return a boolean 
fn is_valid_url(url: &str) -> bool { 
    Url::parse(url).is_ok() 
} 
 
// generate short link and return a Result 
pub async fn generate_short_link(url: &str, kv: KvStore) -> Result<String> { 
    let key = thread_rng() 
        .sample_iter(&Alphanumeric) 
        .take(5) 
        .map(char::from) 
        .collect::<String>(); 
    kv.put(&key, &url)?.execute().await?; 
    return Result::Ok(key); 
}

GET /:url :

implementasi dari GET /:url berikut:

get_async("/:url", |req, env| async move { 
            let key = req.path().clone(); 
            if let Some(p) = key.split("/").last() { 
                let kv = env.kv("KV_URL")?; 
                let actual_url = kv.get(p).text().await?; 
                if let Some(a) = actual_url { 
                    let furl = a.to_string(); 
                    return Response::redirect(Url::parse(&furl).unwrap()); 
                } else { 
                    return Response::error("Not found", 404); 
                } 
            } else { 
                return Response::error("Not found", 404); 
            } 
        })

POST /short-link

implementasi dari POST /short-link berikut:

post_async("/short-link", |mut req, ctx| async move { 
            let body = req.json::<ShortUrl>().await?; 
            let kv = ctx.env.kv("KV_URL")?; 
            if !is_valid_url(&body.url) { 
                return Response::from_json(&GenericResponse { 
                    status: 400, 
                    message: "Invalid URL".to_string(), 
                }); 
            } 
            let _key = generate_short_link(&body.url, kv).await?; 
            Response::from_json(&GenericResponse { 
                status: 200, 
                message: format!("https://{}{}{}", req.url()?.host_str().unwrap(), "/", _key), 
            }) 
        })

Testing Pada Environment Dev

Jalankan perintah berikut untuk menjalankan code secara local

npx wrangler dev

Maka akan muncul output sebagai berikut:

Output Development

Akses link diatas untuk melakukan testing

Deploy ke Cloudflare Worker

Jalankan perintah berikut untuk melakukan deployment code yang sudah dikembangkan ke cloudflare worker

npx wrangler deploy

Berikut adalah output dari deployment

Output Deployment

Akses secara Publik

Coba akses kedua endpoint tersebut melalui cloudflare worker kalian

Contoh:

/short-link

Test POST

/:url

Test Get

Kesimpulan

Dengan demikian, kita telah berhasil membuat sebuah URL shortener menggunakan Rust, Cloudflare Worker, dan Cloudflare KV. Selamat mencoba!

Follow my linkedin on: www.linkedin.com/in/marchel-fahrezi-212a87185