deepkit-framework icon indicating copy to clipboard operation
deepkit-framework copied to clipboard

[Feature request] API SDK extraction

Open alpharder opened this issue 2 years ago • 2 comments

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:

  • 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.

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
  1. ../packages/server-sdk is now a regular NPM package;

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


alpharder avatar Feb 04 '24 14:02 alpharder

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

  • Client generators be used to achieve the same goals?

Only for the http controllers though

lionelhorn avatar Aug 07 '24 21:08 lionelhorn

@lionelhorn In a some way – yes, for HTTP

alpharder avatar Aug 08 '24 06:08 alpharder