Skip to content
Flon, the API maker that uses JSON
Ruby Shell
Branch: master
Clone or download
Latest commit d293fd0 Sep 14, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
bin Initial commit Sep 4, 2019
lib Bump vesion to 0.3.1 Sep 14, 2019
spec Use Flon::Request for endpoints Sep 13, 2019
.gitignore Initial commit Sep 4, 2019
.rspec Initial commit Sep 4, 2019
.rubocop.yml Exclude specs from rubocop Metrics/BlockLength Sep 6, 2019
.travis.yml Initial commit Sep 4, 2019
.yardopts Add .yardopts Sep 6, 2019
Gemfile Initial commit Sep 4, 2019
LICENSE.txt Initial commit Sep 4, 2019 Update Sep 13, 2019
Rakefile Initial commit Sep 4, 2019
flon.gemspec Remove rack-test as a dependency Sep 7, 2019


Flon, the API maker that uses JSON. It focuses on not doing any magic: it’s just a thin and convenient wrapper over Rack, with a hopefully obvious DSL.


Add this line to your application's Gemfile:

gem 'flon'

And then execute:


Or install it yourself as:

gem install flon


Basic usage

To use Flon, simply make a plain class extending Flon::DSL. This will put the router DSL in your class scope.

require 'flon'

class MyAPI
  extend Flon::DSL

  def initialize
    @names = []

  namespace '/names' do
    get '/'
    attr_reader :names

    post '/new'
    def add_name(request)
      @names << request.body

    namespace '/:index' do
      get '/'
      def name_by_index(request)

      put '/edit'
      def change_name(request)
        @names[request.params[:index].to_i] = request.body

You can then create a Flon::API using this:

api =

Note how you initialise everything normally—you can use this for dependency injection without a headache.

Flon::API is a bog-standard Rack app, so you can just use it in, or whatever method you use.


The DSL defines methods for routing based on every HTTP request method, except HEAD, TRACE, OPTIONS, and CONNECT. HEAD is handled by GET routes but the body is discarded.

When you call a routing method, the next method you define will be bound to that route.

get '/route'
def get_route
  # matches GET /route and HEAD /route

post '/route'
def post_route
  # matches POST /route

put '/route'
def put_route
  # matches PUT /route

delete '/route'
def delete_route
  # matches DELETE /route

patch '/route'
def patch_route
  # matches PATCH /route

Each routing DSL method takes a single route pattern as a String. The route pattern is the exact same as Sinatra’s.

The bound method is called when an HTTP request matches that route with that HTTP method.

The method will receive one argument, the Flon::Request object describing the HTTP request:

request.body         # Gets the body; returns a String, or nil if no body

request.headers      # Gets the headers; returns a Hash with String keys and
                     # String values

request.method       # Gets the HTTP method; returns a Symbol with the name of
                     # the method lowercased

request.params       # Gets the route and query parameters, merged, giving
                     # priority to route parameters; returns a Hash with Symbol
                     # keys

request.path         # Gets the path; returns a String

request.query_params # Gets the query parameters, specifically; returns a Hash
                     # with Symbol keys

request.route_params # Gets the route parameters, specifically; returns a Hash
                     # with Symbol keys

request.url          # Gets the request’s URL; returns an URI object

Note that the argument will not be passed if the method does not accept at least one argument, so you can leave it out if you’re not gonna use it.


You can also namespace routes:

namespace '/users' do
  get '/'
  attr_reader :users # GET /users

  post '/new'
  def add_user(request) # /users/new
    @users << request.body

  namespace '/:id' do
    def user_by_id(request) # GET /users/:id

    put '/edit'
    def edit_user(request) # PUT /users/:id/edit
      @users[request.params[:id].to_i] = request.body

Namespaces are entirely “virtual”, that is, they just concatenate their route patterns with their children, so they’re just there for DRYness.


The version method applies a namespace throughout every route:

version '/v1'

get '/yes'
def yes

get '/no'
def no

Going to /yes will give you a 404, but going to /v1/yes will give you "yes". The same thing happens with the /no route.

In reality, version is just an alias for namespace.


Whatever is returned by the route’s method is #to_json’d and sent back. If you want to return a custom response, return a Flon::Response object, which takes the status code as the first argument, the body as the second argument, and the headers as the third argument of its constructor:

get '/admin'
def admin, 'No. Go away.', 'X-Loser' => 'Yes')


After checking out the repo, run bin/setup to install dependencies. Then, run rake to run rubocop and the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to


Bug reports and pull requests are welcome on GitHub at


The gem is available as open source under the terms of the MIT License.

You can’t perform that action at this time.