How to create an overload API or function in Actix-web?

Background

I need to create a couple of endpoints for an API service project. These API can accept encrypted and un-encrypted one (for development). Both parameters then are passed into a same function. For example:

  1. /api/movie/get with encrypted parameter (for production)
  2. /dev/movie/get with un-encrypted parameter (for development)

Current implementation in actix_web

I use actix_web and routes (not macro) to provide path routing. Modified from the sample code below

use actix_web::{web, App, HttpServer, Responder};

async fn index() -> impl Responder {
    "Hello world!"
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    HttpServer::new(|| {
        App::new().service(
            // prefixes all resources and routes attached to it...
            web::scope("/app")
                // ...so this handles requests for `GET /app/index.html`
                .route("/index.html", web::get().to(index)),
        )
    })
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}

For each API endpoint, I had to create 2 functions, such as:

/// for encrypted one
/// PATH: /api/movie/get
pub async fn handle_get_movie(
    app_data: Data<AppState>,
    Json(payload): Json<EncryptedPayload>,
) -> Result<impl Responder, Error> {

    // decrypt the content
    // this is the only difference between un-encrypted and encrypted endpoint
    let params = payload
        .unload::<GetMovieInf>()
        .map_err(|_| MainError::Malformatted)?;

    // other codes here....

    Ok(Json(ReplyInf {ok: true}))
}
/// for un-encrypted one 
/// PATH: /dev/movie/get
pub async fn handle_get_movie(
    app_data: Data<AppState>,
    Json(payload): Json<UnencryptedPayload>,
) -> Result<impl Responder, Error> {

    // other codes here. These codes are exactly identical with the above function...

    Ok(Json(ReplyInf {ok: true}))
}

Questions

Since both functions are similar, does it possible to combine them both into a single function ? a function "overload" maybe ?

The problem is this line Json(payload): Json<UnencryptedPayload> in the parameter function. I tried to use generics like Json<T>. this doesn't work.

I can use the environment variable to control which should be active (EncryptedPayload or UnencryptedPayload). I can use one path for each endpoint (eg: /api/movie/get) and don't have to write the same functionality twice.

Because parameter injection is type-based, not without abstracting over UnencryptedPayload and EncryptedPayload.
But that could possibly be as simple as

enum Payload {
    Encrypted(EncryptedPayload), 
    Unencrypted(UnencryptedPayload), 
} 

And updating the fn parameter from Json<UnencryptedPayload> to Json<Payload>.
Just add any appropriate trait impls / attribute macros.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.