Skip to content

tsoniclang/express

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

68 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@tsonic/express

Express-style HTTP server APIs for Tsonic.

This package is part of Tsonic: https://tsonic.org.

Use this package to write Express-like apps in TypeScript and compile them to native binaries with tsonic.

Prerequisites

Quick Start (new project)

mkdir my-api && cd my-api
npx --yes tsonic@latest init

# Install Express runtime + bindings (installs required ASP.NET Core deps too)
npx --yes tsonic@latest add npm @tsonic/express

# Replace the default App.ts with a minimal API
cat > packages/my-api/src/App.ts <<'EOF'
import { express } from "@tsonic/express/index.js";

export function main(): void {
  const app = express.create();

  app.get("/", async (_req, res, _next) => {
    res.json({ ok: true });
  });

  app.listen(3000);
}
EOF

npm run dev

Then open http://localhost:3000/.

Hello World

// packages/my-api/src/App.ts
import { express } from "@tsonic/express/index.js";

export function main(): void {
  const app = express.create();

  app.get("/", async (_req, res, _next) => {
    res.send("hello");
  });

  app.listen(3000);
}

Basic API Surface

Handler model (important)

This package is Task-first (like ASP.NET): route handlers and middleware should be written as async functions (even if you don't await anything).

This avoids “async-void” behavior and keeps execution/exception semantics deterministic.

Also, handlers use the 3-argument signature: (req, res, next) (even for routes). If you don't need next, name it _next.

Create an app / router

import { express } from "@tsonic/express/index.js";

const app = express.create();
const router = express.Router();

router.get("/ping", async (_req, res, _next) => {
  res.send("pong");
});

app.use("/api", router);

Routing

Common verbs:

app.get("/health", async (_req, res, _next) => {
  res.send("ok");
});
app.post("/items", async (req, res, _next) => {
  res.json(req.body);
});
app.put("/items/:id", async (req, res, _next) => {
  res.send(req.params["id"] ?? "");
});
app.delete("/items/:id", async (_req, res, _next) => {
  res.sendStatus(204);
});
app.patch("/items/:id", async (_req, res, _next) => {
  res.sendStatus(204);
});
app.all("/anything", async (_req, res, _next) => {
  res.send("matched");
});

Middleware

app.use(async (req, _res, next) => {
  // Do something with req
  await next();
});

CORS

app.use(express.cors());

Cookies

app.get("/set-cookie", async (_req, res, _next) => {
  res.cookie("sid", "abc");
  res.send("ok");
});

app.get("/read-cookie", async (req, res, _next) => {
  res.json({ sid: req.cookies["sid"] });
});

Error middleware:

app.useError(async (err, _req, res, _next) => {
  res.status(500).json({ error: `${err}` });
});

Request / Response

Request highlights:

  • req.method, req.path, req.originalUrl
  • req.query, req.params, req.cookies, req.signedCookies
  • req.body (when using body parsers)
  • req.get(name) / req.header(name)

Response highlights:

  • res.status(code)
  • res.send(body), res.json(body), res.sendStatus(code)
  • res.redirect(path) / res.redirect(status, path)
  • res.set(name, value) / res.header(name, value)
  • res.cookie(name, value, options) / res.clearCookie(name, options)

Body parsing

app.use(express.json());
app.use(express.urlencoded());
app.use(express.text());
app.use(express.raw());

Multipart / file uploads

const upload = express.multipart();

app.post("/upload", upload.single("avatar"), async (req, res, _next) => {
  res.json({
    filename: req.file?.originalname,
    fields: req.body,
  });
});

Static files

app.use(express.static("./public"));

Listen / close

const server = app.listen(3000);
server.close();

Advanced docs

Versioning Model

This repo is versioned by runtime major:

License

MIT

About

The NativeAOT port of ExpressJS API

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published