Skip to main content

Creating an API-based Chart

Sometimes, charts data are complicated and closely tied to your business. Forest allows you to code how the chart is computed. Choose API as the data source when configuring your chart. Forest will make the HTTP call to Smart Chart URL when retrieving the chart values for the rendering.

Value API-based Chart

On our Live Demo, we have a MRR value chart which computes our Monthly Recurring Revenue. This chart queries the Stripe API to get all charges made in the current month (in March for this example). When serializing the data, we use the serialize_model() method. Check the value syntax below.
{ value: <number> }
Rails.application.routes.draw do
  # MUST be declared before the mount ForestLiana::Engine.
  namespace :forest do
    post '/stats/mrr' => 'charts#mrr'
  end

  mount ForestLiana::Engine => '/forest'
end
class Forest::ChartsController < ForestLiana::ApplicationController
  def mrr
    mrr = 0

    from = Date.parse('2018-03-01').to_time(:utc).to_i
    to = Date.parse('2018-03-31').to_time(:utc).to_i

    Stripe::Charge.list({
      created: { gte: from, lte: to },
      limit: 100
    }).each do |charge|
      mrr += charge.amount / 100
    end

    stat = ForestLiana::Model::Stat.new({ value: mrr })
    render json: serialize_model(stat)
  end
end

Repartition API-based Chart

On our Live Demo, we have a Charges repartition chart which shows a repartition chart distributed by credit card country. This chart queries the Stripe API to get all charges made in the current month (in March for this example) and check the credit card country.
When serializing the data, we use the serialize_model() method. Check the value syntax below.
{
  value: [{
    key: <string> ,
    value: <number>
  }, {
    key: <string> ,
    value: <number>
  }, …]
}
Rails.application.routes.draw do
  # MUST be declared before the mount ForestLiana::Engine.
  namespace :forest do
    post '/stats/credit-card-country-repartition' => 'charts#credit_card_country_repartition'
  end

  mount ForestLiana::Engine => '/forest'
end
class Forest::ChartsController < ForestLiana::ApplicationController
  def credit_card_country_repartition
    repartition = []

    from = Date.parse('2018-03-01').to_time(:utc).to_i
    to = Date.parse('2018-03-20').to_time(:utc).to_i

    Stripe::Charge.list({
      created: { gte: from, lte: to },
      limit: 100
    }).each do |charge|
      country = charge.source.country || 'Others'

      entry = repartition.find { |e| e[:key] == country }
      if !entry
        repartition << { key: country, value: 1 }
      else
        ++entry[:value]
      end
    end

    stat = ForestLiana::Model::Stat.new({ value: repartition })
    render json: serialize_model(stat)
  end
end

Time-based API-based Chart

On our Live Demo, we have a Charges time-based chart which shows the number of charges per day. This chart queries the Stripe API to get all charges made in the current month (in March for this example) and group data by day.
When serializing the data, we use the serialize_model() method. Check the value syntax below.
{
  value: [{
    label: <string> ,
    values: { value: <number> }
  }, {
    label: <string> ,
    values: { value: <number> }
  }, …]
}
Rails.application.routes.draw do
  # MUST be declared before the mount ForestLiana::Engine.
  namespace :forest do
    post '/stats/charges-per-day' => 'charts#charges_per_day'
  end

  mount ForestLiana::Engine => '/forest'
end
class Forest::ChartsController < ForestLiana::ApplicationController
  def charges_per_day
    values = []

    from = Date.parse('2018-03-01').to_time(:utc).to_i
    to = Date.parse('2018-03-31').to_time(:utc).to_i

    Stripe::Charge.list({
      created: { gte: from, lte: to },
      limit: 100
    }).each do |charge|
      date = Time.at(charge.created).beginning_of_day.strftime("%d/%m/%Y")
      entry = values.find { |e| e[:label] == date }
      if !entry
        values << { label: date, values: { value: 1 } }
      else
        ++entry[:values][:value]
      end
    end

    stat = ForestLiana::Model::Stat.new({ value: values })
    render json: serialize_model(stat)
  end
end

Objective API-based Chart

Creating an Objective Smart Chart means you’ll be fetching your data from an external API endpoint: This endpoint must return data with the following format:
{
  value: {
    value: xxxx,
    objective: yyyy
  }
}
Here’s how you could implement it:
...

namespace :forest do
  post '/stats/some-objective' => 'customers#some_objective'
end

...
...

def some_objective
  # fetch your data here
  stat = ForestLiana::Model::Stat.new({
    value: {
      value: 10, # the fetched value
      objective: 678 # the fetched objective
    }
  })
  render json: serialize_model(stat)
end

...