Module: ZeroClick::Sellers::PageViews

Defined in:
lib/zeroclick/sellers/page_views.rb

Overview

POST /v1/page-views: one fire-and-forget marketing page-view beacon.

As in Usage and Agentify, building the payload and interpreting the response are separate from transport, so what a response MEANS is decided in one pure place. Unlike the usage endpoints the API answers 204 with no body, so the success path parses nothing — see #interpret_report.

The visitor's user-agent/accept/IP are forwarded so the API can classify the viewer and derive the shared viewer id; they are consumed there and never stored raw. Only the path is ever sent, never the query.

Constant Summary collapse

REPORT_PATH =
"/v1/page-views"
REPRESENTATIONS =

What the site actually served for a page-content request: the agent markdown variant, or the normal HTML.

%w[html markdown].freeze

Class Method Summary collapse

Class Method Details

.build_payload(seller:, path:, status: nil, duration_ms: nil, representation: nil, journey_id: nil, captured_at: nil, user_agent: nil, accept: nil, client_ip: nil, country: nil, referrer_host: nil) ⇒ Object

Build the wire body: camelCase string keys, every absent optional key omitted. seller is the seller's public id and path must be an absolute path, both rejected before any request leaves the process.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/zeroclick/sellers/page_views.rb', line 30

def build_payload(seller:, path:, status: nil, duration_ms: nil, representation: nil,
                  journey_id: nil, captured_at: nil, user_agent: nil, accept: nil,
                  client_ip: nil, country: nil, referrer_host: nil)
  Sellers.require_slug!(seller, "seller", "report_page_view")
  unless path.is_a?(String) && path.start_with?("/")
    raise Error.new("malformed_input", operation: "report_page_view",
                                       message: "path must be a string beginning with \"/\"")
  end
  if !representation.nil? && !REPRESENTATIONS.include?(representation)
    raise Error.new("malformed_input", operation: "report_page_view",
                                       message: "representation must be \"html\" or \"markdown\"")
  end

  payload = { "seller" => seller, "path" => path }
  payload["status"] = status unless status.nil?
  payload["durationMs"] = duration_ms unless duration_ms.nil?
  payload["representation"] = representation unless representation.nil?
  payload["journeyId"] = journey_id unless journey_id.nil?
  payload["capturedAt"] = captured_at unless captured_at.nil?
  payload["userAgent"] = user_agent unless user_agent.nil?
  payload["accept"] = accept unless accept.nil?
  payload["clientIp"] = client_ip unless client_ip.nil?
  payload["country"] = country unless country.nil?
  payload["referrerHost"] = referrer_host unless referrer_host.nil?
  payload
end

.interpret_report(status, _body) ⇒ Object

A 204 carries no body, so there is nothing to parse; a non-2xx is the only failure a well-formed beacon can hit here. Distinct from Usage.interpret_report, which requires a JSON body.

Raises:



60
61
62
63
64
# File 'lib/zeroclick/sellers/page_views.rb', line 60

def interpret_report(status, _body)
  return if (200..299).cover?(status)

  raise Error.new("api_status_error", operation: "report_page_view", status: status)
end