Simple zero-dependency file server with routing. Includes dynamic page support for single page applications.
Add a .npmrc file to your project, with the following lines:
@zooduck:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=YOUR_ACCESS_TOKEN
Install from the command line:
npm install @zooduck/simple-server@latestInstall via package.json:
"@zooduck/simple-server": "latest"Clone or Download the repository to your machine.
import { SimpleServer } from 'path/to/@zooduck/simple-server/dist/index.module.js'const server = new SimpleServer()
server.start()const server = new SimpleServer({
port: 1234,
protocol: 'https',
staticPath: 'public'
})
server.start()const server = new SimpleServer()
server.addRoute('book', (request) => {
if (request.method === 'GET') {
const { searchParams } = new URL(request.url, 'http://example.com')
const book = getBook(searchParams.get('book_id'))
// Always return JSON...
return JSON.stringify(book)
}
// ...or null (for bad requests)
return null
})
server.start()Call the endpoint:
// Routes always start with 'api/'
const bookResponse = await fetch('api/book')
const bookResult = await bookResponse.json()You can also use files for routes.
The file must reside in a root level "api" folder (or subdirectory) and export a default function.
The function can be asynchronous or synchronous.
// public/api/v2/book.js
export default async (request) => {
// ...
return JSON.stringify(book)
}Call the endpoint:
const bookResponse = await fetch('api/v2/book')
const bookResult = await bookResponse.json()If you need to share globals between file routes, use the defineGlobals() method.
Globals are passed as the second argument to your exported function.
// server.js
const server = new SimpleServer()
let numberOfCallsToBookEndpoint = 0
// ...
server.defineGlobals({ numberOfCallsToBookEndpoint: numberOfCallsToBookEndpoint })
// public/api/book.js
export default (request, globals) => {
globals.numberOfCallsToBookEndpoint += 1
// ...
return JSON.stringify({ book: book, totalRequests: globals.numberOfCallsToBookEndpoint })
}const response = await fetch('api/book', {
method: 'POST',
body: 'This is a bad request'
})
const result = await response.json()
console.log(result)
// { error: '400 Bad Request' }Note: This example assumes that yourbook route returns null for POST requests.
This server supports dynamic pages by default. Any url not prefixed with api/ and not pointing to a file will return the index.html file from the static path.
Your routing service can then deliver the approriate content based on the url.
The following table illustrates how non-api urls are handled when the router is configured with the staticPath option set to "public".
| url | file |
|---|---|
| / | public/index.html |
| /pages/cities/tokyo | public/index.html |
| /pages/cities/tokyo/info.pdf | public/pages/cities/tokyo/info.pdf |
| /pages/cities/tokyo/index.html | public/pages/cities/tokyo/index.html |
| /pages/cities/tokyo/missing_file.pdf | public/404.html |
| /scripts/example/index.js | public/scripts/example/index.js |
Note: You can disable this behaviour if you wish, by setting the dynamicPages option to false when creating the server:
const server = new SimpleServer({ dynamicPages: false })