aminexpress
v1.1.0
Published
mini HTTP router with fast routing and a diffrent method for handling middlewares
Downloads
4
Maintainers
Readme
Amin Express (HTTP Router)
Introduction
Welcome to AminExpress, a high-performance, strongly-typed HTTP routing library designed to handle large-scale applications efficiently. Leveraging the power of the radix tree data structure, our router ensures rapid and efficient route matching, making it a perfect choice for developers aiming to build scalable and performant web applications.
Key Features
- Efficient Routing: Built on a radix tree data structure, AminExpress excels in quickly matching routes, ensuring minimal latency even as the number of routes grows.
- Middleware Support: Easily integrate middleware to handle tasks such as authentication, logging, and more, enhancing your application's functionality without cluttering your main logic.
- Static File Serving: Simplify the process of serving static files like HTML, CSS, and JavaScript with built-in support, reducing the need for additional configuration or third-party libraries.
- Strongly Typed: With TypeScript support, enjoy the benefits of static typing, including improved code quality, better tooling, and reduced runtime errors.
Whether you're building a small personal project or a large enterprise application, AminExpress provides the performance and flexibility needed to manage your routes effectively.
Contribution
Docs
How it works
This app is an HTTP router with built-in middleware support, similar to popular frameworks like Express.js. However, it utilizes a unique approach by implementing a radix tree data structure for efficient route handling. This README explains the inner workings of the app, including route creation, middleware assignment, and request handling.
radix Tree Data Structure
At the core of the app is a radix tree data structure, which organizes routes in a hierarchical manner. Each segment of a URL path is represented as an edge in the radix tree, and the end of the path is represented as a node. This structure allows for efficient route matching and middleware execution.
Route Creation
When a new route is defined, the app performs the following steps:
URL Segmentation: The URL is split into its constituent parts (edges). For example, the URL /user/id/ali is split into three segments: user, id, and ali.
Node and Edge Creation: For each segment of the URL, the app creates corresponding edges and nodes in the radix tree. If an edge or node already exists, it is reused. This prevents duplication and ensures a compact structure.
- For /user/id/ali, the app creates or reuses the following:
- An edge for user and a node for user.
- An edge for id and a node for id as a child of user.
- An edge for ali and a node for ali as a child of id.
- For /user/id/ali, the app creates or reuses the following:
Middleware and Callback Assignment: The middlewares and route-specific callbacks are assigned to the final node created for the route. Middlewares defined before the route are attached in order, followed by the route's callback.
Request Handling
When a request is received, the app processes it through the following steps:
URL Matching: The app traverses the radix tree using the segments of the incoming URL to find the corresponding node.
- For example, a request to /user/ali would traverse the edges user and ali to find the node for ali.
Middleware Execution: Once the target node is found, the app retrieves the list of middlewares and callbacks stored in that node.
Callback Execution: The app executes the middlewares and callbacks in the order they were defined. Any middlewares defined after the route are also added to the list of callbacks to be executed in sequence. This ensures that each middleware processes the request in sequence before the final callback is executed.
Example
Let's walk through a concrete example:
- Define Middlewares:
router.use((req, res, next) => {
console.log('Middleware 1');
next();
});
router.use((req, res, next) => {
console.log('Middleware 2');
next();
});
- Define Routes:
router.get('/user/ali', (req, res) => {
res.send('Hello, Ali!');
});
router.use((req, res, next) => {
console.log('Middleware 3');
next();
});
Internal Radix Tree Structure:
- The radix tree will have edges and nodes for user and ali. The node for ali will have the middlewares and the callback assigned to it.
Handling a Request:
- A request to /user/ali will trigger the middlewares and the callback in order:
- Middleware 1: Logs 'Middleware 1'.
- Middleware 2: Logs 'Middleware 2'.
- Callback: Sends 'Hello, Ali!' as the response.
- Middleware 3: Logs 'Middleware 3'.
installation
npm install aminexpress
getting started
first you need to import the aminexpress constructor :
import aminexpress from "aminexpress";
const app = aminexpress();
then you can make your route (more informations on routes in methods) or your middlware (more info on middleware):
//route with get method
app.get("/",(req : Request , res : Response , next : NextFunction)=>{
res.end("Hello World!");
});
// middlware
app.use((req : Request, res : Response, next : NextFunction)=>{
console.log("middleware");
next();
})
in the end call the listen method for server :
app.listen(PORT , ()=>{
console.log(`server is listening on port ${PORT}`)
})
methods
app.METHOD()
app.get("your-url",callback,...[callbacks]);
supported methods :
- GET
- POST
- PUT
- DELETE
middleware
app.use(callback, ...[callbacks])
- Accepts multiple callback functions and executes them in the defined order.
app.use(path, callback, ...[callbacks])
- Accepts a path and multiple callback functions, executing them in the defined order for the specified path.
app.use([path], callback, ...[callbacks])
- Accepts multiple paths and callback functions, executing them in the defined order for each specified path.
next()
- Calls the next middleware in the defined order.
next(error)
- If called with an error, it triggers the built-in error handler. (you can set a cutom error handler error handling)
Example Usage:
app.use((req: Request, res: Response, next: NextFunction) => {
// Middleware logic
next(); // Proceed to the next middleware
});
app.use((req: Request, res: Response, next: NextFunction) => {
// Some logic that may cause an error
if (someError) {
next(new Error("Something went wrong")); // Trigger the error handler
} else {
next(); // Proceed to the next middleware
}
});
request
The Request
type extends IncomingMessage
and includes additional objects like query
and params
.
Example:
//you can specify the parameter variable with colon (:)
//gets id as url parameter
app.get("/user/:id", (req: Request, res: Response, next: NextFunction) => {
console.log(req.params);
// { id : "id-in-url" }
});
//multiple parameter
app.get(
"/user/:user_id/profile/:profile_id",
(req: Request, res: Response, next: NextFunction) => {
console.log(req.params);
// {user_id : "user_id-in-url" , profile_id : "profile_id_in_url"}
}
);
//req.query example
app.get(
"/user?p=123&a=31",
(req: Request, res: Response, next: NextFunction) => {
console.log(req.query);
// {p : "123" , a : "31"}
}
);
response
The Response
type extends ServerResponse<IncomingMessage>
, and includes additional methods such as json
, status
, and redirect
.
Example:
//res.end()
app.get("/", (req: Request, res: Response, next: NextFunction) => {
//sets the status code 200 and sends a string
res.status(200).end("hello world!");
});
//res.json()
app.get("/another-route", (req: Request, res: Response, next: NextFunction) => {
res.status(200).json({ message: "hello world" });
});
// res.redirect()
app.get(
"/another-route-2",
(req: Request, res: Response, next: NextFunction) => {
res.redirect("route-to-redirect");
}
);
error handling
this library has its own error handler that you can call it with next(err : Error)
you can set custom error handler with app.errorHandler(callback)
Example:
app.errorHandler(
(err: Error, req: Request, res: Response, next: NextFunction) => {
console.log(err.message);
}
);
serve static
The serveStatic
function simplifies the process of serving static files such as HTML, CSS, JavaScript, images, and other assets. This function helps deliver these files directly to the client, making it easy to build and deploy static content within your application.
Example:
app.serveStatic(__dirname + "/uploads", "/uploads");
Contribution
We welcome contributions to HTTP Router! Whether you want to report a bug, propose a new feature, or submit a pull request, your involvement is greatly appreciated.
How to Contribute
Fork the Repository:
- Navigate to the aminexpress repository on GitHub.
- Click the "Fork" button at the top right of the page.
Clone Your Fork:
- Open your terminal and clone your forked repository:
git clone https://github.com/smaEti/AminExpress
- Navigate to the project directory:
cd AminExpress
- Open your terminal and clone your forked repository:
Create a Branch:
- Create a new branch for your work:
git checkout -b feature-or-bugfix-description
- Create a new branch for your work:
Make Changes:
- Implement your changes in the codebase.
Commit Your Changes:
- Add the files you changed:
git add .
- Commit your changes with a meaningful message:
git commit -m "Description of your changes"
- Add the files you changed:
Push to GitHub:
- Push your changes to your forked repository:
git push origin feature-or-bugfix-description
- Push your changes to your forked repository:
Open a Pull Request:
- Go to the original repository and click the "Compare & pull request" button.
- Provide a clear description of the changes you made and any relevant information.
- Submit the pull request.
Thank you for your interest in contributing to aminexpress!