1.1.2 • Published 6 years ago
ts-echo v1.1.2
An easy http restful framework written by Typescript
Package includes both compiled javascript
and typescript
declaration(.d.ts) files
Developers can continue coding in both typescript
and javascript
Features:
- Basic routes
- Group routes
- Middleware
- Custom exception handler
- Log supports
- NOT support optional route path like
/path/[maybe]
(The author doesn't want to do that. (╯‵□′)╯ ┻━┻)
Installation:
npm install --save ts-echo
Usage:
Basic routes:
import { Server, Router, Context } from "ts-echo";
// create router
const router = new Router();
// define routes
router.GET("/hello", async (ctx: Context) => {
ctx.response.string("Hi there.");
return; // with or without `return` are both working
});
// run server
Server.loadRouter(router);
Server.run(3000, "127.0.0.1");
Access parameters:
// create router
const router = new Router();
// define routes
router.PATCH("/user/{user_id}", async (ctx: Context) => {
const routeParams = ctx.params; // access route parameters
const requestBody = await ctx.request.body(); // access request body
const queryParams = ctx.request.query(); // access query string parameters
const headers = ctx.request.header(); // access request headers
// send response in application/json
ctx.response.json({
routeParams,
requestBody,
queryParams,
headers,
});
return;
});
Response:
// create router
const router = new Router();
// define routes
router.GET("/string", async (ctx: Context) => {
ctx.response.string("response in string"); // which will set `Content-Type: text/html` in response header
return;
});
router.GET("/json", async (ctx: Context) => {
ctx.response.json({ // which will set `Content-Type: application/json` in response header
success: true,
message: "json",
});
return;
});
router.GET("/json/but/string", async (ctx: Context) => {
ctx.response.json({
success: true,
message: "json",
});
// modify response header
ctx.response.setHeader("Content-Type", "text/html"); // which will set `Content-Type` back to `text/html`
return;
});
Group routes:
// create router
const router = new Router();
// define routes
router.group("/v1", (r: Router) => {
r.GET("/hello", async (ctx: Context) => {
// should visit /v1/hello now.
ctx.response.string("Hi there.");
return;
});
});
Middleware:
class GroupMiddleware extends Middleware { // import { Middleware } from "ts-echo"
public async before(ctx: Context) {
console.log("before group");
// return ctx.response.string("stop now.");
// In before() method, if a `Response` instance returns, it will directly send response and end the request
}
public async after(ctx: Context) {
console.log("after group");
}
}
class SingleMiddleware extends Middleware {
public async before(ctx: Context) {
console.log("before single");
}
public async after(ctx: Context) {
console.log("after single");
}
}
// create router
const router = new Router();
// define routes with middleware
router.group("/v1", (r: Router) => {
r.GET("/hello", async (ctx: Context) => {
ctx.response.string("Hi there.");
return;
}, [new SingleMiddleware()]);
}, [new GroupMiddleware()]);
// the order of middleware execution should be:
// before group -> before single -> after single -> after group
Server.loadRouter(router);
// ...
Log:
// enable log print
Server.printLogs(true);
// then you can use the default logger which will print logs to console
// or set your logger which must be a winston.Logger
const logger = new winston.Logger({ // import * as winston from "winston"
level: "debug",
transports: [
new winston.transports.Console({
label: "APP_NAME",
align: false,
colorize: true,
timestamp: true,
})
],
});
Server.setLogger(logger); // set logger before you load router
// load router as always
Server.loadRouter(router);
// run server and execute the callback function
Server.run(3000, "127.0.0.1", () => {
logger.info("Let's roll!");
});
Exception handler:
class Exception extends Error {
public statusCode: number = 400;
public message: string = "";
protected __proto__: Error; // in order to be caught correctly
constructor(statusCode: number = 200, message: string = "") {
super(message);
this.__proto__ = new.target.prototype; // in order to be caught correctly
this.message = message;
this.statusCode = statusCode;
}
}
// set custom exception handler to catch and handle errors
router.setExceptionHandler((err: Error, ctx: Context) => {
const resp = ctx.response;
if (err instanceof Exception) {
resp.json({
message: err.message,
}, err.statusCode);
} else if (err instanceof Error) {
resp.json({
code: "SERVER ERROR",
message: err.message,
stack: err.stack,
}, 500);
}
});
router.GET("/not-found", async (ctx) => {
throw new Exception(404, "missing");
});
// then load router
Server.loadRouter(router);
// ...
All together in javascript
:
const Server = require("ts-echo").Server;
const Router = require("ts-echo").Router;
const HttpException = require("ts-echo").HttpException;
const Middleware = require("ts-echo").Middleware;
// create a router
const router = new Router();
// add routes
router.group("/v1", router => {
router.group("/users", router => {
router.GET("/", async (ctx) => {
// basic response
ctx.response.string("user list here");
return;
});
router.GET("/{user_id}", async (ctx) => {
// access route params
ctx.response.string("user detail for " + ctx.params.user_id);
return;
});
router.GET("/{user_id}/papers/{paper_id}", async (ctx) => {
ctx.response.string("paper: " + ctx.params.paper_id + " from user: " + ctx.params.user_id);
return;
});
});
router.GET("/hello", async (ctx) => {
// response with custom status-code and headers
ctx.response.string("hi there.", 200, { hello: "world" });
return;
});
});
// set custom exception handler to catch and handle errors
router.setExceptionHandler((err, ctx) => {
const resp = ctx.response;
if (err instanceof HttpException) {
resp.json({
message: err.message,
}, err.statusCode);
} else if (err instanceof Error) {
resp.json({
type: "SERVER ERROR",
message: err.message,
stack: err.stack,
}, 500);
}
});
router.GET("/not-found", async (ctx) => {
throw new HttpException(404, "missing");
});
// access request body, query params and route params
router.PATCH("/article/{id}", async (ctx) => {
ctx.response.json({
request_body: await ctx.request.body(),
query: ctx.request.query(),
router_param: ctx.params,
});
return;
})
// with middlewares
class ExampleMiddleware extends Middleware {
async before() {
console.log("before example");
}
async after() {
console.log("after example");
}
}
class AnotherMiddleware extends Middleware {
async before() {
console.log("before another");
}
async after() {
console.log("after another");
}
}
const em = new ExampleMiddleware();
const am = new AnotherMiddleware();
router.group("/middleware", router => {
router.GET("another", async (ctx) => {
ctx.response.json({ success: true, message: "test middleware" });
return;
}, [am]);
}, [em]);
// start the server, load routes and run
// enable log prints
Server.printLogs(true);
// set custom logger
// logger must be a winston.LoggerInstance
const winston = require("winston");
const logger = new winston.Logger({
level: "debug",
transports: [
new winston.transports.Console({
label: "APP_NAME",
align: true,
colorize: true,
timestamp: true,
})
],
});
Server.setLogger(logger);
Server.loadRouter(router);
Server.run(3000, "127.0.0.1", () => {
logger.info("let's roll!");
});
1.1.2
6 years ago
1.1.1
6 years ago
1.1.0
6 years ago
1.0.1
6 years ago
0.1.0
6 years ago
0.0.19
6 years ago
0.0.18
6 years ago
0.0.17
6 years ago
0.0.16
6 years ago
0.0.15
6 years ago
0.0.14
6 years ago
0.0.13
6 years ago
0.0.12
6 years ago
0.0.11
6 years ago
0.0.10
6 years ago
0.0.9
6 years ago
0.0.7
6 years ago
0.0.6
6 years ago
0.0.5
6 years ago
0.0.4
6 years ago
0.0.3
6 years ago
0.0.2
6 years ago
0.0.1
6 years ago
0.0.0
6 years ago
1.0.0
6 years ago