The question we get on every kickoff
On 23 of our last 30 migration kickoffs, a platform architect has asked the same question within the first hour: “Will the new system expose GraphQL?” The answer is no — and the reasoning is the same every time. GraphQL is a good fit for some problems. Oracle Forms migration is not one of them.
This post lays out why, based on what we’ve measured across 14 production deployments.
What the source system actually looks like
An Oracle Forms application is a collection of screens, each bound to a small number of database blocks. A block maps to a table or view. Queries are parameterized, result sets are bounded, and navigation between screens passes a handful of keys. The access pattern is narrow, predictable, and already described by the original .fmb files.
The median screen in our sample talks to 2.3 tables and runs 4 distinct queries. The 95th percentile hits 11 tables and 19 queries. This isn’t a domain where clients need to compose arbitrary graphs on the fly.
REST maps to the existing shape
Every block, trigger, and LOV in a migrated form has a direct REST equivalent:
GET /api/orders?status=open®ion=EU
GET /api/orders/{id}
POST /api/orders
PATCH /api/orders/{id}
POST /api/orders/{id}/approve
GET /api/lov/customers?q=acm
The generator produces one endpoint per block query, one per LOV, and one per named PL/SQL action. The OpenAPI spec falls out of the JSON descriptor automatically. Every endpoint is typed end-to-end because the types come from the original database schema, not from a hand-written resolver layer.
The GraphQL cost nobody talks about
GraphQL’s appeal is flexibility. Clients ask for exactly the fields they need, joins happen server-side, and over-fetching disappears. For a migration, those benefits show up as costs:
- N+1 resolution. Forms screens issue predictable joins. GraphQL resolvers have to reconstruct those joins at runtime, and DataLoader batching adds a layer that didn’t exist in the source system.
- Authorization surface. SOX-scoped applications need field-level access control. REST endpoints encode permissions at the route level; GraphQL pushes them into every resolver. We measured a 3.2x increase in auth-related code in a prototype GraphQL port.
- Query complexity limits. Production GraphQL servers need depth limits, cost analysis, and persisted queries to prevent abuse. None of this is needed for a known set of migrated screens.
- Caching. REST responses cache cleanly at the CDN and browser layer. GraphQL POST bodies don’t.
The audit argument
Oracle Forms migrations are frequently in scope for SOX, HIPAA, or similar regimes. Auditors review API surfaces. A REST API with 240 endpoints and an OpenAPI spec takes a day to walk through. A GraphQL schema with 80 types and arbitrary query composition takes a week — and the auditor still has questions about which client queries are actually possible in production.
On one utility migration, the audit team explicitly asked for REST because their existing control matrix was built around HTTP verbs and URL patterns. Rebuilding it for GraphQL would have pushed the SOX sign-off by a quarter.
Where GraphQL would make sense
We’re not religious about this. GraphQL is a good fit when clients are heterogeneous, the schema is broad, and query shapes are unpredictable — mobile apps pulling from a product catalog, for instance. Oracle Forms migrations are none of those things. The clients are known (the migrated screens), the schema is bounded (the database the Forms app already uses), and the queries are enumerated in the .fmb files themselves.
Choosing REST here isn’t conservatism. It’s matching the tool to the shape of the problem.
The takeaway
Every endpoint in our generated stack is REST, documented in OpenAPI, and derived directly from the original Forms metadata. The decision isn’t about which API style is better in the abstract. It’s about which one maps cleanly to 30 years of screen-bound database access, and which one auditors can sign off on before the first screen goes live.