/simple_bridge

SimpleBridge provides a simple, standardized interface to Erlang HTTP Servers.

Primary LanguageErlangMIT LicenseMIT

SimpleBridge

SimpleBridge takes the pain out of coding to multiple Erlang HTTP servers by creating a standardized interface. It currently supports Mochiweb, Inets, and Misultin, with Yaws coming soon.

SimpleBridge is used in the experimental branch of the The Nitrogen Web Framework.

In a sense, it is similar to EWGI, except SimpleBridge has some key improvements/differences:

  • Smaller code base - SimpleBridge is 870 lines, compared to 1,974 lines for EWGI. This is because SimpleBridge uses the underlying HTTP server's built in parsing functions as much as possible.
  • Easily extended - Takes about 150 lines to add support for a new HTTP server, vs. ~350 for EWGI.
  • MultiPart File Uploads - SimpleBridge has better support for HTTP POSTS, including support for multipart file uploads, with size limits and handle-able errors.
  • Static File Support - Support for sending a static file to the browser, using the underlying HTTP server's own methods.
  • Cookies Support - SimpleBridge provides interface functions for getting and setting cookies.
  • No Middleware Components - SimpleBridge does not explicitly support EWGI's concept of "middleware components". (Though you could probably fake it, haven't tried.)

SimpleBridge is split into two parts:

  • A Request Bridge is a parameterized module that allows you to see information about the incoming request.
  • A Response Bridge is a parameterized module that allows you to construct a response.
Hello World Example
% SimpleBridge Hello World Example in Mochiweb

start(_, _) ->
	Options = [{ip, "127.0.0.1"}, {port, 8000}],
	Loop = fun loop/1,
	mochiweb_http:start([{name, mochiweb_example_app}, {loop, Loop} | Options]).

loop(Req) ->
	Request = simple_bridge:make_request(mochiweb_request_bridge, {Req, "./wwwroot"}),
	HTML = [
		"<h1>Hello, World!</h1>",
		io_lib:format("METHOD: ~p~n<br><br>", [Request:request_method()]),
		io_lib:format("COOKIES: ~p~n<br><br>", [Request:cookies()]),
		io_lib:format("HEADERS: ~p~n<br><br>", [Request:headers()]),
		io_lib:format("QUERY PARAMETERS: ~p~n<br><br>", [Request:query_params()])		
	],

	Response = simple_bridge:make_response(mochiweb_response_bridge, {Req, "./wwwroot"}),		
	Response1 = Response:status_code(200),
	Response2 = Response1:header("Content-Type", "text/html"),
	Response3 = Response2:data(HTML),
	Response3:build_response().

Request Bridges

How do I make a request bridge?

To make a request bridge for an incoming request, call the simple_bridge:make_request/2 function, specifying the appropriate bridge module for your HTTP server, and the arguments that it needs. This code would sit in the loop/1 function of a Mochiweb server, or the do/1 function of an Inets server.

Inets example:

RequestBridge = simple_bridge:make_request(inets_response_bridge, Info)

Mochiweb example:

RequestBridge = simple_bridge:make_request(mochiweb_response_bridge, [{Req, Docroot}]).

What can I do with the request bridge object?

Once you have created the request bridge object (a parameterized module), it provides you with a standard interface for accessing the request method, path, query parameters, post parameters, headers, and cookies of the request:

Request Bridge Interface

  • Bridge:request_method() - returns 'GET', 'POST', 'HEAD', etc.
  • Bridge:path() - returns the requested path and file.
  • Bridge:peer_ip() - returns the client's IP address in tuple format (74.125.67.100 = {74, 125, 67, 100})
  • Bridge:peer_port() - returns the client's port.
  • Bridge:headers() - returns a proplist of headers, [{header1, "Value1"}, {header2, "Value2"}, ...]
  • Bridge:header(Header) - returns the value of a header.
  • Bridge:cookies() - returns a proplist of cookies, [{"Cookie1", "Value1"}, {"Cookie2", "Value2"}, ...]
  • Bridge:query_params() - returns a proplist of query params, [{"Query1", "Value1"}, {"Query2", "Value2"}, ...]
  • Bridge:post_params() - returns a proplist of post params, [{"Post1", "Value1"}, {"Post2", "Value2"}, ...]
  • Bridge:post_files() - returns a list of upload_file records, describing the files uploaded in a multipart post.
  • Bridge:request_body() - returns the request body that has been read so far, as a list.
  • Bridge:error() - returns an Erlang term describing any errors that happened while parsing a multipart post.

What modules are involved in a request bridge?

  • request_bridge.erl - The behaviour interface that request bridge modules must implement.
  • request_bridge_wrapper.erl - A parameterized module that wraps a request.
  • inets_request_bridge.erl - The request bridge module for Inets.
  • mochiweb_request_bridge.erl - The request bridge module for Mochiweb.
  • webmachine_request_bridge.erl - The request bridge module for Webmachine.
  • cowboy_request_bridge.erl - The request bridge module for Cowboy.
  • yaws_request_bridge.erl - The request bridge module for Yaws.
  • misultin_request_bridge.erl - The request bridge module for Misultin.
  • ???_request_bridge.erl - Support for more servers on the way.

To extend the SimpleBridge to work with other HTTP servers (or other versions of Inets, Mochiweb, or Yaws), copy and modify inets_request_bridge.erl or mochiweb_request_bridge.erl.

Response Bridges

How do I make a response bridge?

To make a request bridge for an incoming request, call the simple_bridge:make_response/2 function, specifying the appropriate bridge module for your HTTP server, and the arguments that it needs. This code would sit in the loop/1 function of a Mochiweb server, or the do/1 function of an Inets server.

Inets example:

ResponseBridge = simple_bridge:make_response(inets_response_bridge, Info)

Mochiweb example:

ResponseBridge = simple_bridge:make_response(mochiweb_response_bridge, {Req, Docroot})

What can I do with the Response Bridge?

Once you have created the request bridge object (a parameterized module), it provides you with a standard interface for combining headers, cookies, and a response body into a response appropriate for your http server.

Each function below returns a new bridge object, so your will need to chain together requests like this:

Bridge = simple_bridge:make_response(inets_response_bridge, Info),
Bridge1 = Bridge:status_code(200),
Bridge2 = Bridge1:header("Header1", "Value1"),
Bridge3 = Bridge2:data(HTML),
etc.

Response Bridge Interface

  • Bridge:status_code(Code) - set the HTTP status code. (200, 404, etc.)
  • Bridge:header(Name, Value) - set an HTTP header.
  • Bridge:clear_headers() - clear all previously set headers.
  • Bridge:cookie(Name, Value) - set a cookie for path "/" with expiration in 20 minutes.
  • Bridge:cookie(Name, Value, Path, Exp) - Set a cookie. Exp is an integer in minutes.
  • Bridge:clear_cookies() - clear all previously set cookies.
  • Bridge:data(Data) - set the data to return in the response. Usually HTML goes here.
  • Bridge:file(File) - Send a static file to the browser.

Finally, you build the response to send to your HTTP server with the build_response/0 function.

  • Bridge:build_response() - Create a response tuple that you can hand off to your HTTP server.

What modules are involved in a response bridge?

  • response_bridge.erl - The behaviour interface that response bridge modules must implement.
  • response_bridge_wrapper.erl - A parameterized module that wraps a response.
  • inets_response_bridge.erl - The response bridge module for Inets.
  • mochiweb_response_bridge.erl - The response bridge module for Mochiweb.
  • webmachine_response_bridge.erl - The response bridge module for Webmachine.
  • cowboy_response_bridge.erl - The response bridge module for Cowboy.
  • yaws_response_bridge.erl - The response bridge module for Yaws.
  • misultin_response_bridge.erl - The response bridge module for Misultin.
  • ???_response_bridge.erl - Support for more servers on the way.

To extend the SimpleBridge to other HTTP servers (or other versions of Inets, Mochiweb, or Yaws), copy and modify inets_response_bridge.erl or mochiweb_response_bridge.erl.