apex

Apex is a RubyMotion web framework for OS X. It uses GCDWebServer under the hood and provides a Sinatra-like router and DSL.

Apex is currently experimental and in development. Let me know what you think on Twitter.

Installation

# In Gemfile:
gem 'apex', :git => 'https://github.com/clearsightstudio/apex.git'

# In Terminal:
bundle install
rake pod:install

Usage

Using your AppDelegate

class AppDelegate < Apex::Server
  port 8080 # defaults to 8080

  layout do
    "<html>" +
    "<head><title>Apex</title></head>" +
    "<body>" +
    content +
    "</body>" +
    "</html>"
  end

  get "/" do |r|
    "<h1>Apex is running. Response: #{r}</h1>" +
    "<p><a href='/about'>About Apex</a></p>"
  end

  get "/about" do |r|
    "<h1>About Apex</h1>" +
    "<p><a href='/'>Home</a></p>"
  end

  post "/some_post" do |request|
    request.headers["User-Agent"]
  end

end

Alternate Railsy Syntax

This is under consideration.

class AppDelegate < Apex::Server
  def routes
    get "/", controller: HomeController, action: :home
    get "/about", controller: AboutController, action: :about
    get "/about/me", controller: AboutController, action: :me
  end
end

class HomeController < Apex::Controller
  def home
    render :home, layout: DefaultLayout
  end
end

class AboutController < Apex::Controller
  layout AboutLayout

  def about
    render :about
  end

  def me
    render :me, name: "Jamon"
  end
end

def AboutView < Apex::View
  def about
    "<h1>About</h1>"
  end

  def me(args={})
    "<h1>Me #{args[:name]}</h1>"
  end
end

def AboutLayout < Apex::Layout
  def render
    "<html>" +
      "<head>" +
        "<title>#{title}</title>" +
      "</head>" +
      "<body>#{content}</body>" +
    "</html>"
  end

  # Potentially, a Ruby DSL for HTML:
  def render
    html do
      head do
        title "My title"
      end
      body do
        content_for :body
      end
    end
  end
end

Standalone class


class WebServer < Apex::Server
  port 8080 # defaults to 8080

  layout do
    "<html>" +
    "<head><title>Apex</title></head>" +
    "<body>" +
    content +
    "</body>" +
    "</html>"
  end

  get "/" do |r|
    "<h1>Apex is running. Response: #{r}</h1>" +
    "<p><a href='/about'>About Apex</a></p>"
  end

  get "/about" do |r|
    "<h1>About Apex</h1>" +
    "<p><a href='/'>Home</a></p>"
  end

  post "/some_post" do |request|
    request.headers["User-Agent"]
  end
end

Then in your AppDelegate (or wherever you'd like to start your server):

@server = WebServer.new
@server.start_server

JSON

You can also return json. You can specify the response_type, like so:

get "/current_user", response_type: :json do |request|
  {
    name: 'Todd',
    age: 21
  }
end  

Or it will auto-detect the repsonse type if you return a hash instead of a string:

get "/current_user" do |request|
  {
    name: 'Todd',
    age: 21
  }
end  

Benchmarking

Somewhat useless (but still fun) benchmarking against a minimal Node.js/Express app shows Apex serving requests about 1.4x as fast as Node.

# Node.js / express.js app found in ./benchmarks/node/app.js
$ ab -r -n 10000 -c 6 -r http://192.168.1.246:8081/benchmark | grep "Requests per second"
Requests per second:    2789.32 [#/sec] (mean)
# Apex server found in ./app/app_delegate.rb
$ ab -r -n 10000 -c 6 -r http://192.168.1.246:8080/benchmark | grep "Requests per second"
Requests per second:    3862.26 [#/sec] (mean)

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request