APIs as Inheritable Classes
Distributed object-oriented programming for the service era. APIs aren't endpoints — they're objects with persistent state, callable behavior, and identity.
What if you could treat an entire API the same way you treat a class in object-oriented programming? Not just the types or the contracts, but the actual runtime behavior — databases, endpoints, business logic — all inheritable, overridable, and composable.
The Paradigm Shift
In traditional software development, we have a fundamental mismatch. Within a single program, we enjoy the full power of object-oriented design: classes, inheritance, polymorphism, encapsulation. But the moment we cross a network boundary, all of that disappears. We're left with raw HTTP calls, JSON payloads, and manually coordinated contracts.
APIs as Inheritable Classes eliminates this boundary. The mapping is direct:
- Class = API — The service itself is your class definition
- Properties = Tables — Persistent state lives in the database
- Methods = Endpoints — Callable behavior exposed over the network
- Inheritance = Import and Extend — One service extends another
- Override = Plugin Pipelines — Replace specific behaviors without forking
- Composition = Aggregate Without Modification — Combine services declaratively
- Interface = Contract (OpenAPI) — Schema-driven type safety across boundaries
Real-World Use Cases
Multi-Tenant SaaS Platform
Imagine building a white-label e-commerce platform. Each tenant needs their own checkout flow, product catalog, and pricing rules — but they all share core infrastructure. With inheritable APIs, your base EcommerceAPI defines standard endpoints. Each tenant's API extends it, overriding only what's different. The checkout endpoint for Tenant A can add loyalty points; Tenant B can integrate with their warehouse system. No duplication, no separate codebases.
Microservices Without the Pain
A payment service extends your base TransactionAPI, inheriting audit logging, retry logic, and idempotency handling. It only defines what's unique: Stripe integration, refund policies, fraud detection. When the base API improves its retry logic, every inheriting service benefits automatically.
Plugin Ecosystems
Third-party developers extend your platform API without access to source code. They override the beforeCreate hook to add validation, extend the User model with custom fields, or wrap existing endpoints with additional functionality — all through the contract, not the implementation.
How Existing Tools Approach This
Several technologies have explored pieces of this paradigm, though none fully realize the vision of APIs as true first-class objects:
CORBA / DCOM
The original distributed object systems. They proved the concept works but were hampered by complexity, platform lock-in, and binary protocols that didn't survive the web era. The idea was right; the execution was premature.
gRPC with Protocol Buffers
Provides strong contracts and code generation across languages. Supports service definitions that feel like interfaces. However, there's no inheritance model — each service is standalone. You can't extend a gRPC service; you can only call it.
GraphQL Federation
Apollo Federation allows composing multiple GraphQL services into a unified graph. This is composition but not inheritance. You can merge schemas, but one service can't override another's resolver or extend its types with new behavior.
Swagger/OpenAPI Extensions
OpenAPI specs can use $ref and allOf for schema composition. This achieves type inheritance but only at the documentation level. The runtime behavior — the actual endpoint implementation — remains completely separate.
LoopBack 4
A Node.js framework that models APIs as classes with decorators. Controllers can extend other controllers. It's the closest mainstream approach to inheritable APIs, but limited to a single runtime — you can't inherit from a remote service.
Why This Matters
The explosion of microservices has created an explosion of duplicated code. Every team writes their own authentication middleware, their own pagination logic, their own error handling. They copy-paste patterns from service to service, then spend years keeping them synchronized.
Inheritance solves duplication. That's why we invented it for classes. The same principle applies to services — if your authentication pattern is defined once and inherited everywhere, you fix it once, upgrade it once, test it once.
"A fundamentally different abstraction than REST, GraphQL, gRPC, or microservices. Distributed OOP — like CORBA or DCOM conceptually, but with modern deployment targets and schema-driven contracts."
How It Works
In an Application Operating System, API inheritance is achieved through configuration, not code. A child service declares a remote API as a dependency, then re-exposes its routes with an extended plugin pipeline.
Consider an identity service that handles authentication:
// identitydb/config.json - The parent API
{
"apis": {
"prjapi": {
"$aHRoutes": {
"$db:list.PATCH:/identitydb.identities/activate": {
"path": [
"plg-config",
"plg-authenticated",
"plg-validate_token",
"plg-activate",
"plg-generate_token_auth"
],
"expects": { ... },
"returns": { ... }
}
}
}
}
}
A members service that needs authentication inherits from the identity API:
// membersdb/config.json - The child API
{
"apis-remote": {
"identityapi": {
"deployments": {
"production": { "url": "https://identity.internal" }
}
}
},
"apis": {
"prjapi": {
"$aHIncludeServices": {
"apis": ["identityapi"]
},
"$aHRoutes": {
// Inherit route from parent API
"$api:identityapi.list.PATCH:/identitydb.identities/activate": {
"path": ["jsen-sym-plugin-default-connect"],
"expects": {
"$api:identityapi.list.PATCH:/identitydb.identities/activate -> expects": ""
},
"returns": "$api:identityapi.list.PATCH:/identitydb.identities/activate -> returns"
}
}
}
}
}
The notation $api:identityapi.list.PATCH:/identitydb.identities/activate references a route on a running remote API. The child service:
- Inherits the route — Exposes the parent's endpoint as its own
- Inherits the contract — The
-> expectsand-> returnsnotation pulls the parent's schema - Proxies via plugin —
jsen-sym-plugin-default-connectforwards requests to the parent - Can extend the pipeline — Add plugins before or after the connect to inject custom logic
"The child doesn't copy the parent's code — it references the running parent service. Change the parent, and all children inherit the change automatically."
Beyond Single Services
The real power emerges when inheritance crosses network boundaries. Your members API doesn't need to be in the same codebase or even the same data center as the identity API. It extends a remote service by contract, inheriting its schema and proxying calls to the parent while injecting its own logic.
This is how operating systems work — your program inherits capabilities from the kernel without having the kernel's source code. An application operating system extends the same principle to the entire stack.