Nested

Nested is a DSL to create a restful API in a declarative way. It is implemented in ruby. The author has some strong opinions about REST/API.

Quickstart

Nested provides you a bunch of keywords to declare the resources of your API. Most important are "singleton", "many" and "one".

class MyApi < Nested::App
  singleton :user
end

You just declared your first resource! But it does not do much right, so lets add a HTTP verb to make it accessible.

class MyApi < Nested::App
  singleton :user do
    get
  end
end

Now our resource is reachable by issuing a GET request to "/user". It still does not return any useful data. A resources is always backed by a model. Mostly you will use an array, hash or orm-instances (e.g. activerecord) as underlying model. The easiest way is to provide a block to your resource.

class MyApi < Nested::App
  singleton :user, ->{ {name: "joe"} } do
    get
  end
end

The model block will be invoked each time the resource is requested. We still do not get back the underlying model from our resource. In nested you have to explicitly whitelist which fields your want to expose for a resource.

class MyApi < Nested::App
  singleton :user, ->{ {id: 99, name: "joe"} } do
    serialize :id, :name
    get
  end
end

Congrats! You just created your first nested API. Checkout the other sections to get more information about different resource types, verbs, serialization and conditionals.

Nested:App

In nested you implement your API as a normal ruby class which inherits from Nested::App

class MyApi < Nested::App
end

Resources

Singleton

A unique value.

class MyApi < Nested::App
  # the current user
  singleton :user do
    serialize :id, :email, :username

    # GET /user
    get
  end

  # session which is used to login/logout
  singleton :session do
    # perform login, POST /session
    post

    # perform logout, DELETE /session
    delete
  end
end

Many

A list of values.

class MyApi < Nested::App
  many :tasks do
    serialize :id, :title, :description

    # GET /tasks
    get
  end
end

One

A specific value of many resource.

class MyApi < Nested::App
  many :tasks do
    serialize :id, :title, :description

    # GET /tasks
    get

    one do
      # GET /tasks/:id
      get
    end
  end
end

One can only be used within a enclosing Many. One inherits its name and serialization information from the Many.

Http Verbs

Nested supports all commonly used http verbs used in a resftul API. Call the verb as method inside the resource block to make the resource respond to that http verb.

class MyApi < Nested::App
  singleton :user do
    # respond to GET /user
    get

    # respond to POST /user
    post

    # respond to DELETE /user
    delete

    # respond to PUT /user
    put

    # respond to PATCH /user
    patch
end

You can pass a block to each http verb to impement the concret behavior.

class MyApi < Nested::App
  singleton :user, ->{ {name: "joe" } } do
    get do
      puts "i am a GET request"
    end

    delete do
      puts "and i am a DELETE one"
    end
  end
end

The http verb block can access the model of the resource as an instance variable.

class MyApi < Nested::App
  singleton :user, ->{ {name: "joe" } } do
    get do
      puts "my name is #{@user.name}"
    end
  end
end

The model is available in all http verb blocks. Except in post. The post block has to return a new model.

class MyApi < Nested::App
  singleton :user do
    post do
      {name: "joe"}
    end
  end
end

Nested gives you access to http parameters through the params method as known from other frameworks and in addition to this a useful shorthand.

class MyApi < Nested::App
  singleton :user, ->{ {name: "joe", age: 33 } } do
    put do
      @user.name = params[:new_name]
      @user.age = params[:age]
    end

    # same as

    put do |new_name, age|
      @user.name = new_name
      @user.age = age
    end
  end
end

Serialize

Nested does not automatically serialize and expose a attributes of the underlying model as resource fields. You have to list them explicitly. This allows you fine grain control over what and when something is exposed and gets you a decoupling from your model layer as well.

Serialize a single field

class MyApi < Nested::App
  singleton :user do
    serialize :email
    get
  end
end

Serialize multiple fields

class MyApi < Nested::App
  singleton :user do
    serialize :id, :email, :username
    get
  end
end

You can invoke serialize multiple times.

class MyApi < Nested::App
  singleton :user do
    serialize :id, :email
    serialize :username
    get
  end
end

In the previous examples we always serialize a 1:1 field value from the model. Sometimes you want to transform the model value or serialize some completly synthetic fields. This can be easily accomplished by passing a one entry Hash to serialize. The key will be used as serialized field name. The value of the hash is expected to be a block which gets invoked with the model as argument. The return value of the block will be used a serialization value.

class MyApi < Nested::App
  singleton :user do
    serialize :id, :email
    serialize username: ->(user){ "*** #{user.username} ***" }
    get
  end
end