Reflet is a suite of modules made of well-typed decorators.
Reflet is simple and flexible. It will help you organize your app, without the pitfall of verbosity.
But most importantly, Reflet is french for reflection (pronounce ruh flay π).
Organize your Express application.
Documentation.
@Use(isAuthenticated)
@Router('/things')
class ThingRouter {
@Get('/:id')
async get(@Params('id') id: string, @Res res: Response) {
const thing = await db.collection('things').find({ id })
res.status(200).send(thing)
}
@Send({ status: 201 })
@UseGuards((req) => canCreateThing(req.user))
@Post()
async create(@Body('item') item: string) {
const newThing = await db.collection('things').insertOne({ item })
return newThing
Add-on: Reflet/express-middlewares
Declare your Mongoose models in a more concise way.
Documentation.
@Model()
@SchemaOptions({ autoIndex: false })
class User extends Model.I {
static findByEmail(email) {
return this.findOne({ email });
}
@Field({ type: String, required: true })
email: string
@Field(String)
name: string
}
const user = new User({ email: '[email protected]', name: 'Jeremy' })
await user.save()
Typed HTTP primitives to use within any framework.
Documentation.
@Router('/things')
class ThingRouter {
@UseStatus(Status.Created)
@Post()
async create(@Headers(RequestHeader.Authorization) auth: string) {
if (!auth) {
throw HttpError.Unauthorized('Stop right there')
}
}
}
Why another decorator framework ? Simply (and biasedly) put, a better developer experience.
Reflet modules aim to stay close to the technology's underlying abstractions they decorate,
so you don't have to learn a whole new terminology to be productive. ποΈβ
e.g. Reflet/express has decorators like Use
for app.use
method, Router
for express.Router
, Send
for res.send
.
If you're familiar with Express, you're gonna love its Reflet decorators.
As such, Reflet modules don't try to be agnostic or compatible with multiple technologies at once (e.g. decorators for both Express, Koa, Fastify), because that would mean :
- more detached, less familiar abstractions. π€
- less accurate static typing (conditional types to aknowledge differences). π€₯
- hence, more error prone code (from my part and yours). π
Instead, Reflet hopes to provide a well-defined and well-typed module for each libraries.
Reflet takes full advantage of TypeScript by narrowing its type signatures, to prevent as much mistakes as possible. π―
e.g. Headers
decorator narrows its input to a union of request headers instead of just string
, UseStatus
decorator narrows its input to a union of status codes instead of just number
.
Every exposed API is fully documented, with examples and even links to the original library documentation, so you're never alone in the dark of your editor theme. βοΈ
Most decorator frameworks are great for the simple stuff, but inevitably get in your way later down the road. π
Reflet does its best to avoid this by staying simple and to the point, composable, and by eating its own dog food: common decorators are built with lower-level tools, that are also provided to you. π
e.g. exposed Express parameter decorators are created by the same createParamDecorator
method that is provided to you.
This design allows for easy extension and plugins. π§©
In this regard, Reflet generally provides a core module with all the basic decorators to do everything, and add-ons for extra convenient features.
e.g. Reflet/express-middlewares provides middleware decorators to handle authorization (UseGuards
), response mapping (UseInterceptor
), to complete the features of Reflet/express.
NPM ecosystem got a bad rep by encouraging intricate third-party dependencies for the sake of DRY principle.
Time has come for a smarter dependency diet. π³
Reflet modules fully own their codebase. No direct third-party dependencies, only peer ones.
e.g. Reflet/express only asks for the necessary peer dependencies: express
, @types/express
, @reflet/http
.
Reflet uses extensive integration testing, to make sure its decorators work with the underlying library.
e.g. Reflet/express is tested with HTTP requests, Reflet/mongoose is tested with mongoose queries and an in-memory mongo.
Careful abstractions &&
clear-cut modules &&
commented/documented code &&
small number of files/folders ===
reduced indirection and complexity. π§΅
Have a look and compare with similar frameworks. π§Ά