use()
respond()
check()
wait()
join()
reject()
next()
timeout()
The Router
class allows you to create end-point observables:
1import { Router } from 'rxxpress';
2
3const router = new Router();
4router.get('/').pipe(...).subscribe(); // --> define a `GET` endpoint on '/'
5router.put('/').pipe(...).subscribe(); // --> define a `PUT` endpoint on '/'
6
7router.get('/stuff').pipe(...).subscribe(); // --> define a `GET` endpoint on '/stuff'
8router.post('/stuff').pipe(...).subscribe(); // --> define a `POST` endpoint on '/stuff'
9router.delete('/stuff').pipe(...).subscribe(); // --> define a `DELETE` endpoint on '/stuff'
10
11export default router;
You can then use router instances on Express apps and routers:
1import * as express from 'express';
2import router from './router';
3
4const app = express();
5app.use(router.core); // --> DO NOT FORGET THE .core
6app.listen();
Each route observable emits objects of type Packet
:
1export interface Packet {
2 req: Request, // --> the incoming request object, same as in Express
3 res: Response, // --> the outgoing response object, same as in Express
4 next: NextFunction // --> the next callback (basically indicating you don't want to handle this and want the next guy to take over).
5}
1router.get('/say-hi/:name').subscribe(
2 ({req, res, next}) => {
3 if (req.params.name === 'dude') res.send('Hellow Dude!');
4 else next();
5 }
6);
The req
, res
and next
properties are exactly the same (req, res, next) => ...
parameters
you would get with any Express request handler.
Similar to Express routers, you can invoke router.<METHOD>(<path>)
on Router
instances
to get an endpoint with the corresponding HTTP verb:
1router.get('/').pipe(respond(() => 'Hellow!')).subscribe();
2router.post('/stuff').subscribe(({req, res}) => ...);
RxXpress supports the same list of HTTP methods as Express.
Additionally, you can also use router.all(<path>)
to match all HTTP verbs on given path.
1router.all('/api/*').pipe( /* --> for all api endpoints */
2 authenticate(), /* --> authenticate */
3 groupBy(({req}) => req._.user.id), /* --> rate limit per user */
4 mergeMap(group => group.pipe(debounceTime(1000))), /* --> rate limit per user */
5 next() /* --> pass to the next handler */
6).subscribe();
Similar to Express routers, you can use .use()
method to mount middlewares and
sub-routers on a Router
instance. This is particularly useful in combination with
the use()
operator:
1import { Router, use, notfound } from 'rxxpress';
2import * as bodyParser from 'body-parser';
3
4import subRouter from './sub-router';
5
6const router = new Router();
7
8router.use('/users').pipe(
9 use(bodyParser), // --> use famouse body-parser middleware
10 use(subRouter), // --> can be an Express router or an RxXpress router
11 notfound() // --> well if no sub-router responded, then its 404
12).subscribe();
It is common practice in Express code to attach custom data to request object:
1function authenticate(req, res, next) {
2 // do stuff
3 req.user = user; // --> so all subsequent handlers will have access to request's user object.
4 next();
5}
This however does not sit well with TypeScript in general, and in case of RxXpress forces
you to either give up the type-inference by annotating req
as any
, or casting it to any
everytime you want to attach data or fetch attached data.
Since these solutions are neither elegant nor convenient, RxXpress router simply adds a _
key to req
on each packet it emits, which is a liniently typed object specifically for
attaching custom data:
1router.all('*').pipe(
2 tap(({req}) => {
3 // do stuff
4 req._.user = user; // --> attach user now without messing with type inference
5 })
6).subscribe();