Backend
Ruby
net/http from the standard library. Nothing to add to the Gemfile.
require "json"
require "net/http"
require "uri"
class Pulse
BASE = URI("https://api.thepulseapi.com/api/v1").freeze
def initialize(api_key:, organization_id:)
@api_key = api_key
@organization_id = organization_id
end
def track(session_id, signals)
post("/track", sessionId: session_id, signals: signals)
end
def ranked_catalog(session_id, limit: 24)
post("/catalog/ranked", sessionId: session_id, limit: limit)
end
def session(session_id)
post("/session", sessionId: session_id)
end
private
def post(path, **body)
# organizationId is required on nearly every endpoint and is read from the body,
# not from the key.
body[:organizationId] = @organization_id
request = Net::HTTP::Post.new(BASE.path + path)
request["Content-Type"] = "application/json"
request["x-api-key"] = @api_key
request.body = JSON.generate(body)
response = Net::HTTP.start(
BASE.host, BASE.port,
use_ssl: true,
open_timeout: 5,
read_timeout: 5,
) { |http| http.request(request) }
raise "PULSE #{path}: #{response.code}" unless response.is_a?(Net::HTTPSuccess)
JSON.parse(response.body)
end
endRails
PULSE = Pulse.new(
api_key: ENV.fetch("PULSE_API_KEY"),
organization_id: ENV.fetch("PULSE_ORG_ID"),
)def show
session_id = cookies[:pulse_session]
@products = if session_id
PULSE.ranked_catalog(session_id, limit: 24)["items"]
end
rescue StandardError
# Personalisation is an enhancement. Catalogue order is a working page.
@products = nil
ensure
@products ||= Product.where(category: params[:slug]).limit(24)
endBoth timeouts
open_timeout bounds the connection and read_timeout bounds the wait for a response. Set
only the first and a server that accepts your connection and then stalls holds the request
until something upstream gives up.

