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
Markdown
<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)
[](https://packagephobia.com/result?p=rjweb-server)
[](https://socket.dev/npm/package/rjweb-server)
</div>
<br>
<br>
<br>
```sh
npm i rjweb-server
yarn add rjweb-server
pnpm add rjweb-server
```
- 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
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)
})
```
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)
})
```
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}`)
})
)
)
```
Serve a Static Folder using CLI
```sh
rjweb serve [path to folder] [arguments]
rjweb serve ./static --port 4444 --hideHTML
```
Generate a Template using CLI
```sh
rjweb generate [path to destination folder]
rjweb generate ./chat-app
```
View Help
```sh
rjweb --help
```
- rjweb-server-ejs (To Render EJS templates easily)
- rjweb-server-ratelimit (To add rate limiting easily)
- Javascript: https://replit.com/@RobertJansen/aous
- Typescript: https://replit.com/@RobertJansen/aous-ts
👤 **0x4096**
Contributions, issues and feature requests are welcome!<br>
Feel free to check [issues page](https://github.com/0x7d8/NPM_WEB-SERVER/issues).
Give a Star if this project helped you!
Copyright © [0x7d8](https://github.com/0x7d8).<br>
This project is MIT licensed.