Gamend.ApiConventions (gamend_core v1.0.1192)

Copy Markdown View Source

Mechanical checks for the conventions in docs/specs/api-conventions.md.

Source-level, not runtime: the rules are about how code is written (field names, serializer shapes, route paths), so they are checked by parsing files rather than by introspecting a booted app. mix gamend.api.lint runs them; CI fails on any violation.

These exist because the conventions were implicit for a year and drifted exactly where nobody was looking — 16 fields serialized null against a documented "never null" policy, OpenAPI schemas contradicted their own serializers, and one duration setting shipped with no unit in its name. A convention nothing enforces is a suggestion.

Summary

Functions

Every path the compiled router serves, :params as {}.

String/map schema fields that can actually be nil: no default:, and not in the changeset's required list.

Every violation, ordered by rule then file.

Types

violation()

@type violation() :: %{
  rule: String.t(),
  file: String.t(),
  line: pos_integer(),
  message: String.t()
}

Functions

declared_route_paths()

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

Every path the compiled router serves, :params as {}.

Read from Phoenix.Router.routes/1 rather than parsed from source — routes live inside scope blocks, so the literal strings in the source are suffixes, not full paths.

nullable_schema_fields()

@spec nullable_schema_fields() :: %{required(String.t()) => String.t()}

String/map schema fields that can actually be nil: no default:, and not in the changeset's required list.

violations()

@spec violations() :: [violation()]

Every violation, ordered by rule then file.