deepkit / deepkit-framework

A new full-featured and high-performance TypeScript framework
https://deepkit.io/
MIT License
3.22k stars 123 forks source link

[Feature request] API SDK extraction #548

Open alpharder opened 9 months ago

alpharder commented 9 months ago

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

  1. Write a config file:
{
 exportTo: '../packages/server-sdk',
 controllersToExport: [ControllerA, ControllerB],
exportedPackageName: '@acme/server-sdk'
}
  1. Run code generation

    npm run generate-sdk
  2. ../packages/server-sdk is now a regular NPM package;

  3. 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);

lionelhorn commented 3 months ago

@alpharder in a way, could https://github.com/hanayashiki/deepkit-openapi

Only for the http controllers though

alpharder commented 3 months ago

@lionelhorn In a some way – yes, for HTTP