smithery/glandais

contract-first-api

Generate OpenAPI contract from backend and regenerate frontend/mobile API clients

Installation

$ npx skills add smithery/glandais --skill contract-first-api

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 3,710 B
  • docs SUMMARY.md 107 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Contract-First API Workflow

Run this skill after modifying backend REST resources or DTOs to sync the OpenAPI contract and regenerate the frontend/mobile clients.

Step 0 — Bump the API contract version (always, before generating)

pedalons.api.version in backend/src/main/resources/application.properties is the single source of truth for the contract version. It feeds both info.version in contracts/openapi.yaml and GET /api/version (which also reports the git commit the server was built from), so deployments can be identified. Bump it whenever the contract changes — semver on the contract itself:

  • MAJOR — breaking change: endpoint or field removed/renamed, type changed, optional field became required
  • MINOR — backwards-compatible addition: new endpoint, new optional field
  • PATCH — descriptions/docs only

If the generated contracts/openapi.yaml diff turns out to be empty, revert the bump.

One-shot (preferred)

The repo root has regenerate.sh, which runs the whole chain end-to-end and fails fast (set -e):

bash regenerate.sh

It performs, in order:

  1. cd backend && mvn clean package -DskipTests — generates contracts/openapi.{yaml,json}
  2. cd frontend && pnpm check — see below
  3. cd mobile && bash check.sh — see below

Prefer this over running the steps by hand so nothing drifts out of sync.

Steps (what the scripts do)

1. Generate OpenAPI Contract

cd backend && mvn clean package -DskipTests

Generates contracts/openapi.yaml and contracts/openapi.json.

2. Regenerate Frontend Client — pnpm check

cd frontend && pnpm check

pnpm check expands to: pnpm install && pnpm generate-api && pnpm generate-routes && pnpm format && pnpm typecheck && pnpm lint && pnpm build.

  • generate-api runs Orval → src/api/dto/, src/api/endpoints/, src/api/zod/
  • generate-routes regenerates the UI routes contract (paths.generated.*, AASA, deeplinks) from contracts/routes.yaml — don't skip this; it's part of the contract surface
  • typecheck (tsgo -b) is the real type gate — not build

3. Regenerate Mobile Client — check.sh

cd mobile && bash check.sh

check.sh runs: flutter pub get && dart run openapiretrofitgenerator && dart run build_runner build && flutter analyze.

  • Generates lib/api/generated/clients/ (Retrofit) and lib/api/generated/models/ (Freezed)
  • flutter analyze verifies no Dart errors

After Running

  1. Report any errors from the generation or verification steps.
  2. If there are TypeScript or Dart errors, help fix them.

Common Issues

  • Empty schemas in OpenAPI: Missing @Schema(implementation = ...) in @APIResponse annotations
  • Orval errors: Usually caused by an invalid OpenAPI spec — check backend annotations
  • Mobile buildrunner conflicts: buildrunner build deletes conflicting outputs by default (the old --delete-conflicting-outputs flag was removed in build_runner 2.5.0)
  • @Tag name collides in the mobile client: the tag becomes a getter on the generated PedalonsApiClient, which already carries static String get version. A tag named Version therefore produces a Dart compile error, and flutter analyze won't catch it (analysis_options.yaml excludes lib/api/generated/**) — run dart analyze lib/api/generated/ after renaming a tag.
  • Renaming a @Tag leaves stale generated files: the mobile generator writes the new *_client.dart but doesn't delete the old one; remove it by hand.