Client configuration

Grillon can be configured in different ways. We use Hyper as the default HTTP client and provide you with a default configuration. By using Hyper, we can leverage on the low-level API to inspect HTTP requests and responses and provide interesting features to Grillon.

Default client implementation

The default client implementation should provide you with the most common features. All you need to do is configure the base API URL when you create an instance of Grillon.

let grillon = Grillon::new("https://jsonplaceholder.typicode.com")?;

This way you don't have to rewrite the base URL each time you want to send a request and perform assertions on the response. You can reuse the existing client and create a new request. In the following example we send a POST request to https://jsonplaceholder.typicode.com/posts:

let request = grillon
    .post("posts")
    .payload(json!({
        "title": "foo",
        "body": "bar",
        "userId": 1
    }))
    .assert()
    .await;

The assert function consumes the grillon::Request and prevents further changes to the structure of the request when users want to run assertions on the response.

Refer to the Requests chapter for more information about how to configure your requests. Note that at the moment Grillon only supports HTTP(s), but later we will extend the use for different protocols and frameworks such as gRPC or SSL.

Session and authentication

Store cookies

You can update your client to enable or disable the cookie store with store_cookies:

// If an http response contains `Set-Cookie` headers, then cookies will be saved for
// subsequent http requests.
let grillon = Grillon::new("https://server.com/")?.store_cookies(true)?;

grillon.post("auth").assert().await.headers(contains(vec![(
    SET_COOKIE,
    HeaderValue::from_static("SESSIONID=123; HttpOnly"),
)]));

grillon
    .get("authenticated/endpoint") // An endpoint where the session cookie `SESSIONID=123` is required.
    .assert()
    .await
    .status(is_success());

The cookie store is disabled by default.

Basic Auth

You can easily configure your headers with the basic_auth function to set a per-request authentication:

Grillon::new("https://server.com/")?
    .get("auth/basic/endpoint")
    .basic_auth("isaac", Some("rayne"))
    .assert()
    .await
    .status(is_success());

Note that the header is considered as sensitive and will not be logged.

Bearer token

You can also use the bearer_auth function to set your Bearer header per-request:

Grillon::new("https://server.com/")?
    .get("auth/bearer/endpoint")
    .bearer_auth("token-123")
    .assert()
    .await
    .status(is_success());

This header is also considered as sensitive and will not be logged.

Use a different client

When you want to use a different client to send your requests and handle the responses, you should use the internal http response representation to assert. For that you need to use the Assert structure.

For example, suppose you want to use reqwest to perform an http GET request and you want to assert that the response time is less than 400ms. First you need to create your own structure that will handle a reqwest::Response.

struct MyResponse {
    pub response: reqwest::Response,
}

Next, you need to implement the grillon::Response trait to describe how you handle the various pieces of information that Grillon needs to perform assertions:

#[async_trait(?Send)]
impl Response for MyResponse {
    fn status(&self) -> StatusCode {
        self.response.status()
    }

    async fn json(self) -> Option<Value> {
        self.response.json::<Value>().await.ok()
    }

    fn headers(&self) -> HeaderMap {
        self.response.headers().clone()
    }
}

The next step is to create a new Assert instance which requires:

  • An implementation of a grillon::Response,
  • the response time in milliseconds,
  • and the LogSettings for the assertion results.

Let's first run the request and get the execution time:

let now = Instant::now();
let response = reqwest::get(mock_server.server.url("/users/1"))
    .await
    .expect("Failed to send the http request");
let response_time = now.elapsed().as_millis() as u64;

Now let's pass the response to your own response structure:

let my_response = MyResponse { response };

You are now ready to assert against a reqwest::Response wrapped by your own implementation of a grillon::Response:

Assert::new(my_response, response_time, LogSettings::default())
    .await
    .response_time(is_less_than(400));