Note

This documentation reflects the beta version of NodePlace. The current alpha version is a pre-release, aimed at gathering feedback from the community to shape the final product and address key developer pain points.

Typescript support is only available in es modules. however, that does not mean that the code will break in commonjs modules, only that you will have to turn of noImplicitAny in tsConfig and also other fields that may cause the ts compiler to complain.

This alpha version is not intended for serious projects but to try out and explore. Please report any issues or bugs you encounter on our Discord server. Your feedback is invaluable. Thank you in advance for helping make NodePlace better!

API Documentation

nodeplace()

The nodeplace() function initializes and returns a new NodePlace application instance.

import nodeplace from 'nodeplace'

const app = nodeplace()

Description

  • Purpose: Initializes the core application instance for defining routes, mounting middleware, and configuring the framework.
  • Return Value: Returns an application object with methods for handling requests, managing middleware, and starting the server.

Methods

nodeplace.json([options])

nodeplace.json is a built-in middleware function that parses incoming requests with JSON payloads. It populates the req.body property with the parsed data.

Features

  • Content-Type Matching: Only processes requests where the Content-Type header matches application/json.
  • Unicode Support: Accepts any Unicode encoding of the body.
  • Error Handling: Automatically handles malformed JSON or empty bodies.
app.use(nodeplace.json(options))

Options

OptionDescriptionTypeDefault
limitMaximum size of the incoming JSON payload.String or Number100kb
strictEnsures only objects and arrays are parsed (if set to true).Booleantrue
reviverA function passed to JSON.parse to transform the parsed JSON.Functionundefined

Behavior

  • Successful Parsing: Populates req.body with the parsed JSON object.
  • Invalid JSON: Responds with:
    • Status: 400
    • Content-Type: Application/Json
    • Body:{"message": "Unexpected token <input> is not valid JSON" }
  • Empty Body: Responds with:
    • Status: 400
    • Content-Type: Application/Json
    • Body:{ "message": "Failed to process empty body" }
  • Internal Errors: Responds with:
    • Status: 500
    • Content-Type: Application/Json
    • Body:{ "message": some server error }

Example

import nodeplace from 'nodeplace'

const app = nodeplace()

// Middleware to parse JSON payloads
app.use(nodeplace.json())

app.post('/data', (req, res) => {
    console.log(req.body)
    res.json({ message: 'Data received', data: req.body })
})

app.listen(3000, () => {
    console.log('Server running on http://localhost:3000')
})

As req.body’s shape is based on user-controlled input, all properties and values in this object are untrusted and should be validated before trusting. For example, req.body.foo.toString() may fail in multiple ways, for example foo may not be there or may not be a string, and toString may not be a function and instead a string or other user-input.

nodeplace.static(root, [options])

nodeplace.static is a built-in middleware function for serving static files. It maps incoming requests to file paths within a specified root directory.

For best results, use a reverse proxy cache to improve performance of serving static assets.

Features

  • File Serving:Serves static files such as HTML, png, and pdf.
  • Cache Control:Supports options like maxAge and immutable for optimized client-side caching.
  • Extension Fallbacks:Automatically serves files with specified extensions if the requested file is not found.
  • Custom Headers:Allows setting custom HTTP headers for responses.
app.use(nodeplace.static(root, options))

Arguments

  • root: (Optional) The directory from which to serve static assets. Defaults to 'public'.
  • options: (Optional) An object specifying configuration options for serving static files.

Options (Optional)

OptionDescriptionTypeDefault
dotfiles Determines how dotfiles (files starting with .) are treated ('allow' or 'ignore').Stringignore
etagEnables or disables ETag generation for caching.Booleantrue
extensionsFile extensions to try when the requested file is not found.Array<String>[]
maxAgeSets the max-age directive in the Cache-Control header (in milliseconds).Number0
lastModifiedSets the Last-Modified header to the file’s modification time.Booleantrue
immutableAdds the immutable directive to Cache-Control for long-lived caching. Requires maxAge.Booleanfalse
setHeadersA custom function for setting headers on the response.Function(res, path, stat)undefined

Behavior

  • If a file is found:
    • Responds with the file contents.
    • Automatically sets headers like Content-Type, ETag, and Last-Modified if enabled.
  • If a file is not found:
    • If extensions are specified, attempts to resolve the file by appending each extension in the list.
    • If still not found, invokes next() to pass control to the next middleware.

Example with Options

import nodeplace from 'nodeplace'

const options = {
    dotfiles: 'ignore',
    etag: true,
    extensions: ['html', 'htm'],
    maxAge: 86400000, // 1 day in milliseconds
    immutable: true,
    setHeaders: (res, path, stat) => {
        res.setHeader('X-Custom-Header', 'NodePlace-Static')
    }
}

const app = nodeplace()

app.use(nodeplace.static('assets', options))

app.listen(3000, () => {
    console.log('Static file server running on http://localhost:3000')
})
Dotfiles by default are ignored for security purposes, Use 'allow' to serve them. Combine maxAge and immutable for efficient client-side caching of static assets. Use setHeaders to add headers like X-Timestamp for debugging or tracking.

nodeplace.urlencoded([options])

nodeplace.urlencoded is a built-in middleware function for parsing incoming requests with URL-encoded payloads. It is commonly used to parse form submissions.

Features

  • Form Data Parsing:application/x-www-form-urlencoded payloads into a JavaScript object.
  • Customizable Parsing:Supports configuration options to adjust how payloads are handled.
  • Unicode Support:Fully compatible with Unicode-encoded bodies.
app.use(nodeplace.urlencoded(options))

Arguments (Optional)

OptionDescriptionTypeDefault
parameterLimitLimits the number of parameters parsed to prevent potential denial-of-service attacks.Number1000
limitMaximum size of the incoming JSON payload.String or Number100kb

Behavior

  • Parses the request body and populates req.body with a key-value object.
  • If the Content-Type does not match application/x-www-form-urlencoded, the middleware skips parsing.
  • Validates the structure of the payload to ensure compatibility with the specified options.

Example

Basic Form Parsing

import nodeplace from 'nodeplace'

const app = nodeplace()

app.use(nodeplace.urlencoded({}))

app.post('/submit', (req, res) => {
    console.log(req.body)
    res.send('Form submitted!')
})

app.listen(3000, () => {
    console.log('Server running on http://localhost:3000')
})

As req.body’s shape is based on user-controlled input, all properties and values in this object are untrusted and should be validated before trusting. For example, req.body.foo.toString() may fail in multiple ways, for example foo may not be there or may not be a string, and toString may not be a function and instead a string or other user-input.

Application()

The app object in NodePlace serves as the foundation of your application. It is created by calling the nodeplace() function and provides methods for defining routes, managing middleware, and controlling how your app handles HTTP requests.

Creating an Application

import nodeplace from 'nodeplace'

const app = nodeplace()

This initializes a new NodePlace application.

The app object comes with several methods and properties for managing application behavior, including route handling, middleware mounting, and configuration.

Methods

MethodDescription
app.listen(port[, callback])Starts the server, binding it to the specified port.
app.use([path], callback)Mounts middleware functions at the specified path (default is /).
app.get(path, callback)Handles HTTP GET requests to the specified path.
app.post(path, callback)Handles HTTP POST requests to the specified path.
app.put(path, callback)Handles HTTP PUT requests to the specified path.
app.delete(path, callback)Handles HTTP DELETE requests to the specified path.

Examples

Starting a Server

import nodeplace from 'nodeplace'

const app = nodeplace()

app.listen(3000, () => {
    console.log('Server is running on http://localhost:3000')
})

Adding Routes

app.get('/', (req, res) => {
    res.send('Hello, world!')
})

app.post('/submit', (req, res) => {
    res.send('Form submitted!')
})

Mounting Middleware

app.use((req, res, next) => {
    console.log('Time:', Date.now())
    next()
})

Methods

app.all(path, callback [, callback ...])

The app.all() method routes all HTTP methods to the specified path. This is useful for applying middleware or handling requests regardless of the HTTP method.

app.all(path, callback [, callback ...])

Parameters

  • path:The path to match for the route.
  • callback:One or more callback functions that handle the request. These follow the standard (req, res, next) signature.

Example: Logging All HTTP Methods

app.all('/logs', (req, res) => {
    console.log(`${req.method} request to ${req.path}`)

    res.send('This route handles all HTTP methods')
})

In this example:

  • A single route /logs is defined to handle any HTTP method (GET, POST, PUT, DELETE, etc.).
  • The server logs the method used for each request.

Example: Middleware Application

app.all('/secure/*', (req, res, next) => {
    if (!req.isAuthenticated) {
        res.status(401).send('Unauthorized')
    } else {
        next()
    }
})

In this example:

  • Middleware ensures that all requests to paths under /secure/ are authenticated.
  • If the user is authenticated, the next handler is called.

app.delete(path, callback [, callback ...])

The app.delete() method routes HTTP DELETE requests to the specified path and handles them with the provided callback(s). It is commonly used to remove resources on the server.

app.delete(path, callback [, callback ...])

Parameters

  • path:The route path where the handler should apply.
  • callback:The route path where the handler should apply.

Example: Deleting a Resource

app.delete('/users/:id', (req, res) => {
    const userId = req.params.id
    // Logic to delete user by ID
    res.send(`User with ID ${userId} deleted`)
})

In this example:

  • The route /users/:id accepts DELETE requests.
  • The req.params.id retrieves the user ID from the URL, and a confirmation response is sent.

Example: Middleware with DELETE

app.delete('/resources/:id', authenticate, (req, res) => {
    const resourceId = req.params.id
    // Logic to delete the resource
    res.status(200).json({ message: `Resource ${resourceId} removed` })
})

In this example:

  • Middleware authenticate ensures only authorized users can delete resources.
  • A JSON response confirms the deletion.

app.disable(setting)

The app.disable method disables a specific setting.

Parameters:

  • setting (String): The name of the setting to disable.

Example:

app.disable('poweredBy')

This disables the poweredBy header.

app.enable(setting)

The app.enable method explicitly enables a specific setting.

Parameters:

  • setting (String): The name of the setting to enable.

Example:

app.enable('poweredBy');

This enables the poweredBy header.

app.get(path, callback [, callback ...])

The app.get() method routes HTTP GET requests to the specified path and handles them with the provided callback(s). This method is typically used to retrieve and display data or serve static pages.

Syntax

app.get(path, callback [, callback ...])

Parameters

  • path:The route path where the handler should apply.
  • callback:One or more callback functions to handle the request, with the standard (req, res, next) signature.

Example: Basic GET Handler

app.get('/', (req, res) => {
    res.send('Welcome to the Homepage')
})

In this example:

  • The route / accepts GET requests.
  • A simple text response is sent to the client.

Example: Dynamic Routes

app.get('/users/:id', (req, res) => {
    const userId = req.params.id
    res.send(`User ID: ${userId}`)
})

In this example:

  • The route /users/:id dynamically handles GET requests for user IDs.
  • The req.params.id retrieves the dynamic portion of the URL.

Example: Middleware with GET

app.get('/dashboard', authenticate, (req, res) => {
    res.send('Welcome to your dashboard')
})

In this example:

  • Middleware authenticate ensures only logged-in users can access the dashboard.

Example: JSON Response

app.get('/api/products', (req, res) => {
    res.json([
        { id: 1, name: 'Laptop', price: 1200 },
        { id: 2, name: 'Phone', price: 800 }
    ])
})

In this example:

  • The route /api/products serves a JSON array of products.
  • Use this for API endpoints.

app.listen(path, [callback])

The app.listen() method binds and listens for connections on the specified port or path. It is typically the final step in starting your NodePlace application, making it ready to handle incoming requests.

Syntax

app.listen([port[, host[, backlog]]][, callback])
app.listen(path, [callback])

Parameters

  • Port(optional): The port number for the server to listen on.
  • host(optional): The hostname or IP address to bind the server to. Defaults to "0.0.0.0".
  • backlog(optional): The maximum number of pending connections the server will allow.
  • path(optional): A Unix domain socket path or Windows named pipe for server connections.
  • callback(optional): A function that executes once the server starts successfully.

If port is omitted or is 0, the operating system will assign an arbitrary unused port, which is useful for cases like automated tasks (tests, etc.).

import nodeplace from 'nodeplace' 

const app = nodeplace() 

app.listen(3000)

Example: Listening on a Port

app.listen(3000, () => {
    console.log('Server is running at http://localhost:3000')
})

In this example:

  • The server listens on port 3000.
  • A success message is logged to the console.

Example: Listening on a Unix Socket

app.listen('/tmp/app.sock', () => {
    console.log('Server is listening on /tmp/app.sock')
})

In this example:

  • The server listens on a Unix domain socket at /tmp/app.sock.
  • Suitable for inter-process communication on Unix-like systems.

Example: Dynamic Port Assignment

app.listen('/tmp/app.sock', () => {
    console.log('Server is listening on /tmp/app.sock')
})

In this example:

  • The operating system assigns an unused port dynamically.
  • Use this for scenarios like test automation.

Using HTTPS and HTTP Together

import http from 'http'
import https from 'https'

const app = nodeplace()

http.createServer(app).listen(80, () => {
    console.log('HTTP server running on port 80')
})

https.createServer({ key: privateKey, cert: certificate }, app).listen(443, () => {
    console.log('HTTPS server running on port 443')
})

In this example:

  • The same app handles both HTTP and HTTPS requests using Node.js' http and https modules.
  • Use this for scenarios like test automation.

app.patch(path, callback [, callback ...])

The app.patch() method routes HTTP PATCH requests to the specified path and handles them with the provided callback(s). This method is typically used for partially updating resources.

Syntax

app.patch(path, callback [, callback ...])

Parameters

  • path:The route path where the handler should apply.
  • callback:One or more callback functions to handle the request, with the standard (req, res, next) signature.

Example: Basic PATCH Handler

app.patch('/user', (req, res) => {
    res.send('User updated')
})

In this example:

  • The route /user accepts PATCH requests.
  • A simple confirmation message is sent to the client.

Example: Dynamic Routes

app.patch('/users/:id', (req, res) => {
    const userId = req.params.id
    res.send(`User with ID ${userId} has been updated`)
})

In this example:

  • The route /users/:id dynamically handles PATCH requests for specific user IDs.
  • req.params.id retrieves the dynamic portion of the URL to identify the user.

Example: Middleware with PATCH

app.patch('/settings', verifyToken, (req, res) => {
    res.send('Settings have been updated')
})

In this example:

  • Middleware verifyToken ensures that only authorized users can access the /settings route.
  • The response confirms the successful update of settings.

Example: JSON Payload

app.patch('/api/products/:id', (req, res) => {
    const { id } = req.params
    const { name, price } = req.body

    res.json({ id, updated: { name, price } })
})

In this example:

  • The route /api/products/:id accepts PATCH requests with a JSON payload.
  • The response includes the updated product details.

Example: Chained Middleware

app.patch(
    '/profile',
    validateProfileUpdate,
    saveChanges,
    (req, res) => {
        res.send('Profile updated successfully')
    }
)

In this example:

  • Multiple middleware functions are chained together:
    • validateProfileUpdate ensures incoming data is valid.
    • saveChanges persists updates to the database.
  • The final callback sends a success message to the client.

app.put(path, callback [, callback ...])

The app.put() method routes HTTP PUT requests to the specified path and handles them with the provided callback(s). This method is generally used to update or replace existing resources on the server.

Syntax

app.put(path, callback [, callback ...])

Parameters

  • path:The route path where the handler should apply.
  • callback:One or more callback functions to handle the request, with the standard (req, res, next) signature.

Example: Basic PUT Handler

app.put('/profile', (req, res) => {
    res.send('Profile updated successfully')
})

In this example:

  • The route /profile accepts PUT requests.
  • A success message is sent to the client.

Example: Updating Resource Data

app.put('/users/:id', (req, res) => {
    const userId = req.params.id
    const updatedData = req.body
    res.json({ message: `User ${userId} updated`, updatedData })
})

In this example:

  • The route /users/:id dynamically handles PUT requests for specific users.
  • req.params.id retrieves the user ID from the URL.
  • req.body contains the updated user data sent in the request payload.

Example: Middleware with PUT

app.put('/settings', authenticate, (req, res) => {
    res.send('Settings updated successfully')
})

In this example:

  • Middleware authenticate ensures only authorized users can update settings.
  • The final callback confirms the update.

Example: Handling Partial Updates with PUT

app.put('/orders/:orderId', (req, res) => {
    const orderId = req.params.orderId
    const changes = req.body
    res.json({ message: `Order ${orderId} updated`, changes })
})

In this example:

  • The route /orders/:orderId accepts PUT requests for modifying order details.
  • The server responds with the applied changes.

Example: Chained Middleware for Validation

app.put(
    '/posts/:id',
    validatePostData,
    updatePostInDatabase,
    (req, res) => {
        res.send('Post updated successfully')
    }
)

In this example:

  • Middleware functions validatePostData and updatePostInDatabase are chained together:
    • validatePostData ensures the submitted data is valid.
    • updatePostInDatabase applies the updates in the database.
  • The final callback sends a success response to the client.

app.settings(options)

The app.settings method allows you to configure application-level settings, enabling or disabling specific features.

Parameters:

  • options (Object): An object containing key-value pairs for settings.

Example:

app.settings({poweredBy: false })

In this example, the poweredBy header is disabled.

app.use([path,] callback [, callback ...])

The app.use() method mounts middleware, error handlers, or routers onto your NodePlace application. It is a versatile method that allows you to enhance your application’s functionality by adding reusable components to the request-response cycle.

Syntax

app.use([path,] callback [, callback ...])

Parameters

  • path(optional): The base path at which the middleware or router is mounted. Defaults to /, applying the middleware globally.
  • callback:One or more middleware functions, error handlers, or routers to process requests.

Example: Global Middleware

app.use((req, res, next) => {
    console.log(`${req.method} ${req.url}`)

    next()
})

In this example:

  • A middleware logs each incoming request’s method and URL.
  • It applies globally to all routes.

Example: Path-Specific Middleware

app.use('/admin', authenticate)

In this example:

  • The authenticate middleware is applied to all routes under /admin.
  • Only authenticated users can access these routes.

Example: Mounting a Router

const userRouter = nodeplace.Router()

userRouter.get('/', (req, res) => {
    res.send('User Home')
})

userRouter.get('/:id', (req, res) => {
    res.send(`User ID: {req.params.id}`)
})

app.use('/users', userRouter)

In this example:

  • A userRouter handles requests to /users and its subpaths.
  • The routes /users/ and /users/:id are defined within the router.

Example: Serving Static Files

app.use(nodeplace.static('public'))

In this example:

  • The static middleware serves files from the public directory.
  • Requests for files like /images/logo.png are automatically handled.

Example: Middleware Chain

app.use(
    '/dashboard',
    authenticate,
    logActivity,
    (req, res) => {
        res.send('Welcome to the Dashboard')
    }
)

In this example:

  • Multiple middleware functions (authenticate and logActivity) process requests to /dashboard.
  • The final callback sends a success response.

Example: Error Handling

app.use((err, req, res, next) => {
    console.error(err.stack)
    res.status(500).send('Something went wrong!')
})

In this example:

  • An error-handling middleware catches unhandled errors in the application.
  • It sends a 500 status code along with an error message.

Request

The req object in NodePlace represents the HTTP request made by a client. It provides details about the request, such as headers, body, query parameters, and URL. This object is an enhanced version of Node.js' native request object, with additional properties and methods provided by NodePlace.

Additional Properties

req.body

Contains data submitted in the request body. Typically populated by body-parsing middleware, such as nodeplace.json() or nodeplace.urlencoded().

As req.body’s shape is based on user-controlled input, all properties and values in this object are untrusted and should be validated before trusting. For example, req.body.foo.toString() may fail in multiple ways, for example foo may not be there or may not be a string, and toString may not be a function and instead a string or other user-input.

Example: Accessing req.body

app.post('/profile', (req, res) => {
    res.send(`Name: ${req.body.name}`)
})

In this example:

  • Data sent in the body (e.g., {"name": "John"}) is accessible via req.body.

req.params

An object containing properties mapped to route parameters. For example, if the route defines /users/:id, the id parameter is available as req.params.id.

As req.params’s shape is based on user-controlled input, all properties and values in this object are untrusted and should be validated before trusting. For example, req.params.foo.toString() may fail in multiple ways, for example foo may not be there or may not be a string, and toString may not be a function and instead a string or other user-input.

Example: Accessing Route Parameters

app.get('/users/:id', (req, res) => {
    res.send(`User ID: ${req.params.id}`)
})

In this example:

  • A request to /users/123 will respond with User ID: 123.

req.query

An object containing the query string parameters from the URL.

As req.query’s shape is based on user-controlled input, all properties and values in this object are untrusted and should be validated before trusting. For example, req.query.foo.toString() may fail in multiple ways, for example foo may not be there or may not be a string, and toString may not be a function and instead a string or other user-input.

Example: Accessing Query Parameters

app.get('/search', (req, res) => {
    res.send(`Search term: ${req.query.q}`)
})

In this example:

  • A request to /search?q=NodePlace will respond with Search term: NodePlace.

req.res

This property holds a reference to the response object. The response is the extended version of the NodePlace response, which means it also have the extended properties and methods

Response

The res object in NodePlace represents the HTTP response that your application sends to a client. It provides methods for sending data, setting headers, and controlling the HTTP status of the response. This object extends Node.js' native response object with additional methods and properties provided by NodePlace.

Additional Methods

res.cookie(name, value [, options])

Sets a cookie in the response.

Example: Setting a Cookie

app.get('/set-cookie', (req, res) => {
    res.cookie('username', 'john_doe', { httpOnly: true, maxAge: 3600000 })
    res.send('Cookie set')
})

Options

OptionDescriptionTypeDefault
domainSpecifies the domain for the cookie.stringnull
expiresSets the cookie’s expiration date in GMT format.Datenull
encodeA synchronous function used for cookie value encoding.FunctionencodeURIComponent
httpOnlyMarks the cookie as accessible only via HTTP(S), not JavaScript.booleanfalse
maxAgeSpecifies the time in milliseconds until the cookie expires.numbernull
pathSpecifies the path for the cookie.string/
secureMarks the cookie to be sent only over HTTPS.booleanfalse
sameSiteControls whether the cookie is sent with cross-site requests (Strict, Lax, or None).stringnull
signed Indicates if the cookie should be signed.booleanfalse

res.clearCookie(name [, options])

Clears the cookie specified by name. For the cookie to be cleared properly, the options provided to res.clearCookie must match those used when setting the cookie with res.cookie(), excluding expires and maxAge.

Example: Clearing a Cookie

app.get('/clear-cookie', (req, res) => {
    res.cookie('username', 'john_doe', { path: '/user', httpOnly: true })
    res.clearCookie('username', { path: '/user', httpOnly: true })
    res.send('Cookie cleared')
})

Parameters

  • name:(string, required) The name of the cookie to clear.
  • options (optional):(optional) An object specifying attributes of the cookie to match when clearing it. See res.cookie() for the available options.

Behavior:

If options like path, domain, or secure were specified when the cookie was set using res.cookie(), they must be included in res.clearCookie() to match the original cookie. For example:

res.cookie('key', 'value', { path: '/api' })
res.clearCookie('key', { path: '/api' }) // Matches and clears the cookie.
Options like httpOnly and sameSite will also be preserved when clearing the cookie if they were used during the original res.cookie() call. The options parameter is optional but strongly recommended to ensure the cookie is properly matched and cleared.

res.json([body])

Sends a JSON response. This method sets the Content-Type header to application/json automatically.

Example: Sending JSON

app.get('/users', (req, res) => {
    res.json([{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }])
})

res.redirect([status,] path)

Redirects the client to a specified path or URL. Optionally accepts an HTTP status code (default is 302).

Example: Redirecting to a URL

app.get('/old-page', (req, res) => {
    res.redirect('/new-page')
})

Example: Redirecting with a Custom Status Code

app.get('/moved-permanently', (req, res) => {
    res.redirect(301, '/new-page')
})

res.send([body])

Sends a response to the client. The body parameter can be a string, buffer, array, or object.

Example: Sending Text Response

app.get('/welcome', (req, res) => {
    res.send('Welcome to NodePlace!')
})

Example: Sending JSON Response

app.get('/api/data', (req, res) => {
    res.send({ id: 1, name: 'NodePlace' })
})

res.sendFile(path [, options] [, callback])

Transfers the file at the given path to the client. Sets the Content-Type response HTTP header field based on the file’s extension. If the root option is set, the path argument can be a relative path; otherwise, it must be an absolute path.

The method supports caching, range requests, and additional headers to fine-tune the response. Use it to serve static files or dynamically generated paths.

Example: Serving a Static File

app.get('/download', (req, res) => {
    res.sendFile('/absolute/path/to/file.zip', {
        cacheControl: true,
        maxAge: 3600, // 1 hour
    })
})

Example: Serving with Options

app.get('/file/:name', (req, res, next) => {
    const options = {
        root: path.join(__dirname, 'public'),
        dotfiles: 'deny',
        maxAge: '1d',
        cacheControl: true,
        immutable: true,
        headers: {
            'x-timestamp': Date.now(),
            'x-sent': true,
        },
    }

    const fileName = req.params.name
    res.sendFile(fileName, options, (err) => {
        if (err) {
            next(err) // Pass control to error handling middleware
        } else {
            console.log('File sent:', fileName)
        }
    })
})

Options

OptionDescriptionTypeDefault
maxAgeSpecifies the Cache-Control max-age in milliseconds.number0
rootThe root directory for resolving the relative file path.stringnull
headersAllows you to set additional HTTP headers. This can be useful for security or metadata requirements.Objectnull
dotfilesDetermines how dotfiles (hidden files starting with .) are handled. Can be one of "allow", "deny", or "ignore".string"ignore"
acceptRangesEnables or disables support for range requests.Booleantrue
cacheControlEnables or disables the Cache-Control header in the response. When enabled, use maxAge to specify the cache duration.Booleantrue
immutableAdds the immutable directive to the Cache-Control header. This is useful for static files that will never change. If enabled, maxAge should also be set to allow caching.Booleanfalse
lastModifiedAutomatically sets the Last-Modified header based on the file’s last modified timestamp on the file system. Setting this to false disables the header.Booleantrue
dispositionControls the Content-Disposition header for the file. Can be "inline" (display in-browser) or "attachment" (download file). If unspecified, it defaults to "inline" for most files and "attachment" for certain MIME types like archives.String"inline" / "attachment" based on file type

res.set(field [, value])

Sets the HTTP header field to a specific value.

Example: Setting a Header

app.get('/custom-header', (req, res) => {
    res.set('X-Custom-Header', 'NodePlace')
    res.send('Header set')
})

res.status(code)

Sets the HTTP status code for the response. Returns the res object for chaining.

Example: Setting Status Code

app.get('/not-found', (req, res) => {
    res.status(404).send('Page not found')
})

res.type(type)

Sets the Content-Type HTTP header to the specified MIME type.

Example: Setting Content Type

app.get('/text', (req, res) => {
    res.type('text/plain')
    res.send('This is plain text')
})

Example: Setting JSON Type

app.get('/json', (req, res) => {
    res.type('application/json')
    res.send({ message: 'This is JSON' })
})

Router

The Router object in NodePlace is an instance of middleware and routing functionality. It acts as a "mini-application" that can have its own middleware, routes, and error-handling logic. Routers are particularly useful for modularizing your application by separating concerns and grouping related routes.

Syntax

const router = nodeplace.Router()

Features of Router

  • Modular and mountable, allowing for clean separation of application logic.
  • Can handle its own middleware, routes, and error handlers.

Creating a Router

Example: Basic Router Setup

const router = nodeplace.Router()

router.get('/', (req, res) => {
    res.send('Welcome to the Router!')
})

app.use('/router', router)

Features of Router

  • A router is created using nodeplace.Router().
  • The router handles requests to /router and responds to /router/ with a welcome message.

Handling Routes with Router

Dynamic Routes

You can define dynamic routes with parameters directly in the router.

router.get('/user/:id', (req, res) => {
    res.send(`User ID: ${req.params.id}`)
})

Explanation:

  • The router handles requests to /user/:id, where :id is a dynamic parameter.
  • Use req.params.id to access the dynamic value.

Using Middleware in Routers

Routers can have middleware specific to their routes.

router.use((req, res, next) => {
    console.log('Router-specific middleware')
    next()
})

router.get('/dashboard', (req, res) => {
    res.send('Router-specific Dashboard')
})

Explanation:

  • Middleware added to the router applies only to routes defined within that router.

Combining Middleware and Routes

router.get(
    '/example',
    (req, res, next) => {
        console.log('Middleware before response')
        next()
    },
    (req, res) => {
        res.send('Hello from Example!')
    }
)

Explanation:

  • Middleware added to the router applies only to routes defined within that router.

Mounting Routers

Routers can be mounted on specific paths in the main application.

Example: Mounting a Router

const adminRouter = nodeplace.Router()

adminRouter.get('/settings', (req, res) => {
    res.send('Admin Settings')
})

app.use('/admin', adminRouter)

Explanation:

  • The adminRouter handles routes prefixed with /admin.
  • Requests to /admin/settings are served by the router.

Router-Level Middleware

Middleware specific to a router can be added using router.use().

Example: Router Middleware

const loggingMiddleware = (req, res, next) => {
    console.log(`Request Method: ${req.method}, Path: ${req.path}`)

    next()
}

router.use(loggingMiddleware)

router.get('/profile', (req, res) => {
    res.send('Profile Page')
})

Explanation:

  • The middleware logs each request method and path before the route handler is executed.

Method: router.route(path)

Defines multiple HTTP method handlers for a single route.

Example: Handling Multiple Methods

router.route('/items')
    .get((req, res) => {
        res.send('List of Items')
    })
    .post((req, res) => {
        res.send('Create a New Item')
    })
    .put((req, res) => {
        res.send('Update an Item')
    })
    .delete((req, res) => {
        res.send('Delete an Item')
    })

Explanation:

  • Use router.route() to define GET, POST, PUT, and DELETE handlers for /items.

Nested Routers

NodePlace allows routers to be nested infinitely, providing a powerful way to organize complex applications into manageable modules. Nested routers inherit middleware and routing logic from their parent routers, enabling seamless composition of application features.

Example: Basic Nested Router Setup

const nodeplace = require('nodeplace')
const app = nodeplace()

// Main Router
const mainRouter = nodeplace.Router()

// Sub Router
const subRouter = nodeplace.Router()

subRouter.get('/info', (req, res) => {
    res.send('This is nested inside the main router!')
})

// Mount Sub Router onto Main Router
mainRouter.use('/sub', subRouter)

// Mount Main Router onto the App
app.use('/main', mainRouter)

Explanation:

  • The subRouter is mounted on the /sub path of mainRouter
  • The mainRouter is mounted on the /main path of the app.
  • A request to /main/sub/info will pass through both the mainRouter and subRouter.

Example: Middleware in Nested Routers

// Define middleware for subRouter
subRouter.use((req, res, next) => {
    console.log('SubRouter Middleware Triggered')
    next()
})

subRouter.get('/data', (req, res) => {
    res.json({ message: 'Nested router data' })
})

// Main Router Middleware
mainRouter.use((req, res, next) => {
    console.log('MainRouter Middleware Triggered')
    next()
})

// Mount the Sub Router onto Main Router
mainRouter.use('/sub', subRouter)

Explanation:

  • Middleware defined in mainRouter is executed before any middleware or routes in subRouter.
  • Nested routers allow middleware at different levels of the hierarchy to work together.

Example: Deeply Nested Routers

// Level 3 Router
const level3Router = nodeplace.Router()

level3Router.get('/deep', (req, res) => {
    res.send('Deeply nested route')
})

// Level 2 Router
const level2Router = nodeplace.Router()
level2Router.use('/level3', level3Router)

// Level 1 Router
const level1Router = nodeplace.Router()
level1Router.use('/level2', level2Router)

// Mount Level 1 Router onto the App
app.use('/level1', level1Router)

Explanation:

  • The level3Router is nested within level2Router, which is nested within level1Router.
  • A request to /level1/level2/level3/deep passes through all routers in the hierarchy.

Key Benefits of Nested Routers

  • Modularization: Split application logic into smaller, reusable units.
  • Hierarchy: Build complex applications with clear routing hierarchies.
  • Isolation: Each router can have its own middleware and error-handling logic, ensuring clean separation of concerns.