TestsTested | ✗ |
LangLanguage | Obj-CObjective C |
License | MIT |
ReleasedLast Release | Dec 2014 |
Maintained by Unclaimed.
Depends on: | |
CocoaAsyncSocket | ~> 7.0 |
JLRoutes | ~> 1.4 |
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.
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.
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:
BARCookieParser
parses the cookies in the request, if any, and adds that data to the requestBARSessionStore
examines the cookie objects attached to the request, if any, and adds the corresponding session to the request, if it existsBARSessionStore
adds the cookie object to the responseBARCookieParser
serializes the cookie object into a header and attaches it to the responseYou'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:
BARCookieParser
parses the cookies in the request, if any, and adds that data to the requestBARSessionStore
examines the cookie objects attached to the request, if any, and adds the corresponding session to the request, if it existsBARSessionStore
adds the cookie object to the responseBARCookieParser
serializes the cookie object into a header and attaches it to the responseBARCookieParser
parses the cookies in the request, if any, and adds that data to the requestBARSessionStore
examines the cookie objects attached to the request, if any, and adds the corresponding session to the request, if it exists403 Forbidden
or 401 Unauthorized
responseBARSessionStore
adds the cookie object to the responseBARCookieParser
serializes the cookie object into a header and attaches it to the responseIn 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.
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.
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.
See the LICENSE.md file.