0.2.1 • Published 5 months ago

@starscream/core v0.2.1

Weekly downloads
-
License
MIT
Repository
-
Last release
5 months ago

Starscream - Batteries Included Fastify

Starscream is an small, opinionated framework ontop of Fastify, almost like a distribution. It includes a bunch of plugins, sets up sensible defaults, and wires things together so you can work in a convention over configuration style. It aims to be the most productive tool for building API driven web services, including all the other little bits that don't happen to exactly be APIs.

Status

Still pretty Gadget specific. Mostly used as a place to pull out code that feels general into a shared spot. Not really a framework yet, but handy for demarcating between Gadget API specific stuff and Good Web Server specific stuff.

Features

  • TypeScript everywhere
  • Centralized, multi-environment, user extensible configuration
  • File based Fastify plugin registration with scoping contexts
  • pnpm workspace based development workflow
  • Good testing support via transactional fixtures and integration testing sessions (with fastify.inject)

Included Plugins

  • @fastify/secure-sessions for sessions
  • @fastify/view for view rendering
  • @fastify/websocket for websockets
  • typeorm for database connectivity
  • etc, see boot.ts

File Based Routes with Scope

Starscream uses a filesystem based router similar to next.js where each HTTP route is a separate file on disk, and the file's path governs the HTTP path pattern that runs the code in the file. For example, you might have this folder structure:

src/
  routes/
    GET-home.ts
    GET-posts.ts
    POST-posts.ts
    posts/
      GET-[id].ts

This would register routes for GET /home, GET /posts, POST /posts, and GET /posts/:id with Fastify. Starscream uses this convention so that it's always easy to find the file that powers a given route in a project, and also so that routes can be lazily required, improving boot and reboot performance in development. A route file is a file which exports an async route handler function like this:

import { StarscreamRoute } from "@starscream/core";

const route: StarscreamRoute = async (request, reply) => {
  await reply.send({ pong: request.ip });
};

export default route;

If you want to add route options to a route like route hooks, route schema, or route constraints, you can do that by setting the options property on the route object like so:

import { StarscreamRoute } from "@starscream/core";

const route: StarscreamRoute = async (request, reply) => {
  // some useful stuff
};

route.options = {
  preValidation: someAuthHook,
  constraints: { host: "one-specific-domain.com" },
  // and all the other fastify route options here: https://www.fastify.dev/docs/latest/Reference/Routes/#routes-option
};

export default route;

File Based Fastify Plugins

Fastify has a plugin encapsulation feature where registered hooks, decorators, or other required plugins apply only to the other stuff registered within that plugin and not outside it. This is really useful for isolation and composition -- if you want to run a hook for user authentication for example, you can add it in an outer plugin, and all routes added to that plugin or inner plugins will run the hook.

To make encapsulation easy and predictable, Starscream maps each folder of routes on the filesystem to a new plugin encapsulation context. So, hooks added to one folder of routes apply to all the routes within that folder, but not to routes in other folders.

Plugin files must start with a + character. This shows Starscream you mean for it to be a plugin file and not a route. Files that aren't routes and aren't plugins aren't allowed in the src/routes directory -- they can go anywhere else in src and be imported by routes or plugins just fine.

For example, if you had this folder structure:

src/
  routes/
    GET-home.ts
    GET-posts.ts
    +scope.ts
    posts/
      GET-[id].ts
      +scope.ts

Hooks or decorators defined in src/routes/scope.ts will apply to all routes, and then hooks or decorators defined in src/routes/posts/+scope.ts will only apply to routes src/routes/posts.

Plugins are one source file that exports an async function which is passed the server instance the plugin should work with. They look like this:

import { StarscreamPlugin } from "@starscream/core";

const scope: StarscreamPlugin = async (server) => {
  server.decorateRequest("myCoolRequest", true);
};

export default scope;

Plugin files can do anything normal Fastify plugins can, and are eager loaded during development to ensure any setup they do is applied before routes start getting run. Plugins are the right place to register other plugins.

Config

Starscream exports a Config object which has both starscream's configuration and your app's configuration on it. Set config in starscream.config.ts which will be auto required from the root of the api project. If you have a starscream.config.local.ts it will also be auto required and merged into the final Config object.

Handy config doodads:

  • Config.env has an EnvironmentName object that has a name: string as well as testLike() or productionLike() interrogators
  • Config.app has your app's configuration

Starscream also replaces TypeORM's config management facilities with it's own, so configure TypeORM with Config.database. To use secrets in production for the config, reference them in the starscream.config.ts file like you might any other environment variable with process.env['SOME_SECRET_VAR'].

Utilities

inlineOperation

Useful for booting up the application but not actually starting the server in order to do useful stuff, like seed the database or run a migration.