SmallPlate

Examples in Rust

Rust examples using Plate-Link resolve endpoint

These examples call:

GET /{plateId}/resolve/{id}

and redirect from your Rust server.

actix-web

use actix_web::{get, web, App, HttpRequest, HttpResponse, HttpServer, Responder};
use serde::Deserialize;

const LINK_BASE: &str = "https://link.example.com";
const PLATE_ID: &str = "1";

#[derive(Deserialize)]
struct ResolveEnvelope {
    data: ResolveData,
}

#[derive(Deserialize)]
struct ResolveData {
    destination: String,
}

#[get("/u/{id}/{tail:.*}")]
async fn redirect(path: web::Path<(String, String)>, req: HttpRequest) -> impl Responder {
    let (id, tail) = path.into_inner();
    let query = req.query_string();
    let mut resolve = format!("{}/{}/resolve/{}", LINK_BASE, PLATE_ID, id);
    if !tail.is_empty() {
        resolve.push('/');
        resolve.push_str(&tail);
    }
    if !query.is_empty() {
        resolve.push('?');
        resolve.push_str(query);
    }

    let response = match reqwest::get(resolve).await {
        Ok(r) => r,
        Err(_) => return HttpResponse::BadGateway().body("resolve failed"),
    };
    if !response.status().is_success() {
        return HttpResponse::build(response.status()).body("link not found");
    }

    let payload: ResolveEnvelope = match response.json().await {
        Ok(v) => v,
        Err(_) => return HttpResponse::BadGateway().body("invalid resolve payload"),
    };

    HttpResponse::TemporaryRedirect()
        .append_header(("Location", payload.data.destination))
        .finish()
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| App::new().service(redirect))
        .bind(("127.0.0.1", 8080))?
        .run()
        .await
}

Rocket

#[macro_use]
extern crate rocket;

use rocket::response::Redirect;
use serde::Deserialize;

const LINK_BASE: &str = "https://link.example.com";
const PLATE_ID: &str = "1";

#[derive(Deserialize)]
struct ResolveEnvelope {
    data: ResolveData,
}

#[derive(Deserialize)]
struct ResolveData {
    destination: String,
}

#[get("/u/<id>/<tail..>?<q..>")]
async fn redirect(id: &str, tail: std::path::PathBuf, q: Option<String>) -> Result<Redirect, rocket::http::Status> {
    let mut resolve = format!("{}/{}/resolve/{}", LINK_BASE, PLATE_ID, id);
    if !tail.as_os_str().is_empty() {
        resolve.push('/');
        resolve.push_str(&tail.to_string_lossy());
    }
    if let Some(query) = q {
        if !query.is_empty() {
            resolve.push('?');
            resolve.push_str(&query);
        }
    }

    let response = reqwest::get(resolve)
        .await
        .map_err(|_| rocket::http::Status::BadGateway)?;
    if !response.status().is_success() {
        return Err(rocket::http::Status::NotFound);
    }

    let payload: ResolveEnvelope = response
        .json()
        .await
        .map_err(|_| rocket::http::Status::BadGateway)?;

    Ok(Redirect::temporary(payload.data.destination))
}

#[launch]
fn rocket() -> _ {
    rocket::build().mount("/", routes![redirect])
}

On this page