Essential Server is just your everyday Node.js server written in TypeScript, based on the Express.js web framework — designed to get new projects off the ground as quickly as possible.
See below on how to get started ASAP.
✅ Schema-validated environment variables (using zod)
✅ Deeply-engrained semantic versioning (Semantic Version 2.0.0)
- Captures and validates
version
stipulated inpackage.json
to avoid discrepancies
✅ Advanced parsing of URL-encoded query strings for richer query data (using qs)
✅ JSON requests (request.body
) and responses
✅ Thorough schema validation of requests (using zod)
- Route parameters: schema sensibly constrained to
Record<string, string>
- Query parameters: schema sensibly constrained to qs-compatible output
- Body: schema sensibly constrained to JSON-serialisable object
✅ Automatic, configurable request logging (using morgan)
✅ Basic error handling, out of the boxes
- Throws
500 Internal Server Error
on exception. - If an Error object is caught, displays
error.message
in body of the error response.
✅ Appends "best practice" security headers (using helmet)
✅ Implements Cross-Origin Resource Sharing (CORS) controls (using helmet and cors)
✅ Rate limiting, out of the box (using express-rate-limit)
- IP based.
- Currently uses internal memory store.
✅ Caching, out of the box
- Useful
cacheHandler
middleware to enable appropriate response caching on individual routes or across router(s)- Control own caching behaviour (through middleware options)
- Control caching behaviour of external caches (through middleware options pertaining to
Cache-Control
headers)
- Currently uses internal memory store (node-cache).
- Node.js v22+
-
Using a terminal, run the command below to clone Essential Server into a new project directory:
npx degit TejBirringTM/EssentialServer <your_project_name>
-
Navigate to the local clone:
cd <your_project_name>
-
Navigate to the Essential Server GitHub repository.
-
Click 'Use this template' followed by ;Create a new repository'.
-
Follow the instructions provided by GitHub to clone Essential Server into a new repository for your project.
-
Using a terminal, clone the newly-created project repository to your local machine.
-
Navigate to the local clone:
cd <your_project_name>
From the terminal, install project dependencies: npm install
-
Ensure all tests pass.
From the terminal, run:
npm test
If any test fails, please submit a report here.
-
Run the server and test its endpoints.
From the terminal, run:
npm run start
You can test the server by sending HTTP requests to the endpoints implemented in
src/routes/*.ts
files from a HTTP client like Insomnia or Postman.Once you're done, exit the server by pressing
Ctrl + C
while in the terminal.
Congratulations!
Now, it's time for you to implement your own server!
See here for more information about this.
While you are developing, you will find this command helpful to start the server; it will restart the server every time a source file is modified: npm run dev
Before proceeding, it would be a good idea to understand the folder structure of Essential Server:
src/
├─ config/
| code that parses environment variables and
| exports a configuration object to the rest
| of the codebase.
|
├─ middlewares/
| top-level files export Express.js middleware(s)
| (i.e. route handler functions) for use by the
| server application, a router, or individual
| routes.
|
├─ routes/
| top-level files default export a Router
| object describing routes to serve.
| Note: the routers are loaded and served
| automatically!
|
├─ services/
| modules that provide foundational services
| to the rest of the system.
|
├─ utils/
| simple utility classes, modules, and functions;
| stateless and pure (i.e. no side effects).
The tests/
folder should follow the same pattern as the src/
folder.
Currently, all configurations (but one) are determined by the environment variables of the
server's execution environment. All environment variables are described in
src/config/schema.ts
– see the describe(...)
calls.
Note: When running in debug
mode, the .env
file in the project's root directory will be loaded by default.
The other configuration used by the system is the version
value from the project's package.json
file. The version string must abide by Semantic Version 2.0.0. The 'major' part of the version will determine the base
path of the server.
Example
If src/routes/public.ts
exports a route called my/test/
, and the version
number in package.json
is set to '2.4.1'
, the route will be served from /api/v2/public/my/test/
(with or without the trailing /
).
The general pattern for endpoints is: /api/v<version_major>/<router_file_name>/<route_path>
To add a new configuration, you should first append any new environment variables to the environment variables schema in src/config/schema.ts
.
Then, you should export the parsed variable via the default export in src/config/index.ts
Example
In src/config/schema.ts
:
export const envSchema = z.object({
// ... omitted for brevity
COOLNESS: z.enum(['not cool', 'cool', 'very cool', 'uber cool'])
.describe('The perceived level of coolness of the server.')
.default('uber cool')
// ... omitted for brevity
});
In src/config/index.ts
:
const config = {
env: env.NODE_ENV,
port: env.PORT,
// ... omitted for brevity
perception: {
of: {
server: {
coolness: env.COOLNESS,
},
},
},
} as const;
export default config;
To add a new route, either:
a. Add routes to an existing router object default exported by a top-level source file in the src/routes
folder.
b. Create a new source file in the src/routes
folder and export default
a new router object from it.
Note: The general pattern for endpoints is: /api/v<version_major>/<router_file_name>/<route_path>
Test infrastructure is currently being implemented.
Essential Server is designed to allow maximum flexibility around deployment by not making design decisions that might ordinarily restrict deployment options.
If you encounter a bug or want to see something added or improved, please go ahead and open an issue!
If you need help with something, feel free to start a discussion!
Thank you, feel free!
Contributions can take many forms, from code for bug fixes and enhancements, to documentation work, writing additional tests, triaging incoming pull requests and issues, and more!
Before submitting a PR, ensure that:
- Code is functional.
- Code is linted.
- Code passes all tests.
- Any requisite updates or additions to documentation have been made.
Feel free to reach out if you're not sure!
MIT License
Copyright © 2024 Tej Birring
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.