Skip to content

Nested request payloads are not camelized #6

Description

@lineoffligbot

Generator::API#extract_body_params walks schema["properties"] exactly one
level deep, so key conversion stops at the top of the payload.

Top level converts correctly:

def query_campaign(ad_product_filter:, portfolio_id_filter: nil, ...)
  request(:post, "/adsApi/v1/query/campaigns",
    json: { "adProductFilter" => ad_product_filter, "portfolioIdFilter" => portfolio_id_filter }.compact)
end

One level down, nothing happens:

def create_campaign(campaigns: nil)
  request(:post, "/adsApi/v1/create/campaigns", json: { "campaigns" => campaigns }.compact)
end

So foo_bar becomes fooBar at the top and the caller hand-writes camelCase for
everything below. The asymmetry lands precisely on the biggest payloads. A single
campaign object has 24 properties, nested arbitrarily deep:

adProduct, autoCreationSettings, brandId, budgets, costType, countries,
endDateTime, fees, flights, frequencies, marketplaceConfigurations,
marketplaceScope, marketplaces, name, optimizations, portfolioId,
purchaseOrderNumber, salesChannel, siteRestrictions, skanAppId,
startDateTime, state, tags, targetedPGDealId

create_async_report(configuration:) has the same problem: adProduct, columns,
filters, format, groupBy, reportTypeId, timeUnit.

Options

  1. Recursive key transform on the way out. Cheap, no new dependency. But it is
    lossy: targetedPGDealId round-trips to targetedPgDealId. Needs an acronym
    table (PG, SKAN, ASIN, SKU, DSP, ...). Peddler solves exactly this with
    lib/peddler/acronyms.rb feeding a Zeitwerk inflector.
  2. Generate the nested types. Data classes for request bodies, the way Peddler
    generates lib/peddler/reports/*.rb. Much larger lift, but it is the only option
    where the RBS story is actually complete instead of untyped at every interesting
    boundary.
  3. Do nothing, document it. Defensible for a deliberately thin generated client:
    nested bodies are raw JSON, matching the Amazon docs one-to-one.

Option 3 is the honest status quo and costs a README paragraph. Option 2 is the
real fix. Option 1 is the trap: it looks like the cheap win but silently corrupts
acronym-bearing keys unless the table is exhaustive.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestquestionFurther information is requested

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions