# 0002. Keep HTTP REST; do not replace the API with GraphQL - Status: Accepted - Date: 2026-09-18 - Deciders: VMall maintainers - Related: [0001](0001-rust-api-modular-monolith.md) ## Context The mall, shop-admin, and platform-admin apps share one typed REST client in `@vmall/shared`. Handlers already return composed DTOs (`ProductWithSkus`, `OrderView`, `CartView`). Command flows (checkout, pay, cancel, partial ship, issue invoice) are state machines with 409 conflicts and idempotent `UPDATE … WHERE status = …`. A GraphQL rewrite was proposed to “modernize” the API. ## Decision **Keep REST** on `/api/*`. Do not replace the public contract with GraphQL. A **read-only GraphQL** endpoint for catalog browsing may be considered later if a third-party or mobile client needs arbitrary field sets. Write paths (checkout, stock, fulfillment, invoices) stay REST commands. ## Consequences Positive: - Existing OpenSpec HTTP scenarios, integration tests, and the mock adapter remain valid. - Role checks stay on routes (`AuthUser::require_*`), not per GraphQL field. - GET caching and payment/webhook-style POSTs stay straightforward. Negative: - Clients that want a custom nested graph still make several REST calls (already the case; DTOs cover storefront needs). ## Alternatives considered **Full GraphQL (`async-graphql`) as the only API.** Rejected: would rewrite three apps, `@vmall/shared`, seed scripts, and all HTTP tests; field-level auth for three roles on one schema is harder to audit; N+1 needs DataLoaders; uploads and webhooks still want REST. **JSON:API / sparse fieldsets.** Not needed while composed DTOs match the UIs. **BFF per frontend.** Unnecessary while all three apps share one contract package.