# Send a query, headers and a form

**For:** Rust developers calling a web API that takes query parameters, headers or form posts.

You add query parameters and headers to a GET request and send a form in a POST. httpbin.org echoes back what it received, so you can see exactly what went over the wire.

Before you start: you need Rust with Cargo. fibre_http comes from crates.io as `fibre_http = "0"`.

## Set up the project

Start a new binary crate.

```sh
cargo new query_and_form
cd query_and_form
```

Put this in the `[dependencies]` section of `Cargo.toml`:

```toml title="Cargo.toml"
[dependencies]
fibre_http = { version = "0", features = ["json"] }
serde_json = "1"
```

The `json` feature lets you read httpbin's answer as JSON. Sending a query, headers and a form does not need it.

## The program

Replace `src/main.rs` with this:

```rust title="src/main.rs"
use fibre_http::SyncClient;
use serde_json::Value;

fn main() -> Result<(), fibre_http::Error> {
    let client = SyncClient::new();

    let echo: Value = client
        .get("https://httpbin.org/get")
        .query(&[("q", "rust http"), ("page", "2")])
        .header("accept", "application/json")
        .header("x-tutorial", "query-and-headers")
        .send()?
        .error_for_status()?
        .json()?;
    println!("url: {}", echo["url"]);
    println!("query: {}", echo["args"]);
    println!("accept: {}", echo["headers"]["Accept"]);
    println!("x-tutorial: {}", echo["headers"]["X-Tutorial"]);

    let echo: Value = client
        .post("https://httpbin.org/post")
        .form(&[("name", "fibre"), ("kind", "http")])
        .send()?
        .error_for_status()?
        .json()?;
    println!("content type: {}", echo["headers"]["Content-Type"]);
    println!("form: {}", echo["form"]);
    Ok(())
}
```

Run it:

```shell-session
$ cargo run
url: "https://httpbin.org/get?q=rust+http&page=2"
query: {"page":"2","q":"rust http"}
accept: "application/json"
x-tutorial: "query-and-headers"
content type: "application/x-www-form-urlencoded"
form: {"kind":"http","name":"fibre"}
```

## What each part does

`query` takes a list of name and value pairs. It encodes them for you, which is why the space in `rust http` became a `+` in the URL. If the URL already has a query, the new pairs go after it.

`header` adds one header. Call it again for each header you need.

`form` encodes the pairs as a form body and sets `Content-Type` to `application/x-www-form-urlencoded`. If you set your own `Content-Type` header first, `form` leaves it alone.

`json()` reads the body and parses it. Here it parses into `serde_json::Value`, so you can pick fields out by name.

## Where to go next

The next tutorial sends and receives your own Rust types as JSON. The usage guide covers raw bodies and `Expect: 100-continue`: [https://github.com/excsn/fibre/blob/main/http/README.USAGE.md](https://github.com/excsn/fibre/blob/main/http/README.USAGE.md)
