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.
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:
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:
we improved status code “combination” when path matchers are combined
we fixed a bug where a path matcher would change the Allow header of HTTP OPTIONS requests to include methods that have no route
we changed the Accept header matcher to support quality-weighted syntax (eventhough qualities are ignored) and to support wildcards like image/* and */*
we changed the Content-Type header matcher to support parameters, so that text/plain; charset=utf-8 would be matched when a route is looking for text/plain
we added a new matcher for the Access-Control-Request-Method header to make it easier to deal with CORS preflight requests
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:
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.
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:
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.
Cookie Middleware
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 middlewareletpipeline=single_middleware(CookieParser);// construct a basic chain from our pipelinelet(chain,pipelines)=single_pipeline(pipeline);// build a router with the chain & pipelinegotham::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 setupletrepo:Repo<SqliteConnection>=Repo::new("products.db");// create a middleware pipeline from our middlewareletpipeline=single_middleware(DieselMiddleware::new(repo));// construct a basic chain from our pipelinelet(chain,pipelines)=single_pipeline(pipeline);// build a router with the chain & pipelinegotham::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 stateletrepo=Repo::borrow_from(&state);// execute database callsrepo.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)]structClaims{sub:String,exp:usize}// create a middleware pipeline from our middlewareletmiddleware=JWTMiddleware::<Claims>::new("secret".as_ref());letpipeline=single_middleware(middleware);// construct a basic chain from our pipelinelet(chain,pipelines)=single_pipeline(pipeline);// build a router with the chain & pipelinegotham::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 stateletclaims=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!
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:
Adoption of Tokio Reform and the new tokio crate.
Adoption of Hyper 0.12 and the new http crate.
Improvements to the internal routing algorithms.
Ability to customize the Tokio runtime used by Gotham.
Asynchronous static file serving via tokio-fs.
Many performance and usability improvements.
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:
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:
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.
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)]structRequestCounter{inner:Arc<Mutex<usize>>,}/// Counter implementation.implRequestCounter{/// Creates a new request counter, setting the base state to `0`.fnnew()->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.fnincr(&self)->usize{letmutw=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!fnsay_hello(state:State)->(State,Response<Body>){letmessage={// borrow a reference to the counter from the stateletcounter=RequestCounter::borrow_from(&state);// create our message, incrementing our request counterformat!("Hello from request #{}!\n",counter.incr())};// create the responseletres=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.pubfnmain(){// create our state middleware to share the counterletmiddleware=StateMiddleware::new(RequestCounter::new());// create a middleware pipeline from our middlewareletpipeline=single_middleware(middleware);// construct a basic chain from our pipelinelet(chain,pipelines)=single_pipeline(pipeline);// build a router with the chain & pipelinegotham::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 + runtimegotham::start("127.0.0.1:7878",router());// Allows control of thread counts; in this case a single threadgotham::start_with_num_threads("127.0.0.1:7878",router(),1);// Allows control of the `TaskExecutor` usedgotham::start_on_executor("127.0.0.1:7878",executor());// Returns a `Future` to spawn a Gotham servergotham::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.
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:
A framework that runs on stable Rust, taking advantage of as much as possible
of what it offers;
A framework that allowed us to write applications in the way we wanted to
write them;
A learning experience and experiment in what we could achieve with the goal of
building a useful web framework.
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):
Tokio reform and its wider adoption by the community
The experimental Futures 0.2, and the upcoming Futures 0.3
Wider adoption of the http crate
Hyper 0.12
Continued evolution of the Rust language
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:
Waiting and watching for the changes above to be ready for our adoption; and
Family, paid work, and other commitments that have demanded more of our time.
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.
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.
Path extractors and query string extractors work via Serde now
Catching application panics to keep the server process alive
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:
Async static file serving
A more convenient method of dealing with request bodies (form data being the priority)
Track the evolution of Tokio 0.2 and Futures 0.2, and adapt Gotham to suit the needs of the Rust ecosystem as it is updated for the reformed Tokio
Track the adoption of the http crate by hyper, and change Gotham to use the new types for dealing with HTTP
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.
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:
Handlers and Controllers
Advanced Routing
Type Safe Extractors
Middleware and Pipelines
Request State
Sessions
Request and Response helpers
Test helpers
Thoroughly documented code and the beginnings of a Gotham book
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:
Enhancing our Router API with builders/macros to make this much more comfortable for folks used to defining routes in Rails or Phoenix
Compiled Templates
Form extraction
First class Diesel integration
Async static file serving
i18n
Hot reload during development
Structured logging
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.