This repository is dedicated to bringing the power of TSOA (TypeScript OpenAPI) to Deno, with a special focus on enabling TSOA APIs in Supabase Edge Functions. It provides a Deno-compatible version of the TSOA runtime, allowing the use of TSOA controllers in Edge Functions powered by Deno.
TSOA is an open-source framework designed to facilitate building REST APIs in TypeScript by automatically generating Swagger documentation from TypeScript interfaces and decorators. It simplifies API development by reducing boilerplate code and enhancing the TypeScript experience.
Hono is a fast and simple web framework for Deno, inspired by Express and other JavaScript/TypeScript frameworks. It's designed for building efficient and scalable server-side applications, and it's particularly well-suited for Deno environments.
- Deno Compatibility: Offers a Deno-compatible version of the TSOA runtime.
- Hono Integration: Includes a modified
hono-router
template for TSOA, facilitating the use with Hono in Deno.
To start using TSOA with Deno:
- Install the
tsoa-deno
on the client side to generate routes and spec files (ie.npm install -g tsoa-deno
). - The key difference with
tsoa-deno
compared to the standard TSOA npm package is the inclusion of thehono-router.hbs
in the resources folder, tailored for Deno and Hono. You can specify 'hono' as middleware intsoa.config
. - The code example below shows the needed config files for initial setup and usage. A fully functional example is also available in tsoa-deno-example repo.
For comprehensive guidance on building APIs with TSOA, refer to the original TSOA guide and the TSOA GitHub repository.
See tsoa-deno-example repo for a complete code example.
The only tsoa-deno specific setting of the config (compared to vanilla tsoa), is the middleware which must be 'hono'. This will ensure that tsoa-deno generates Deno/Supabase Edge functions compatible routes.ts code.
Filename: functions/tsoa.json
{
"entryFile": "tsoa.index.ts",
"noImplicitAdditionalProperties": "throw-on-extras",
"controllerPathGlobs": [
"**/*-controller.ts"
],
"spec": {
"outputDirectory": "api-specs",
"specVersion": 3
},
"routes": {
"routesDir": "./_shared",
"middleware": "hono"
}
}
It is important to set experimentalDecorators
to true in the deno.config, as of Deno 1.40 this setting is set to false as default.
Filename: functions/deno.json
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": false,
"lib": ["esnext", "dom"]
},
"importMap": "./import_map.json",
"include": [
"./**/*.ts"
]
}
In order for the library to work, two mappings are required in the import map: @hono and @tsoa-deno/runtime.
ℹ️ Supabase: In Supabase Edge functions, the import map has to be called "import_map.json" and be placed in the root or in the function root, Supabase import map docs. Supabase does not currently allow a custom deno.json configuration, so in Supabase deno.json will be ignored.
Filename: functions/import_map.json
{
"imports": {
"@hono": "https://deno.land/x/hono@v3.7.6/mod.ts",
"@tsoa-deno/runtime": "https://deno.land/x/tsoa_runtime@v6.1.5.0/mod.ts"
}
}
In the functions index file we get the routes defined in the shared folder (generated with tsoa-deno routes
) and register them in the hono router.
Filename: functions/tsoa/index.ts
/// <reference lib="deno.ns" />
// Get TSOA controller routes for this endpoint
import * as routes from '../_shared/routes.ts';
import { Hono } from '@hono';
const app = new Hono();
// Register routes
routes.RegisterRoutes(app);
Deno.serve(app.fetch);
The controller syntax is the same as in vanilla TSOA.
ℹ️ Supabase: In Supabase Edge functions the route (ie. @Route('/tsoa')
) has to correspond/be equal to the actual path of the Edge function.
Filename: functions/tsoa/tsoa-controller.ts
import { Route, Body, Post, Controller } from 'tsoa_runtime';
@Route('/tsoa')
export class TsoaController extends Controller {
/**
* A simple TSOA endpoint test
*/
@Post('test')
public async test(@Body() body: { input: string }): Promise<{ outputMatrix: number[] }> {
const outputMatrix = [1, 10, 4, 7];
return { outputMatrix };
}
}
Here are some useful npm scripts to watch for changes, generate the TSOA routes and start a local Deno dev server.
Filename: functions/package.json
...
"scripts": {
"start": "npm run watch",
"build": "tsoa-deno routes",
"serve": "npm run build && deno run --watch --allow-net --config deno.json example/index.ts",
"watch": "concurrently --names \"TSOA,DENO\" \"nodemon -x tsoa-deno spec-and-routes -e ts,js,mjs,cjs,json --ignore **/routes.ts --ignore **/swagger.json\" \"npm run serve\"",
"test": "deno test --allow-net --quiet --config deno.json"
},
...
This Deno port of tsoa-runtime is currently in a testing phase to gauge its suitability and acceptance among Deno developers. Contributions, feedback, and reports on usage experiences are highly welcomed and appreciated. We envision this project potentially becoming part of the mainstream TSOA release in the future. Please refer to the main repository for guidelines on contributing.