We proudly released a few days ago Expressive Tea 1.2.0. It contains new parameter decorators, dynamic responses, renders view integration, and https settings.
From this version, HTTPS configuration is getting through Server Settings Decoration at the boot stage. With this, we create https servers as straightforward and easy to configure. Starting at current version Server Settings decorator allow three new properties:
@ServerSettings({
port: 8080,
privateKey: './certs/key.pem',
certificate: './certs/cert.pem'
securePort: 4443
})
class Bootstrap extends Boot {
}
Expressive Tea controllers follow the ExpressJS convention to set a response into the controllers using the “Response” instance from Express. However, We include a dynamic response mechanism in this release that allows developers to use a better choice to keep it clean and straightforward.
All controller’s decorated methods with any of the HTTP response types (ex. Get, Post, Put) instead of using the standard response callback now you can return any value and will be managed by the framework auto-response and also if not content-type provided is auto-select the response content-type.
@Get('/test')
// Automatically Response with a html response.
async index(req: Request, res: Response ): Promise<unknown> {
return `<h1> Data Test ${test}</h1>`;
}
@Get('/test-html')
// Return a html to show object as string representation.
async indexHtml(req: Request, res: Response ): Promise<unknown> {
res.type('html');
return {test};
}
@Get('/no-annotation')
// We still support standard response.
async withoutAnnotation(req: Request, res: Response) {
res.send('Hello World');
}
@Post('/test')
// This it will return a application/json response
postResponse(req: Request, res: Response) {
return { test: 'testing response' };
}
If a Template engine is setting up and you generated layout and views to response rendering view. This is fantastic news!!. Expressive Tea now supports a new decorator to create responses with rendering a view template.
Importantly. This Decorator simplifies how to implement the old 1.1 version that requires decorating a method and using the “render” response. Among the dynamic response, this is an exception and must return an object to use as local variables in the rendered view.
Dynamic Response Exception
View Decorator is only accept return objects since should be used as local variables in the render view template.
// @View(renderViewName: string, path: string)
@View('user', '/view')
async user(@query('username') username: string): Promise<{username: unknown}> {
return {username};
}
An essential aspect of Expressive Tea is creating a straightforward framework. Importantly, for us, the implementation of the parameter’s decorators was critical in this release.
Therefore, this allows developers to inject directly into the controller’s methods, only data that you need. For instance, this can increase clean code and, more importantly, keep developers focused on developing business requirements without worrying about architecture.
Besides, before this release, We follow the ExpressJS convention to create decorated response methods. During our implementations on internal projects, We conclude to introduce new parameter decorators.
However, We will keep using the standard convention from ExpressJS to keep portability and compatibility. After that, please review the next parameter’s decorators:
But also, combined with Dynamic Response might reduce the explicit use of these parameters and keep it on the map for configuration purposes or a specialized response.
In this case we can pass from this:
import {Get, Route} from '@zerooneit/expressive-tea/decorators/router';
import {Request, Response} from 'express';
@Route('/')
export default class RootController {
@Get('/test')
async index(req: Request, res: Response): Promise<void> {
res.json({message: 'this is good!!'});
}
@Post('/search')
async index(req: Request, res: Response): Promise<void> {
const { q:query } = req.query;
const { username, queryType } = req.body;
// ... all business
return { query, username, queryType };
}
}
to this:
import {Get, Route} from '@zerooneit/expressive-tea/decorators/router';
import { next, response, request } from '@zerooneit/expressive-tea/decorators/annotations';
import {Request, Response} from 'express';
@Route('/')
export default class RootController {
@Get('/test')
async index(@response res: Response): Promise<void> {
res.json({message: 'this is good!!'});
}
@Get('/test-simple')
async index(): Promise<void> {
return { message: 'this is good!!'};
}
@Get('/test-error')
async index(@next next): Promise<void> {
next(new Error('just because');
}
@Post('/search')
async index(@request req: Request): Promise<void> {
const { q:query } = req.query;
const { username, queryType } = req.body;
// ... all business code
return { query, username, queryType };
}
}
Another most used feature is getting the URL query parameters and body request object (if you configurated a body parser into your server). This version brings with a query and body parameter’s decorators that allows injecting directly into the method decorated argument the whole, partial or single query or body parameters from the request object.
With these new features, We ensure agile and faster server-side applications by giving you a straightforward method to get all the data that you need directly as an argument in your methods.
import {Get, Route, Post, View, Param } from '@zerooneit/expressive-tea/decorators/router';
import { query, body } from '@zerooneit/expressive-tea/decorators/annotations';
import { Request, Response } from 'express';
@Route('/')
export default class RootController {
@Get('/test')
// for /test?test=something
async index(@query('test') test: unknown): Promise<unknown> {
return `<h1> Data Test ${test}</h1>`;
// <h1> Data Test something </h1>
}
@Get('/test-json')
// for /test-json?test=something
async indexHtml(@query('test') test: unknown): Promise<unknown> {
return {test};
/*
application/json response:
{ test: 'something' }
*/
}
@Post('/test')
/*
body request:
{ a: 'a', b: 'test', test: 'abcdef'}
*/
async bodyTest(
@body('test') test: any,
@body(['a', 'b']) body: any,
@body() all: any
) {
return { test, body, all };
/*
application/json response:
{ test: 'abcdef', body: {a: 'a', b:'test'}, all: { a: 'a', b: 'test', test: 'abcdef'} }
*/
}
}
Finally, We also introduce in this version the URL parameter’s decorator. It follows the same process as the body and query decorator. The only exception in this decorator is not allowing to get multiple parameters since each URL parameter is a single value.
Also, there is another important rule that is applying for this. The injected value will be affected for every “@Param” decorator included in the controller or globally.
import {Get, Route, Post, View, Param } from '@zerooneit/expressive-tea/decorators/router';
import { query, body, param, next, response, request } from '@zerooneit/expressive-tea/decorators/annotations';
import { Request, Response } from 'express';
import { NextFunction } from 'express';
@Route('/')
export default class RootController {
@Param('userId')
async parameterUserId(@request req: Request, @next next: NextFunction): Promise<void> {
req.params.userId = 'Decorated one';
next();
}
@Get('/with-params/:userId')
async withParams(@param('userId') userId: unknown ): Promise<unknown> {
return `<h1> Data Test ${userId}</h1>`;
// It will show <h1> Data Test Decorated one</h1>
}
}
expresive-tea (this link opens in a new window) by Zero-OneiT (this link opens in a new window)
A Express and Typescript REST Service Template.
2 Subscribers 23 Watchers 8 Forks Check out this repository on GitHub.com (this link opens in a new window)
Lead Developer for Expressive Tea - Javascript Fullstack Developer - Open Source Advocate - Amateur Data Science - Python Enthusiastic
Diego Resendez