Announcing Gotham 0.6

I’m happy to announce the 0.6 release of gotham. Below you can find the highlights of all changes. Starting with this release, you can see the full changelog at the GitHub release page: https://github.com/gotham-rs/gotham/releases

Update to Tokio 1.0

This release updates gotham to the Tokio 1.0 release for the most stable async platform that Rust has ever seen! Please refer to the the respective announcements of tokio 1.0 and hyper 0.14 to see what has changed.

Custom Hyper Services

With the new version, you can integrate gotham with all its goodness into custom hyper services. Previously, you had to start the server through gotham’s exposed start methods, which still works, but doesn’t allow for as much customization. This is an excerpt from our new example:

#[derive(Clone)]
struct MyService {
    router: Router,
    addr: SocketAddr,
}

impl Service<Request<Body>> for MyService {
    type Response = Response<Body>;
    type Error = Error;
    type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;

    fn poll_ready(&mut self, _cx: &mut task::Context<'_>) -> task::Poll<Result<(), Self::Error>> {
        task::Poll::Ready(Ok(()))
    }

    fn call(&mut self, req: Request<Body>) -> Self::Future {
        // NOTE: You don't *have* to use call_handler for this (you could use `router.handle`), but
        // call_handler will catch panics and return en error response.
        let state = State::from_request(req, self.addr);
        call_handler(self.router.clone(), AssertUnwindSafe(state)).boxed()
    }
}

let addr = "127.0.0.1:7878";
let listener = TcpListener::bind(&addr).await?;

loop {
    let (socket, addr) = listener
        .accept()
        .await
        .context("Error accepting connection")?;

    let service = MyService {
        router: router.clone(),
        addr,
    };

    let task = async move {
        Http::new()
            .serve_connection(socket, service)
            .await
            .context("Error serving connection")?;

        Result::<_, Error>::Ok(())
    };

    tokio::spawn(task);
}

Miscellaneous

A huge thanks to everyone that contributed to this release, it wouldn’t be this awesome without your help! If there is something missing in this release that you’d like to see, please reach out to us. You can do that using GitHub issues or Gitter chat, and of course you are more than welcome to hand in Pull Requests. We appreciate every contribution.

Announcing Gotham 0.5

You’ve all been waiting for another release, and I’m happy to announce that gotham 0.5 is finally here! With this release, we have several new faces on the team:

Together with the existing maintainers, we brought you some exiting changes.

Async/Await support

As futures and async/await has been standardized in Rust, we have moved from futures 0.1 to the new API. Your handler function can now be a true async function:

async fn foo_create_response() -> Response<Body> {
	unimplemented!()
}

async fn foo_handler(state: State) -> HandlerResult {
	let res = foo_create_response().await;
	Ok((state, res))
}

fn router() -> Router {
	build_simple_router(|router| {
		route.get("/foo").to_async(foo_handler);
	})
}

Furthermore, it is possible to take a reference to the State, allowing for usage of the ? shorthand when dealing with Results:

async fn foo_create_response() -> anyhow::Result<Response<Body>> {
	unimplemented!()
}

async fn foo_handler(state: &mut State) -> Result<Response<Body>, HandlerError> {
	let res = foo_create_response().await?;
	Ok(res)
}

fn router() -> Router {
	build_simple_router(|router| {
		router.get("/foo").to_async_borrowing(foo_handler);
	})
}

As you’ve seen in the above code, we are now also using anyhow instead of the now outdated failure crate.

Unfortunately, there is no support for closures yet with borrowing support, so .to_async_borrowing(|state: &mut State| /* code */) does not work as of today, and you’ll have to stick with .to_async(|state| async move { /* code */ }).

Path Matchers

We have improved the behaviour of path matchers in gotham 0.5 as well as included a new path matcher:

WebSocket support

Gotham now has connection upgrades enabled, and therefore enables the use of WebSockets. Please check out the examples to find out how websockets can be used in gotham today.

Glob Names

The glob processing in our router has been improved to allow for multiple named globs in one path:

fn router() -> Router {
	build_simple_router(|router| {
		router.get("/foo/*first/bar/*second").with_path_extractor::<FooBarExtractor>().to(foo_bar_handler);
	})
}

Miscellaneous

In addition to above changes, we have updated a lot of dependencies and have updated all of our examples to reflect the changes. Gotham is now also re-exporting some of its dependencies including anyhow, hyper and rustls in an effort to reduce the possibility of a version mismatch. Speaking of rustls, TLS support is now behind a feature flag that is enabled by default. All projects that don’t need TLS support in gotham, e.g. because they are behind a reverse proxy, can now disable TLS support and get rid of the unused dependencies.

A huge thanks to everyone that contributed to this release, it wouldn’t be this awesome without your help! If there is something missing in this release that you’d like to see, please reach out to us. You can do that using GitHub issues or Gitter chat, and of course you are more than welcome to hand in Pull Requests.

Announcing Gotham 0.4

It’s been a little while, but today we’re happy to announce the latest release of the Gotham web framework: Gotham 0.4! This release focuses on some of the more common use cases when writing web services, by introducing several new middlewares and features to improve productivity when working with Gotham.

TLS Support

One of the larger features included in this release is the support for TLS when working with Gotham. This is handled via the popular Rust TLS library rustls, in combination with the Tokio bindings provided by tokio-rustls.

Creation of a TLS server is consistent with the existing Gotham API, with the only difference being the requirement of a rustls::ServerConfig to be provided at server startup:

let addr = "127.0.0.1:7878";
let config = rustls::ServerConfig::new(...);

gotham::tls::start(addr, || Ok(say_hello), config)

This simple tweak to the API makes it easy to handle TLS connections without having to learn an entire new set of APIs.

Middlewares

Gotham 0.4 includes work on a few new middlewares designed to improve some common use cases, and fit in with common patterns when writing web services. Each of the middlewares below is available in either the core of Gotham itself, or distributed as a separate crate on crates.io.

Gotham 0.4 also includes a new middleware named CookieParser, which is designed to make dealing with cookies much simpler and in a much more automatic fashion. All parsing of cookies is done via the de-facto cookie crate.

Unlike some of the other middlewares, the CookieParser middleware ships directly in Gotham’s core library due to it being re-used in the existing SessionMiddleware workflows, and as it’s such a common requirement when building a web service.

To use this middleware, configure it as any other middleware inside your router:

// create a middleware pipeline from our middleware
let pipeline = single_middleware(CookieParser);

// construct a basic chain from our pipeline
let (chain, pipelines) = single_pipeline(pipeline);

// build a router with the chain & pipeline
gotham::start("127.0.0.1:7878", build_router(chain, pipelines, |route| {
    route.get("/").to(say_hello);
}))

Then you will automatically have a CookieJar available on the State provided to your request, which you can easily access as needed:

CookieJar::borrow_from(&state)

If you have any existing middlewares dealing with cookies, maybe for things like authorization, you can now place them after the CookieParser in the middleware chain and they will then also have access to the new CookieJar entity. This allows you to remove any custom cookie parsing that you may have had to write in the past. One example of this is the existing SessionMiddleware, which will now look for any previously parsed cookies t avoid doing unnecessary work.

An example of this middleware is available in the repository, so please do check it out.

Diesel Middleware

Diesel is a very popular ORM written in Rust, and there has been some work in progress for a compatible middleware for some time. Thanks to the work of @colinbankier this is now available via the gotham_middleware_diesel crate, which offers a convenient API for interacting with Diesel from Gotham.

This middleware introduces a Repo struct, which is used as a layer between Diesel and Gotham to ensure that database interaction can be easily chained alongside other asynchronous operations. This structure is fairly straightfoward and offers an easy way to interact with Diesel from inside Gotham:

// create a new repo, in this case just using a SQLite setup
let repo: Repo<SqliteConnection> = Repo::new("products.db");

// create a middleware pipeline from our middleware
let pipeline = single_middleware(DieselMiddleware::new(repo));

// construct a basic chain from our pipeline
let (chain, pipelines) = single_pipeline(pipeline);

// build a router with the chain & pipeline
gotham::start("127.0.0.1:7878", build_router(chain, pipelines, |route| {
    route.get("/").to(say_hello);
}))

From there you gain simple access to Repo on the request state, just like when using other middlewares. You can then use the Repo to execute database calls on a separate connection pool:

// borrow the repo from the state
let repo = Repo::borrow_from(&state);

// execute database calls
repo.run(move |conn| {
    diesel::insert_into(products::table)
        .values(&product)
        .execute(&conn)
})

What may not be obvious from the snippet above is that calling repo.run actually returns a Future, allowing you to seamlessly sprinkle your database calls amongst other asynchronous handler code without going through too much pain.

This is the main advantage of the Repo type as it manages the synchronous calls of the underlying connections on a separate thread pool, and maintains the appearance that you’re working with an API that’s fully asynchronous to keep things simple.

Naturally a complete example of database interaction is a little too long to embed into a blog post, so please check out the excellent examples Colin provided in the main repository.

JWT Middleware

JSON Web Tokens (usually referred to as JWT) have become a popular way to authenticate against HTTP APIs due to their ability to pass around data in a secure manner, and in an efficient way. In Gotham 0.4, we’re excited to include a simple middleware to validate these tokens, so that you don’t have to!

As a user of this middleware, you are able to deserialize your web tokens directly into a custom structure automatically. All required validation is taken care of by the middleware itself by checking tokens provided in the HTTP Authorization header.

In the example below we’re defining a new Claims structure to represent our tokens. This structure is automatically populated by the middleware, and is available in your API handlers.

#[derive(Deserialize, Debug)]
struct Claims {
    sub: String,
    exp: usize
}

// create a middleware pipeline from our middleware
let middleware = JWTMiddleware::<Claims>::new("secret".as_ref());
let pipeline = single_middleware(middleware);

// construct a basic chain from our pipeline
let (chain, pipelines) = single_pipeline(pipeline);

// build a router with the chain & pipeline
gotham::start("127.0.0.1:7878", build_router(chain, pipelines, |route| {
    route.get("/").to(say_hello);
}))

Then, using the typical state access that Gotham provides, you are able to fetch your Claims structure back out from inside your API code:

// borrow the claims from the state
let claims = Claims::borrow_from(&state);

As this is the first implementation of this middleware, please let us know if you have any suggestions or ways we can extend these use cases!

Miscellaneous

Although not technically part of the Gotham core release, we have also added several new examples to the repository. Thank you to all who had any input in the creation of:

In addition to everything mentioned, we have also updated dependencies to their latest versions as well as migrated the codebase to compile under Rust 2018 edition to make contribution a little easier. So please do get involved if there’s something you’d like to see included!

Announcing Gotham 0.3

First of all, hello there! This is the first announcement after the call for maintainers back in summer, and includes the efforts of several new faces:

Together, as well as input from the original authors @bradleybeddoes and @smangelsdorf, we are the new maintainers of the Gotham project. Today we’re excited to announce the release of Gotham 0.3, which follows the evolution of the broader Rust ecosystem.

What’s in Gotham 0.3

Following along with the changes in libraries such as tokio and hyper, along with the release of the new http crate, Gotham has changed fairly significantly in this release, in terms of both public API and usability.

Some broad highlights of this release include:

In the sections below, we’ll cover some of the more interesting features.

Ecosystem Updates

The 0.3 update has a heavy focus on adopting the changes in the broader Rust ecosystem, beginning with the adoption of the new tokio crate. This was contributed by @whitfin and had the added advantage of removing the only platform-specific code in Gotham. It also opened up several new APIs to control Gotham startup - such as thread count, executor, etc.

In addition Gotham 0.3 upgrades Hyper to 0.12 and adopts the new http crate, to keep Gotham up to date with the latest performance improvements and maintain a familiar API signature. This is due to a huge effort from @nyarly to adopt the new APIs internally, whilst keeping the impact to the Gotham API minimal.

Of course, aside from this, all dependencies of Gotham have been updated to their latest and greatest to avoid any potential bugs which might have been fixed since the last release.

Shorthand Responses

Gotham enables you to return a response through the use of the IntoResponse trait. In Gotham 0.3, this trait is implemented for some shorthand structures to enable easier return handling without having to construct a response. Here is a simple example:

const HELLO_WORLD: &'static str = "Hello, world!";

pub fn say_hello(state: State) -> (State, &'static str) {
    (state, HELLO_WORLD)
}

pub fn main() {
    gotham::start("127.0.0.1:7878", || Ok(say_hello))
}

This is possible as there is a blanket conversion for types implementing Into<Body> for Hyper. As &'static str is one such type, the conversion is automatic. Other basic types are also included, such as Bytes, String and Vec<u8> - making it possible to shorthand many reponses.

Taking it a little further, you can also control the status code and mime type of the response created, using Tuple structures:

(mime::Mime, Into<Body>)
(hyper::StatusCode, mime::Mime, Into<Body>)

This allows for a different style when defining requests. The old create_response helpers are still around though; so if you don’t like this syntax you can stick with the old.

Async Static File Serving

Mentioned as part of the 0.2 announcement, the ability to asynchronously serve static assets is very much something that has been requested to be available as part of Gotham. The 0.3 release includes initial support for this, courtesy of @colinbankier, via a simple API. Below are a few examples of exposing static assets:

build_simple_router(|route| {
    // You can use `to_file` on a route to expose a single asset:
    route.get("/").to_file("assets/index.html");

    // Alternatively, you can use `to_dir` to expose a directory of assets:
    route.get("/static").to_dir("assets");

    // Finally, you can customize options for compression, cache control, etc:
    route.get("/static").to_dir(
        FileOptions::new("assets")
            .with_cache_control("no-cache")
            .with_gzip(true)
            .build(),
    );
});

The structure of this API makes it extremely quick to implement a static site using Gotham. The snippet below shows a complete example of serving a static site from the assets directory using Gotham to serve the requests.

extern crate gotham;

use gotham::router::builder::*;

pub fn main() {
    gotham::start("127.0.0.1:7878", build_simple_router(|route| {
        route.get("/*").to_dir("assets");
    }))
}

We think this is a great improvement for those looking at Gotham for static sites!

Shared State Middlewares

A common question we often see is how to share state across requests. Whilst this has been possible via the use of middleware for a long time, it’s not always obvious exactly how to go about it - and it’s definitely a lot of boilerplate for something so simple. Contributed by @whitfin, Gotham 0.3 includes a new built-in middleware to offer shared state without having to bind it yourself. Below is an example of mutable state across requests, used to keep track of the number of requests the server has received. Note that dependencies and use clauses have been omitted for brevity:

/// Request counter, used to track the number of requests made.
///
/// Due to being shared across many worker threads, the internal counter
/// is bound inside an `Arc` (to enable sharing) and a `Mutex` (to enable
/// modification from multiple threads safely).
///
/// This struct must implement `Clone` and `StateData` to be applicable
/// for use with the `StateMiddleware`, and be shared via `Middleware`.
#[derive(Clone, StateData)]
struct RequestCounter {
    inner: Arc<Mutex<usize>>,
}

/// Counter implementation.
impl RequestCounter {
    /// Creates a new request counter, setting the base state to `0`.
    fn new() -> Self {
        Self {
            inner: Arc::new(Mutex::new(0)),
        }
    }

    /// Increments the internal counter state by `1`, and returns the
    /// new request counter as an atomic operation.
    fn incr(&self) -> usize {
        let mut w = self.inner.lock().unwrap();
        *w += 1;
        *w
    }
}

/// Basic `Handler` to say hello and return the current request count.
///
/// The request counter is shared via the state, so we can safely
/// borrow one from the provided state. As the counter uses locks
/// internally, we don't have to borrow a mutable reference either!
fn say_hello(state: State) -> (State, Response<Body>) {
    let message = {
        // borrow a reference to the counter from the state
        let counter = RequestCounter::borrow_from(&state);

        // create our message, incrementing our request counter
        format!("Hello from request #{}!\n", counter.incr())
    };

    // create the response
    let res = create_response(&state, StatusCode::OK, mime::TEXT_PLAIN, message);

    // done!
    (state, res)
}

/// Start a server and call the `Handler` we've defined above
/// for each `Request` we receive.
pub fn main() {
    // create our state middleware to share the counter
    let middleware = StateMiddleware::new(RequestCounter::new());

    // create a middleware pipeline from our middleware
    let pipeline = single_middleware(middleware);

    // construct a basic chain from our pipeline
    let (chain, pipelines) = single_pipeline(pipeline);

    // build a router with the chain & pipeline
    gotham::start("127.0.0.1:7878", build_router(chain, pipelines, |route| {
        route.get("/").to(say_hello);
    }))
}

Although this example looks quite large due to completeness, the relevant part to look at here is the StateMiddleware used inside main() to attach the RequestCounter as a middleware component. After this is configured you can easily borrow your counter (via RequestCounter::borrow_from(&state)) in any of your handlers and modify using the safety guarantees you’re used to.

Due to the routing API Gotham offers, it’s also possible to attach different states to different parts of your router to offer isolation across handlers. It should also be noted that you can attach multiple StateMiddleware to a single router, as long as the internal type (in this case RequestCounter) is unique.

Customized Startup

In Gotham 0.2 a server would automatically start on a predetermined number of threads, and would use a runtime entirely controlled by Gotham. Although this is typically the desired outcome, Gotham 0.3 introduces a few more APIs to control the server startup:

// Same as previous; uses default threads + runtime
gotham::start("127.0.0.1:7878", router());

// Allows control of thread counts; in this case a single thread
gotham::start_with_num_threads("127.0.0.1:7878", router(), 1);

// Allows control of the `TaskExecutor` used
gotham::start_on_executor("127.0.0.1:7878", executor());

// Returns a `Future` to spawn a Gotham server
gotham::init_server("127.0.0.1:7878", router());

Each of these APIs are just delegates to each other so there’s little maintenance overhead to offering them, but they provide a little extra control over the Gotham service. A good example of this was contributed by @im-0, who used init_server to implement a graceful shutdown for their application by using a select and a shutdown signal from tokio_signal.

A Note from the Maintainers

Although Gotham’s call for maintainers has been answered, please get in touch if you’re interested in contributing! We’re always interested in hearing new ideas and potential improvements to Gotham, especially those based on a 0.4 timeline. The 0.4 roadmap is still being figured out, so feel free to let us know your ideas.

We’d like to say thank you to the developers of our dependencies, the Rust language team themselves, and of course everybody who was involved in the 0.3 release - whether it be a new feature, an example or filing an issue, we couldn’t have done this without you.

The State of Gotham

Update (2018-06-04): The call for maintainers has been answered. Stay tuned.


When we set out to build Gotham, we had some main ideas that helped to shape it:

We’re excited about the framework we’ve built and the ideas we’ve put into it, but have paused to consider Gotham’s present and future position and want to share these thoughts with the community.

Major changes in the ecosystem

The current state of the web ecosystem in Rust is one of flux. There are some major efforts underway which will improve the future of both web and asynchronous applications (in no particular order):

Gotham is at a point now where everything is back on the table, including the design choices based on what was stable in Rust at the time we started Gotham in early 2017.

A call for maintainers

In recent months, development activity in Gotham has decreased. There are two major reasons that we’ve been less active as maintainers:

The second of these points is sufficiently demanding that we don’t have enough time to maintain Gotham as a serious contender in the Rust web framework arena.

We’d like to “pass the torch” to some new maintainer(s) who are willing to give Gotham the attention it deserves. If that’s you, please reach out to one of us via Gitter or email (@bradleybeddoes’ and @smangelsdorf’s email addresses are in the project’s Git history).

What’s next for Gotham?

Gotham, as it stands, isn’t going away. The repositories, crates and chat channel will remain. We’ll continue accepting security fixes and releasing patch versions if necessary, until we determine what’s next.

Feature contributions are still welcome, but may be delayed until a current or future maintainer has time to consider its relevance, impact on the wider framework, and the contribution itself.

Beyond that, it’s up to the next maintainer(s) to set the next priorities. We’re happy to provide our own thoughts on what that should be.

Bradley and Shaun

Gotham 0.2

Since the first release of the Gotham web framework in August 2017, we’ve been excitedly watching the community grow and get involved in the project. Today we’re pleased to announce the release of version 0.2, which includes new features and refinements identified by the community as well as some from our own wishlist.

Some highlights from version 0.2, out of the 99 issues and PRs that we’ve closed in the last 6 months:

Our thanks to everybody involved in the Gotham community by asking questions, providing feedback, and opening issues and pull requests. Anyone who’d like to get involved should come join us on Gitter or GitHub.

We’ve started adding some issues to the 0.3 roadmap, to get an idea of what we’d like to tackle next. Some of the noteworthy ones on our list so far:

You can find out more about the Gotham web framework at https://gotham.rs.

We’d again like to say a sincere thank you to the developers and communities of all our dependencies, and the Rust language. We’re excited for what 2018 will bring to the Rust ecosystem.

Bradley and Shaun

Announcing Gotham

For the last eight months, we’ve been hard at work on a project that we’re thrilled to be able to share with the wider Rust community.

We know it as Gotham and today we’re releasing 0.1.

Gotham is a flexible web framework that does not sacrifice safety, security or speed. The Gotham core team loves many of the elegant concepts that are found in dynamically typed web application frameworks, such as Rails/Phoenix/Django and aspire to achieve them with the type and memory safety guarantees provided by Rust.

Gotham is stability focused. With our release of Gotham 0.1, we’re compatible with Rust stable and every future release of Gotham will maintain that contract. Naturally, we build on beta and nightly as well so if you’re on the bleeding edge Gotham is good to go.

Gotham leverages async extensively thanks to the Tokio project and is further enhanced by being built directly on top of async Hyper. Completing web requests in µs with almost non-existent memory footprints is still taking some getting used to.

We wanted to get Gotham in the hands of the Rust community early with regular smaller iterations to follow. The Gotham 0.1 release includes the following features:

There are some important features still to be built and we hope that the community will help us define even more. Right now our roadmap includes:

You can find out more about Gotham at https://gotham.rs. We look forward to welcoming you into the Gotham community.

Finally, we’d like to say a very sincere thank you to the developers and communities of every dependency we’ve built Gotham on top of, including of course, Rust itself. Your work is amazing and we could not have gotten here without it. We look forward to working with you all in the future.

Bradley and Shaun

Gotham web framework RSS feed