Home

Awesome

Barista

Barista is a modular web server written in Objective-C. Its purpose is to allow embedding a web server into another app or developer tool. Barista takes inspiration from node.js and the ExpressJS web server, breaking its system up into smaller pieces that can be connected together.

Status

Barista is currently early in development. It probably should not be used in an app you're shipping to end users just yet. But it is likely more than adequate for internal tools or building development tools.

The API is not stable, and could or will break for any reason.

Usage/Middleware

At its most basic, a Barista server is just an HTTP server (running on an arbitrary port). It doesn't do anything by default. In order to actually handle requests, you need to add components to the server. Barista includes several components you might (or might not) want to add to your stack. These include:

To add these components, Barista uses the concept of middleware to build a processing pipeline for each request. Barista exposes a BaristaMiddleware protocol that allows you intercept a request either (or both) before and after a request. The order you add middleware determines the order they run. They typically should terminate in a BARRouter. Once you add the BARRouter based on JLRoutes, you can handle as many different types of URLs as you like in a few lines of code.

	[self addRoute:@"/foo/:bar" forHTTPMethod:@"GET" handler:^BOOL(BARConnection *connection, BARRequest *request, NSDictionary *parameters) {
		NSString *responseMessage = [NSString stringWithFormat:@"Hello, %@", parameters[@"bar"]]; // parameters[@"bar"] maps to the key/value set in the URL, e.g. @"42" /foo/42

		BARResponse *response = [[BARResponse alloc] init];
		response.statusCode = 200;
		response.body = [responseMessage dataUsingEncoding:NSUTF8StringEncoding];
		[connection sendResponse:response];
		return YES;
	}];

Middleware are inherently chainable. If you add a BARCookieParser and a BARSessionStore before your BARRouter, a request pipeline would look like this:

You'll notice that middleware can extend request and response objects with their own methods and data. In the request of the above example, BARCookieParser converts headers into NSHTTPCookie objects, and attaches those to the request. BARSessionStore looks for NSHTTPCookie objects and uses them to look up or create BARSession objects, which get attached to the request. Then, your route has the ability to look for either the NSHTTPCookie objects or the BARSession object and act accordingly. Similarly, in the response, the BARSessionStore adds the cookies for the BARSession to the response, and the BARCookieParser converts the cookies on the response to HTTP headers.

Middleware can also intercept requests and handle them automatically if appropriate, preventing the actual route method from being called. This is useful if, for example, you want to prevent users from accessing resources if they are not logged in. If you implemented a piece of middleware that acted as an authorization gate, and added it to the above middleware chain, it would work something like this:

In the second outcome, note that the routed method is never called. This is because middleware has the ability to intercept requests, send their own responses, and prevent them from continuing to the next step in the chain. This makes it very easy and flexible to isolate application logic from basic processing.

Templating

Barista has middleware support for templating engines, specifically Mustache with GRMustache. If you are rendering web pages, this means you can move that data out of your Objective-C code and into files which get rendered at runtime. Templates can be passed an object with values to include, as well. To do this, add the BARMustacheTemplateRenderer middleware to your chain, and point it at a directory of template files. Here is an example of how to do templating in Barista:

In Objective-C:

	[self addRoute:@"/hello" forHTTPMethod:@"GET" handler:^BOOL(BARConnection *connection, BARRequest *request, NSDictionary *parameters) {
		BARResponse *response = [[BARResponse alloc] init];
		response.statusCode = 200;
		[response setViewToRender:@"hello" withObject:@{@"title": @"Hello world!"}];
		[connection sendResponse:response];
		return YES;
	}];

In hello.mustache:

<!DOCTYPE html>
<html>
<head>
	<title>{{title}}</title>
</head>
<body>
	<div>{{title}}</div>
</body>
</html>

The resulting HTML:

<!DOCTYPE html>
<html>
<head>
	<title>Hello world!</title>
</head>
<body>
	<div>Hello world!</div>
</body>
</html>

You can combine this with a BARStaticFileServer to include images, JavaScript, CSS, and whatever else to build rich web pages and web applications.

Wish List

If you wish to contribute middleware or other changes, please submit a pull request. If you are adding new middleware, add an subspec entry to the podspec in the appropriate place. And add your name to the contributors list below, along with adding acknowledgements for open source code.

Contributors

Acknowledgements

License

See the LICENSE.md file.