OapiCodemode.Ingest.Normalize (oapi_codemode v0.5.0)

Copy Markdown View Source

Extracts a flat operation list from a spec, deriving stable readable ids where operationId is missing (the oaskit cards_freeze_ALTIJVI lesson: never trust upstream ids to exist or be usable).

Works on a document whose payload $refs are still intact (Ingest.decompose/1, the one production caller) and on a whole-document-dereferenced one, which is now only the parity oracle the test suite runs OapiCodemode.Resolve against (see OapiCodemode.Ingest.Deref). Parameters are identity-resolved: a parameter Reference Object is followed only far enough to learn {name, in, required} — recorded in param_index and used for the OpenAPI path/operation merge — while parameters keeps the $ref. Nothing referenced is ever inlined here, and the requestBody is kept verbatim for the same reason (operations/2's :request_body option).

Fields are scalar-coerced because they become typed store columns: a non-string operationId is treated as absent, non-string summary and description become nil, tags keeps only its string elements, deprecated is === true. This is the same lenient-ignore policy as the shape guards below, applied to values rather than shapes.

Summary

Functions

Picks the media type a request body should be sent as, and its schema.

The HTTP methods this module extracts operations for.

Extracts the operation list.

Splits a path template into literal segments and {:param, name} holes.

Functions

extract_body(body)

@spec extract_body(term()) :: map() | nil

Picks the media type a request body should be sent as, and its schema.

Public because read-time resolution needs the same answer: Resolve resolves a stored body's refs and then calls this function on the result, rather than reimplement the JSON-preferring media-type choice. Then a body the document inlined and a body it wrote as a Reference Object produce the identical %{"required", "content_type", "schema"} shape by construction, instead of by two implementations agreeing.

Takes a Request Body Object. Anything else — a Reference Object nobody resolved, a marker, a scalar — is no body: nil.

methods()

@spec methods() :: [String.t()]

The HTTP methods this module extracts operations for.

Exposed so the proxy can derive its own method table from it (M4): a method extracted here but unknown to the proxy would blow up at request time rather than at ingest.

operations(spec, opts \\ [])

@spec operations(
  map(),
  keyword()
) :: [OapiCodemode.Operation.t()]

Extracts the operation list.

:request_body says what becomes of an operation's requestBody:

  • :extract (the default) — put it through extract_body/1 here. Used only by the parity oracle (tests), whose document is already dereferenced, so the media type chosen now is the one a later read would choose.
  • :verbatim — keep the node exactly as the document wrote it. The Ingest.decompose/1 path, whose refs are still intact: a Reference Object has no content to choose a media type from, so choosing here would read it for a schema key it does not have and lose the body from the stored row for good. OapiCodemode.Resolve resolves first and calls extract_body/1 after, on every body alike.

parse_segments(path)

@spec parse_segments(String.t()) :: [String.t() | {:param, String.t()}]

Splits a path template into literal segments and {:param, name} holes.