28

How can I parse the name and color arguments from the following URL using actix-web?

http://example.com/path/to/page?name=ferret&color=purple

I suppose my path should be /path/to/page and then when I try to query for name I receive an empty string (req.match_info().query("name") where req: &HttpRequest).

The only documentation I found is about matching names (e.g., if the path is /people/{page}/ it'll match /people/123/ such that page = 123 but that's not what I want.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
H. Desane
  • 593
  • 1
  • 8
  • 16

4 Answers4

29

It looks like they removed the query function and just have a query_string function. You could use a crate for this called qstring:

use qstring::QString;
...
let query_str = req.query_string(); // "name=ferret"
let qs = QString::from(query_str);
let name = qs.get("name").unwrap(); // "ferret"

You could also use an extractor to deserialize the query params into a struct with Serde

use serde::Deserialize;

#[derive(Deserialize)]
struct Info {
    username: String,
}

fn index(info: web::Query<Info>) -> Result<String, actix_web::Error> {
    Ok(format!("Welcome {}!", info.username))
}

Note that the handler will only be called if the query username is actually present in the request. This would call the handler:

curl "http://localhost:5000?username=joe"

but these would not:

curl "http://localhost:5000"
curl "http://localhost:5000?password=blah"

If you need optional parameters, just make the properties in your struct Options.

username: Option<String>

You can also use multiple web::Query<SomeType> parameters in a handler.

Rokit
  • 977
  • 13
  • 23
  • It cannot parse array. For example, `a=1&a=2` should be parsed into `[1, 2]` but you can only get 1 – kigawas Jan 22 '22 at 11:36
9

actix_web::web::query parses query strings:

use actix_web::{web, App};
use serde_derive::Deserialize;

#[derive(Debug, Deserialize)]
pub struct Params {
    name: String,
    color: String,
}

#[get("/path/to/page")]
async fn handler(req: HttpRequest) -> HttpResponse {
    let params = web::Query::<Params>::from_query(req.query_string()).unwrap();
    HttpResponse::Ok().body(format!("{:?}", params))
}

The official documentation has another example.

pinsl
  • 91
  • 1
  • 3
  • 1
    helpful example! note that you can then access attributes of `params` like `params.name` or `&params.name` – abe Dec 15 '22 at 21:13
3

This is for actix-web v0.7

I managed to get it work by using:

let name = req.query().get("name").unwrap(); // name = "ferret"
Kornel
  • 97,764
  • 37
  • 219
  • 309
H. Desane
  • 593
  • 1
  • 8
  • 16
  • 4
    Did this change in a recent version? On Actix Web 1.0.7, I am getting `error[E0599]: no method named `query` found for type `actix_web::request::HttpRequest` in the current scope` – C14L Aug 30 '19 at 13:18
0

If you need default query parameters you can define them with the following code:


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

...

#[derive(Debug, Deserialize)]
pub struct Params {
    orgIds: String
}

...

async fn totd(db_pool: web::Data<Pool>, req: HttpRequest) -> impl Responder {
    let params = web::Query::<Params>::from_query(req.query_string())
        .unwrap_or(web::Query(Params { orgIds: String::from("2") }));
    let org_ids = &params.orgIds;
...

This applies to actix-web = "4"

Alternatively you can also use Query::<HashMap<String, String>>::from_query to parse the query.

Here is an example using from_query:

let params = Query::<HashMap<String, String>>::from_query(req.query_string())
        .unwrap();
let default_org_id = &String::from("2");
let default_lang = &String::from("en");
let org_ids = params.get("orgIds").unwrap_or(default_org_id);
let lang = params.get("lang").unwrap_or(default_lang);

With this second technique it is easier to deal with default values.

gil.fernandes
  • 12,978
  • 5
  • 63
  • 76