Socket
Socket
Sign inDemoInstall

repulser

Package Overview
Dependencies
0
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    repulser

Routing library for javascript


Version published
Weekly downloads
56
increased by21.74%
Maintainers
1
Install size
44.6 kB
Created
Weekly downloads
 

Readme

Source

Repulser

Repulser providers various types of routing strategies.

Note: This package supports both esm and commonjs.

Installation

npm install repulser

Usage

Simple usage

const { createServer } = require('http');
const fs = require('fs');
const stream = require('stream');
const { Router } = require('../cjs');

function isReadableStream(obj) {
  return obj instanceof stream.Stream &&
    typeof (obj._read === 'function') &&
    typeof (obj._readableState === 'object');
}

const router = new Router();

router.get('/', async (ctx) => {
  ctx.reply('Welcome to my API', 200, 'text/html');
});

router.get('/users', async (ctx) => {
  ctx.reply({
    users: [],
  });
});

router.get('/users/:id', async (ctx) => {
  ctx.reply({
    user: {
      id: ctx.params.id,
    },
  });
});

router.post('/users', async (ctx) => {
  // create user
  ctx.reply({
    user: {},
    message: 'User created successfully',
  });
});

router.put('/users/:id', async (ctx) => {
  // update user
  ctx.reply({
    user: {
      id: ctx.params.id,
    },
    message: 'User updated successfully',
  });
});


router.delete('/users/:id', async (ctx) => {
  // delete user
  ctx.reply({
    user: {
      id: ctx.params.id,
    },
    message: 'User deleted successfully',
  });
});

router.get('/users/:id/profile-picture', async (ctx) => {
  // delete user
  ctx.reply(fs.createReadStream('path/to/image'));
});

router.any('/users/any/profile', async (ctx) => {
  switch (ctx.method) {
    case 'GET':
      ctx.reply({ message: 'Get user profile route!' })
      break
    case 'POST':
      ctx.reply({ message: 'Create user profile route!' })
      break
    case 'PUT':
      ctx.reply({ message: 'Update user profile route!' })
      break
    case 'DELETE':
      ctx.reply({ message: 'Delete user profile route!' })
      break
    default:
      ctx.reply({ message: 'Method not supported!' })
      break
  }
});

router.all(['GET', 'PUT', 'DELETE'], '/users/all/address', async (ctx) => {
  switch (ctx.method) {
    case 'GET':
      ctx.reply({ message: 'Get user address route!' })
      break
    case 'PUT':
      ctx.reply({ message: 'Add/Update user address route!' })
      break
    case 'DELETE':
      ctx.reply({ message: 'Delete user address route!' })
      break
  }
});

createServer(async (req, res) => {
  const ctx = {
    method: req.method,
    req,
    res,
    reply: (body, status = 200, type = 'application/json') => {
      ctx.response = { body, status, type };
    },
  };

  [ctx.url, ctx.query] = req.url.split('?');

  ctx.query = new URLSearchParams(ctx.query);

  ctx.params = {};

  const route = router.find(req.method, ctx.url, ctx.params);

  if (!route) {
    res.statusCode = 404;
    res.end(JSON.stringify({
      error: 'Page not found',
    }));
    return;
  }

  await route.handler(ctx);

  if (!ctx.response) {
    res.statusCode = 204;
    res.end();

    return;
  }

  res.statusCode = ctx.response.status || 200;

  if (ctx.method == 'HEAD') {
    res.statusCode = 204;
    res.end();

    return;
  }

  // handle json response
  if (ctx.response.type === 'application/json') {
    res.setHeader('content-type', 'application/json');
    res.end(JSON.stringify(ctx.response.body));
    return;
  }

  if (isReadableStream(ctx.response.body)) {
    res.setHeader('content-type', ctx.response.type || 'application/octet-stream');
    ctx.response.pipe(res);
    return;
  }

  res.setHeader('content-type', ctx.response.type || 'text/plain');
  res.end(ctx.response.body);

}).listen(3000, () => {
  console.info('Server listening on :3000');
})

Advance usage

// USER ROUTER STARTS
const usersRouter = new Router({
  prefix: '/users'
});

usersRouter.get('/', async (ctx) => {
  ctx.reply({
    users: [],
  });
});

usersRouter.get('/:id', async (ctx) => {
  ctx.reply({
    user: {
      id: ctx.params.id,
    },
  });
});

usersRouter.post('/', async (ctx) => {
  // create user
  ctx.reply({
    user: {},
    message: 'User created successfully',
  });
});

usersRouter.put('/:id', async (ctx) => {
  // update user
  ctx.reply({
    user: {
      id: ctx.params.id,
    },
    message: 'User updated successfully',
  });
});


usersRouter.delete('/:id', async (ctx) => {
  // delete user
  ctx.reply({
    user: {
      id: ctx.params.id,
    },
    message: 'User deleted successfully',
  });
});

// USER ROUTER ENDS

// USER PROFILE ROUTER STARTS
const userProfileRouter = new Router({
  prefix: '/:id/profile',
});

userProfileRouter.get('/', async (ctx) => {
  // get user profile
  ctx.reply({
    profile: {
      id: ctx.params.id,
    },
  });
});

userProfileRouter.put('/', async (ctx) => {
  // update user profile
  ctx.reply({
    profile: {
      id: ctx.params.id,
    },
  });
});


userProfileRouter.get('/picture', async (ctx) => {
  // delete user
  ctx.reply(fs.createReadStream('path/to/image'));
});

// USER PROFILE ROUTER ENDS

// ATTACH USER PROFILE ROUTER WITH USER ROUTER
usersRouter.use(userProfileRouter);

// CATEGORY ROUTER STARTS
const categoriesRouter = new Router({
  prefix: '/categories',
});

categoriesRouter.get('/', (ctx) => {
  ctx.reply({
    categories: [],
  });
});

categoriesRouter.post('/', (ctx) => {
  ctx.reply({
    category: {},
    message: 'Category created successfully',
  });
});
// CATEGORY ROUTER ENDS

// PRODUCT ROUTER STARTS
const productsRouter = new Router({
  prefix: '/products',
  // merge instead of appending/prefixing path
  merge: true,
});

productsRouter.get('/', (ctx) => {
  ctx.reply({
    products: [],
  });
});

productsRouter.post('/', (ctx) => {
  ctx.reply({
    product: {},
    message: 'Product created successfully',
  });
});
// PRODUCT ROUTER ENDS

// merge products router with category router
categoriesRouter.use(productsRouter);

// MAIN ROUTER STARTS
const router = new Router();

router.get('/', async (ctx) => {
  ctx.reply('Welcome to my API', 200, 'text/html');
});
// CATEGORY ROUTER ENDS

// attach user router
router.use(usersRouter);
// attach category router under prefix /catalogues, do category route will be /catalogues/categories
router.use('/catalogues', categoriesRouter);

// use main router 

router.find(method, path);

With koajs

app.use(async (ctx, next) => {
  ctx.params = {}
  const route = router.find(ctx.method.toUpperCase(), ctx.url, ctx.params);

  if (!route) {
    throw new Error('Page not found.');
  }

  await route.handler(ctx);

  await next();
});

With expressjs

app.use((req, res, next) => {
  req.params = {}
  const route = router.find(req.method.toUpperCase(), req.url, req.params);

  if (!route) {
    return next(new Error('Page not found.'));
  }

  await route.handler(req, res, next);
});

Extra Features

  • router level middlewares
const router = new Router({
  /*
  note: route.handler will be converted to array
        you can modify the behaviour using
  addMiddleware(route: Route, middleware: CallableFunction)
  */
});

router.use((ctx, next) => {
  // will add this middlewares to every route 
  // note: route.handler will be converted to an Array (no change, if already an Array)
})
  • route handler modifier
import compose from 'koa-compose';

const router = new Router({
  composeHandler(route: Route) {
    route.handler = compose(route.handler)
  },  
});

Keywords

FAQs

Last updated on 16 Sep 2022

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc