Implementing

Recall that a fairing is any type that implements the Fairing trait. A Fairing implementation has one required method: info, which returns an Info structure. This structure is used by Rocket to assign a name to the fairing and determine the set of callbacks the fairing is registering for. A Fairing can implement any of the available callbacks: on_attach, on_launch, on_request, and on_response. Each callback has a default implementation that does absolutely nothing.

Requirements

A type implementing Fairing is required to be Send + Sync + 'static. This means that the fairing must be sendable across thread boundaries (Send), thread-safe (Sync), and have only static references, if any ('static). Note that these bounds do not prohibit a Fairing from holding state: the state need simply be thread-safe and statically available or heap allocated.

Example

Imagine that we want to record the number of GET and POST requests that our application has received. While we could do this with request guards and managed state, it would require us to annotate every GET and POST request with custom types, polluting handler signatures. Instead, we can create a simple fairing that acts globally.

The code for a Counter fairing below implements exactly this. The fairing receives a request callback, where it increments a counter on each GET and POST request. It also receives a response callback, where it responds to unrouted requests to the /counts path by returning the recorded number of counts.

  1. struct Counter {
  2. get: AtomicUsize,
  3. post: AtomicUsize,
  4. }
  5. impl Fairing for Counter {
  6. // This is a request and response fairing named "GET/POST Counter".
  7. fn info(&self) -> Info {
  8. Info {
  9. name: "GET/POST Counter",
  10. kind: Kind::Request | Kind::Response
  11. }
  12. }
  13. // Increment the counter for `GET` and `POST` requests.
  14. fn on_request(&self, request: &mut Request, _: &Data) {
  15. match request.method() {
  16. Method::Get => self.get.fetch_add(1, Ordering::Relaxed),
  17. Method::Post => self.post.fetch_add(1, Ordering::Relaxed),
  18. _ => return
  19. }
  20. }
  21. fn on_response(&self, request: &Request, response: &mut Response) {
  22. // Don't change a successful user's response, ever.
  23. if response.status() != Status::NotFound {
  24. return
  25. }
  26. // Rewrite the response to return the current counts.
  27. if request.method() == Method::Get && request.uri().path() == "/counts" {
  28. let get_count = self.get.load(Ordering::Relaxed);
  29. let post_count = self.post.load(Ordering::Relaxed);
  30. let body = format!("Get: {}\nPost: {}", get_count, post_count);
  31. response.set_status(Status::Ok);
  32. response.set_header(ContentType::Plain);
  33. response.set_sized_body(Cursor::new(body));
  34. }
  35. }
  36. }

For brevity, imports are not shown. The complete example can be found in the Fairing documentation.