We all love type-safe interaction between system components.
It's also a great idea to be able to use the same TypeScript types both in our server and client codebases, which is often referred as isomorphic TypeScript.
However, in a current state of Deepkit, we are limited to a cohesive approach, where both server and client codebases should be coupled: https://deepkit.io/documentation/rpc
This approach is also being used by some other popular tools like https://trpc.io/.
However, the state of a modern JS ecosystem is complicated – we have numerous runtimes (Node, Bun, Deno, Browser, React Native), a bunch of bundlers a build tools.
And sometimes making client and server codebases aware of each other becomes painful – you have to make sure the different tools all understand each other's output, TSConfigs and TS versions are compatible and etc.
Sometimes it's just hard to make these parts play well together.
Solution
Sometimes you just need to have your codebases isolated with some of the reused code being shipped as common packages.
There's an alternative approach for that – generating SDK code for clients to be used. Usually it has a form of an NPM package.
It has a downside of the necessity to be regenerated every time server APIs are changed, but this, however, gives additional flexibility and isolation.
Adepts of type-safety been using this approach for a long time, for example we took OpenAPI definitions and generated client SDKs based on that. It was great when there was no other solution, but it has lots of downsides, at least because OpenAPI definitions may be inaccurate or miss some of the important metadata. It's also completely unusable for RPC.
Suggestion
Provide an ability to generate code (package?), which:
is aware of specified HTTP and RPC public APIs, its details and re-exports I/O types as Typescript types which can be consumed in a client app;
doesn't depend on a server codebase at runtime;
can be used to call HTTP and RPC controllers at a given network address;
fully type-safe and provides validation, serialization and type casting abilities;
Usage example
Just an example, I haven't spent any time on thinking of a great DX.
../packages/server-sdk is now a regular NPM package;
In a client codebase which depends on generated @acme/server-sdk package:
import { HttpApiClient } from '@acme/server-sdk';
import { SomeType} from '@acme/server-sdk'; // this type was used in a controller I/O definition and is available for client
const client = new HttpApiClient('example.com/api');
const result = await client.ControllerA.controllerMethod(type, safe, arguments);
Problem
We all love type-safe interaction between system components.
It's also a great idea to be able to use the same TypeScript types both in our server and client codebases, which is often referred as isomorphic TypeScript.
However, in a current state of Deepkit, we are limited to a cohesive approach, where both server and client codebases should be coupled: https://deepkit.io/documentation/rpc
This approach is also being used by some other popular tools like https://trpc.io/.
However, the state of a modern JS ecosystem is complicated – we have numerous runtimes (Node, Bun, Deno, Browser, React Native), a bunch of bundlers a build tools.
And sometimes making client and server codebases aware of each other becomes painful – you have to make sure the different tools all understand each other's output, TSConfigs and TS versions are compatible and etc.
Sometimes it's just hard to make these parts play well together.
Solution
Sometimes you just need to have your codebases isolated with some of the reused code being shipped as common packages.
There's an alternative approach for that – generating SDK code for clients to be used. Usually it has a form of an NPM package.
It has a downside of the necessity to be regenerated every time server APIs are changed, but this, however, gives additional flexibility and isolation.
Adepts of type-safety been using this approach for a long time, for example we took OpenAPI definitions and generated client SDKs based on that. It was great when there was no other solution, but it has lots of downsides, at least because OpenAPI definitions may be inaccurate or miss some of the important metadata. It's also completely unusable for RPC.
Suggestion
Provide an ability to generate code (package?), which:
Usage example
Just an example, I haven't spent any time on thinking of a great DX.
Generate package
Run code generation
../packages/server-sdk
is now a regular NPM package;In a client codebase which depends on generated
@acme/server-sdk
package:const client = new HttpApiClient('example.com/api');
const result = await client.ControllerA.controllerMethod(type, safe, arguments);