UNPKG

rjweb-server

Version:

Easy and Robust Way to create a Web Server with Many Easy-to-use Features in NodeJS

564 lines (468 loc) 14.7 kB
<div align="center"> [<img src="https://img.rjansen.de/rjweb/logo.png" style="padding-bottom:10px;" height="150">](https://www.npmjs.com/package/rjweb-server) [<img src="https://img.rjansen.de/rjweb/docs.svg" height="75px" style="margin-top:0px;">](https://docs.rjweb.rjansen.de) [<img src="https://img.rjansen.de/rjweb/types.svg" height="75px" style="margin-top:0px;margin-left:-15px;">](https://types.rjweb.rjansen.de) [<img src="https://img.rjansen.de/rjweb/changelog.svg" height="75px" style="margin-top:-25px;">](https://github.com/0x7d8/NPM_WEB-SERVER/blob/main/CHANGELOG.md) [![install size](https://packagephobia.com/badge?p=rjweb-server)](https://packagephobia.com/result?p=rjweb-server) [![Socket Badge](https://socket.dev/api/badge/npm/package/rjweb-server)](https://socket.dev/npm/package/rjweb-server) </div> <br> ### 🍔 [v7 to v8 Migration Guide](https://docs.rjweb.rjansen.de/rjweb-server/v8/migrating-from-v7) ### 🍔 [v6 to v7 Migration Guide](https://docs.rjweb.rjansen.de/rjweb-server/v7/migrating-from-v6) ### 🍔 [v5 to v6 Migration Guide](https://docs.rjweb.rjansen.de/rjweb-server/v6/migrating-from-v5) <br> <br> ## Install ```sh # NPM npm i rjweb-server # Yarn yarn add rjweb-server # pNPM pnpm add rjweb-server ``` ## Update Infos - 0.X | Deprecated - 1.X | Deprecated - 2.X | Deprecated - 3.X | Deprecated - 4.X | Deprecated - 5.X | Deprecated - 6.X | Deprecated - 7.X | Security Patches - 8.X | Patches & Features ## Typescript Custom Properties in HTTP Object (This also works in JavaScript, just remove the interface logic) ```ts import { Server, HTTPRequestContext, Status } from "rjweb-server" interface Custom { count: number } const server = new Server({ bind: '0.0.0.0', // The IP thats bound to port: 5000, // The Port which the Server runs on }) server.path('/', (path) => path .http<Custom, _, _>('GET', '/hello', (http) => http .onRequest(async(ctr) => { if (!ctr.queries.has("name")) return ctr.print('please supply the name queries!!') return ctr.print(`Hello, ${ctr.queries.get("name")}! You are Visit nr.${ctr['@'].count}`) }) ) .http<Custom, { name: string }, _>('POST', '/hello', (http) => http .onRequest(async(ctr) => { if (!('name' in ctr.body)) return ctr.print('please supply the name property!!') return ctr.print(`Hello, ${ctr.body.name}! You are Visit nr.${ctr['@'].count}`) }) ) ) let count = 0 server.on('httpRequest', async(ctr: HTTPRequestContext<Custom>) => { ctr.setCustom('count', ++count) console.log(`request made to ${ctr.url.path} by ${ctr.client.ip}`) }).on('httpError', async(ctr: HTTPRequestContext<Custom>, error) => { console.log(`error on path ${ctr.url.path}!!!`) console.error(error) ctr.status(Status.INTERNAL_SERVER_ERROR) ctr.print('server error') }) server.start() .then((port) => { console.log(`server started on port ${port}`) }) .catch((e) => { console.error('An Error occured while starting the Server!\n', e) }) ``` ## Usage Initialize Server ```js const { Server, Status, size } = require('rjweb-server') const server = new Server({ bind: '0.0.0.0', // The IP thats bound to cors: false, // If Cors Headers will be added port: 5000, // The Port which the Server runs on proxy: { enabled: true // If enabled, alternate IPs will be shown }, body: { enabled: true, // Whether to enable recieving POST Bodies maxSize: size(10).mb(), // Use Size helper to easily get byte count message: 'Payload too large' // Message that gets sent if the Limit is exceeded }, httpCompression: { enabled: true, // whether compressing of http bodies is enabled disabledAlgorithms: ['br', 'deflate'] // algorithms to ignore for compression, in this case will only allow gzip } }) // ctr.params.get... is :name:, example /hello/0x4096 server.path('/', (path) => path // The / is the Path Prefix for all children paths .http('POST', '/post', (http) => http .onRequest(async(ctr) => { return ctr.print(`Hello, ${ctr.body}! How are you doing?`) }) ) .http('GET', '/@{user}', (http) => http .onRequest(async(ctr) => { return ctr.printFile(`../images/profile/${ctr.params.get('user')}.png`, { addTypes: true }) }) ) .http('GET', '/reloadserver', (http) => http .onRequest(async(ctr) => { if (!ctr.queries.has('password')) return ctr.print('provide the password to do this!!') if (ctr.queries.get('password') !== 'imApassword123!') return ctr.print('the password is incorrect!!') setTimeout(() => ctr.controller.reload(), 1000) return ctr.print('server reloaded') }) ) .http('GET', '/redirect/{website}', (http) => http .onRequest(async(ctr) => { switch (ctr.params.get('website')) { case "google": return ctr.redirect('https://www.google.com') case "youtube": return ctr.redirect('https://www.youtube.com') default: return ctr.print('Im only smart enough to redirect to google and youtube :P') } }) ) .ws('/echo', (ws) => ws .onUpgrade((ctr, end) => { if (!ctr.queries.has('confirm')) return end(ctr.status(Status.BAD_REQUEST).print('Please dont forget the confirm query!')) }) .onMessage((ctr) => { ctr.print(ctr.message) }) ) .redirect('/googleplz', 'https://www.google.com') .path('/api', (path) => path .http('GET', '/', (http) => http .onRequest((ctr) => ctr.print('welcome to api!')) ) .path('/v1', (path) => path .http('GET', '/', (http) => http .onRequest((ctr) => ctr.print('welcome to v1 api!')) ) ) .path('/v2', (path) => path .http('GET', '/', (http) => http .onRequest((ctr) => ctr.print('welcome to v2 api!')) ) ) ) ) server.start() .then((port) => { console.log(`server started on port ${port}`) }) .catch((e) => { console.error('An Error occured while starting the Server!\n', e) }) ``` Print to multiple Websockets Periodically ```js const { Server } = require('rjweb-server') const { Readable } = require('stream') // This Stream will count up every second const dataStream = (() => { let i = 0 return new Readable({ objectMode: true, construct() { setInterval(() => { this.push(++i) }, 1000) }, }) }) () const server = new Server({ bind: '0.0.0.0', // The IP thats bound to cors: false, // If Cors Headers will be added port: 5000, // The Port which the Server runs on }) server.path('/', (path) => path .ws('/infos', (ws) => ws .onConnect((ctr) => { ctr.printStream(dataStream, { destroyAbort: false }) }) ) ) ``` Print Promises ```js const { Server } = require('rjweb-server') const wait = require('timers/promises').setTimeout const server = new Server({ bind: '0.0.0.0', // The IP thats bound to cors: false, // If Cors Headers will be added port: 5000, // The Port which the Server runs on }) // this request will load for 5 seconds and send the returned value const handleHello = async() => { await wait(5000) return 'You just waited 5 seconds !!' } server.path('/wait5sec', (path) => path // this request will load for 5 seconds .http('GET', '/func', (http) => http .onRequest((ctr) => { return ctr.print(handleHello) }) ) // this request will also load for 5 seconds .http('GET', '/promise', (http) => http .onRequest(async(ctr) => { await wait(5000) return ctr.print('You just waited 5 seconds !!') }) ) ) server.start() .then((port) => { console.log(`server started on port ${port}`) }) .catch((e) => { console.error('An Error occured while starting the Server!\n', e) }) ``` Authenticate Requests ```js const { Server, Status } = require('rjweb-server') const server = new Server({ bind: '0.0.0.0', // The IP thats bound to cors: false, // If Cors Headers will be added port: 5000, // The Port which the Server runs on }) server.path('/account', (path) => path .validate(async(ctr, end) => { // Will Validate every request starting with the route block prefix (/account) if (!ctr.queries.has('password')) return end(ctr.status(Status.UNPROCESSABLE_ENTITY).print('Passwort Query Missing')) if (ctr.queries.get('password') !== '123456 or database request or sum') return end(ctr.status(Status.UNAUTHORIZED).print('Unauthorized')) // else everything is OK, the request will only end if the end() function is called }) .http('GET', '/', (http) => http .onRequest(async(ctr) => { return ctr.print('Account Infos: idk') }) ) .http('POST', '/edit', (http) => http .onRequest(async(ctr) => { return ctr.print(`Edited Account Infos to ${ctr.rawBody}!`) }) ) ) ``` Use Middleware ```js const { Server } = require('rjweb-server') const someMiddleware = require('some-middleware') const someOtherMiddleware = require('some-other-middleware') const server = new Server({ bind: '0.0.0.0', // The IP thats bound to cors: false, // If Cors Headers will be added port: 5000, // The Port which the Server runs on }, [ someMiddleware.config({}), someOtherMiddleware.config({}) ]) server.start() .then((port) => { console.log(`server started on port ${port}`) }) .catch((e) => { console.error('An Error occured while starting the Server!\n', e) }) ``` Serve Static Files ```js const { Server } = require('rjweb-server') const server = new Server({ bind: '0.0.0.0', // The IP thats bound to cors: false, // If Cors Headers will be added port: 5000, // The Port which the Server runs on }) server.path('/', (path) => path .static('./html', { hideHTML: true // If enabled will remove the html ending from files when serving }) // The html folder is in the root directory, NOTE: Static files will be prioritized over the defined routes ) server.start() .then((port) => { console.log(`server started on port ${port}`) }) .catch((e) => { console.error('An Error occured while starting the Server!\n', e) }) ``` Add Headers on EVERY Request ```js const { Server } = require('rjweb-server') const server = new Server({ bind: '0.0.0.0', // The IP thats bound to cors: false, // If Cors Headers will be added port: 5000, // The Port which the Server runs on }) server.defaultHeaders((dH) => dH .add('im-a-header', 'im the value') ) server.start() .then((port) => { console.log(`server started on port ${port}`) }) .catch((e) => { console.error('An Error occured while starting the Server!\n', e) }) ``` Override Content-Types ```js const { Server } = require('rjweb-server') const server = new Server({ bind: '0.0.0.0', // The IP thats bound to cors: false, // If Cors Headers will be added port: 5000, // The Port which the Server runs on }) server.contentTypes((ct) => cT .add('.jsn', 'application/json') .add('.jn', 'application/json') ) server.start() .then((port) => { console.log(`server started on port ${port}`) }) .catch((e) => { console.error('An Error occured while starting the Server!\n', e) }) ``` Enable Dashboard ```js const { Server } = require('rjweb-server') const server = new Server({ bind: '0.0.0.0', cors: false, port: 5000, dashboard: { enabled: true, path: '/dashboard', // The Dashboad is now accessible at /dashboard password: '124' // The password to use, if not set will not ask to provide one } }) server.start() .then((port) => { console.log(`server started on port ${port}`) }) .catch((e) => { console.error('An Error occured while starting the Server!\n', e) }) ``` Custom Not Found / Server Error Page ```js const { Server, Status } = require('rjweb-server') const server = new Server({ bind: '0.0.0.0', cors: false, port: 5000, }) server.on('route404', async(ctr) => { ctr.status(Status.NOT_FOUND) return ctr.print(`page "${ctr.url.pathname}" not found`) }) server.on('httpError', async(ctr, error) => { ctr.status(Status.INTERNAL_SERVER_ERROR) ctr.print(`ERROR!!! ${error.stack}`) return console.log(ctr.error) }) server.start() .then((port) => { console.log(`server started on port ${port}`) }) .catch((e) => { console.error('An Error occured while starting the Server!\n', e) }) ``` Custom Function on every request ```js const { Server } = require('rjweb-server') const server = new Server({ bind: '0.0.0.0', cors: false, port: 5000, }) server.on('httpRequest', async(ctr, end) => { return console.log(`request made to ${ctr.url.href} by ${ctr.client.ip}`) // you can also end the request here like in validations }) server.start() .then((port) => { console.log(`server started on port ${port}`) }) .catch((e) => { console.error('An Error occured while starting the Server!\n', e) }) ``` ### Cleaning Up Functions Load routes from Directory ```js const { Server } = require('rjweb-server') const server = new Server({ bind: '0.0.0.0', cors: false, port: 5000, }) module.exports.server = server // Important! Needed to make route Files server.path('/', (path) => path .loadCJS('./functions') // This loads CJS files (module.exports) .loadESM('./functions') // This loads ESM files (export default) ) server.start() .then((port) => { console.log(`server started on port ${port}`) }) .catch((e) => { console.error('An Error occured while starting the Server!\n', e) }) ``` Making a route File ```js const { server } = require('../index.js') module.exports = new server.routeFile((file) => file .http('GET', '/say/{word}', (http) => http .onRequest((ctr) => { const word = ctr.params.get('word') ctr.print(`I will say it!!!!!!!!!\n${word}`) }) ) ) ``` ### CLI Serve a Static Folder using CLI ```sh rjweb serve [path to folder] [arguments] # Example rjweb serve ./static --port 4444 --hideHTML ``` Generate a Template using CLI ```sh rjweb generate [path to destination folder] # Example rjweb generate ./chat-app ``` View Help ```sh rjweb --help ``` ## Official Middlewares - rjweb-server-ejs (To Render EJS templates easily) - rjweb-server-ratelimit (To add rate limiting easily) ## Full Example - Javascript: https://replit.com/@RobertJansen/aous - Typescript: https://replit.com/@RobertJansen/aous-ts ## Author 👤 **0x4096** ## 🤝 Contributing Contributions, issues and feature requests are welcome!<br> Feel free to check [issues page](https://github.com/0x7d8/NPM_WEB-SERVER/issues). ## Show your support Give a Star if this project helped you! ## 📝 License Copyright © [0x7d8](https://github.com/0x7d8).<br> This project is MIT licensed.