Skip to content

BrocksiNet/symfony-use-case-driven-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Symfony Use-Case-Driven API Experiment

This repository is a greenfield reference implementation for a use-case-driven, contract-first API built with plain Symfony.

The goal is to validate patterns that could realistically transfer into Shopware later:

  • hand-authored OpenAPI as the public contract
  • explicit DTO mapping instead of entity exposure
  • thin controllers and use-case handlers
  • contract testing against the OpenAPI document
  • minimal runtime magic and minimal framework lock-in
  • audience-shaped API surfaces for store and admin use cases

The implemented slice is still intentionally small. It is large enough to test store reads, idempotent writes, one admin read flow, versioning, and contract governance, but it is not yet proof that the same discipline will feel equally comfortable across dozens of use cases. Teams should validate naming, module boundaries, shared assemblers, and OpenAPI module structure again when the surface grows.

Runtime Surface

The current reference slice is split into two explicit audiences.

Store contract API:

  • GET /api/store/products
  • GET /api/store/products/{product_id}
  • GET /api/store/categories
  • GET /api/store/categories/{category_id}
  • POST /api/store/carts
  • GET /api/store/carts/{cart_id}
  • POST /api/store/carts/{cart_id}/items

Admin contract API:

  • GET /api/admin/open-carts

Deprecation proof point:

  • GET /api/store/demo/deprecated-category/{category_id} is a demo-only deprecated endpoint that advertises Deprecation, Sunset, and successor Link headers for the canonical GET /api/store/categories/{category_id} route

Public documentation endpoints:

  • GET /docs
  • GET /docs/swagger
  • GET /docs/deprecation-policy
  • GET /openapi.json
  • GET /openapi.yaml

Local credentials for testing:

  • store: Context-Token: storefront-context-token
  • admin: admin-token
  • default pinned contract version: 2026-04-01

Optional request version override:

  • Contract-Version: 2026-03-01

Local Workflow

This project is optimized for a Podman-based workflow.

Start the app:

podman compose up -d app

Load fixtures:

podman compose run --rm app php bin/console app:fixtures:load --force

Open the docs:

Example requests:

curl -H 'Context-Token: storefront-context-token' \
  'http://localhost:8001/api/store/products?sort=price'

curl -H 'Authorization: Bearer admin-token' \
  'http://localhost:8001/api/admin/open-carts'

curl -H 'Context-Token: storefront-context-token' \
  -H 'Contract-Version: 2026-03-01' \
  'http://localhost:8001/api/store/products?page_size=1'

One-Shot Verification

Run everything with:

./bin/test-everything

That script will:

  • install Node dependencies if needed
  • lint and publish the OpenAPI artifacts
  • detect breaking OpenAPI changes against the committed baseline
  • validate versioned frozen specs and changelogs
  • prove machine-consumability with @shopware/api-gen
  • start the app
  • reload fixtures
  • run PHPStan
  • run Rector in dry-run mode
  • run php-cs-fixer in dry-run mode
  • run PHPUnit
  • run phpbench benchmarks
  • hit the main store/admin HTTP flows end to end

Lint Markdown docs with:

npm run docs:lint:markdown

OpenAPI Tooling

The canonical OpenAPI source is:

The source is split into reusable JSON modules under:

  • openapi/src/paths
  • openapi/src/test-metadata/paths
  • openapi/src/components/schemas
  • openapi/src/components/responses
  • openapi/src/components/parameters
  • openapi/src/components/requestBodies
  • openapi/src/components/headers

Build-time tooling:

  • Redocly CLI for linting and bundling
  • static Redoc output as the default reviewer-facing docs
  • local Swagger UI assets built from swagger-ui-dist for interactive testing
  • custom structure checks to prevent duplicate schema shapes and inline complex schemas
  • @shopware/api-gen proof generation for audience-scoped TypeScript output

Relevant commands:

npm install
npm run openapi:lint
npm run openapi:build:test-spec
npm run openapi:check:structure
npm run openapi:check:versioning
npm run openapi:diff
npm run openapi:publish
npm run openapi:proof:api-gen

Published build artifacts:

  • openapi/baseline/openapi.json
  • openapi/build/openapi.yaml
  • openapi/build/openapi.json
  • openapi/build/openapi.test.json
  • openapi/build/versions/2026-03-01/openapi.json
  • openapi/build/versions/2026-04-01/openapi.json
  • public/openapi/openapi.yaml
  • public/openapi/openapi.json
  • public/openapi/versions/2026-03-01/openapi.json
  • public/openapi/versions/2026-04-01/openapi.json
  • public/docs/index.html
  • public/docs/swagger/index.html
  • proofs/api-gen/2026-04-01/store/api-types/storeApiTypes.d.ts
  • proofs/api-gen/2026-04-01/admin/api-types/adminApiTypes.d.ts
  • proofs/api-gen/2026-03-01/store/api-types/storeApiTypes.d.ts
  • proofs/api-gen/2026-03-01/admin/api-types/adminApiTypes.d.ts

The public docs and published raw spec are built from openapi/build/openapi.json. Contract tests use the internal merged artifact at openapi/build/openapi.test.json, which adds sidecar x-test-* metadata back for the test harness without exposing that control metadata in the public spec.

Quality Gates

PHP quality:

  • podman compose run --rm app composer phpstan
  • podman compose run --rm app composer rector
  • podman compose run --rm app composer cs
  • podman compose run --rm app php bin/phpunit
  • podman compose run --rm app composer phpbench

Architecture rules are enforced through PHPat in the PHPStan run.

Hosted quality:

Developer DX

Repository-friendly request collection:

Performance scenarios:

Key Docs

About

Experiment how to integrate a contract driven API with Symfony

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors