A step-by-step guide to building a simple web server route matcher using the uCalc Transformer's declarative patterns.
Product:
Class:
Warning
uCalc API Preview Release Notice:The uCalc engine has successfully transitioned to modern cross-platform environments.The next phase envolves some structural changes, performance optimizations, and API refinements.The API is subject to breaking changes prior to the stable release. Please evaluate the preview version thoroughly before production use.
A core task for any web server is routing: mapping an incoming URL path like /users/123 to the correct application logic (a "handler") and extracting any dynamic parameters (like the user ID 123). This project will guide you through building a simple but powerful route matcher using the declarative patterns of the uCalc Transformer.
We'll create a Domain-Specific Language (DSL) for defining routes that is common in modern web frameworks like Express.js or Flask. Placeholders for dynamic segments are enclosed in curly braces.
/users/{id}/products/{category}/{id}The core idea is to treat routing as a text transformation problem. We'll take an incoming URL path and transform it into a string that represents the action to take.
/users/42FromTo("/users/{id}", "Handler: UserProfile, id: {id}")"Handler: UserProfile, id: 42"The application can then easily parse this output string to call the correct function with the extracted parameters.
First, we need a Transformer instance. This will be our router. We will define all our route patterns on this object.
using uCalcSoftware;
var uc = new uCalc();
using (var router = new uCalc.Transformer()) {
// ... rules will go here ...
}
Each route is a FromTo rule. The pattern matches the URL structure, and the replacement string defines the output.
Static Route: A simple, fixed path. router.FromTo("/about", "Handler: AboutPage");
Dynamic Route: A path with one or more variable placeholders. router.FromTo("/users/{id}", "Handler: UserProfile, id: {id}");
What happens if you have two similar routes, like /users/new and /users/{id}? A request for /users/new could technically match both patterns. To resolve this, the Transformer uses a LIFO (Last-In, First-Out) precedence rule: the most recently defined rule is checked first.
Therefore, you must define your most specific rules last to give them higher priority.
using uCalcSoftware;
var uc = new uCalc();
// General rule defined first (lower priority)
router.FromTo("/users/{id}", "Handler: UserProfile, id: {id}");
// Specific rule defined last (higher priority)
router.FromTo("/users/new", "Handler: CreateUserPage");
To process a request, simply call Transform() on the incoming URL string. If the result is different from the original URL, a match was found. If it's unchanged, it's a "404 Not Found."
/users/{id} vs. /users/(\w+)), and the LIFO precedence is a clear, built-in system./ is brittle and doesn't handle complex patterns or constraints well.uCalc provides a declarative, token-aware, and extensible way to define a routing system that is both powerful and easy to maintain.
ID: 1435
using uCalcSoftware;
var uc = new uCalc();
using (var router = new uCalc.Transformer()) {
// Define routes
router.FromTo("/home", "Handler: HomePage");
router.FromTo("/users/{id}", "Handler: UserProfile, id: {id}");
// Test routes
Console.WriteLine($"Matching '/home': {router.Transform("/home")}");
Console.WriteLine($"Matching '/users/42': {router.Transform("/users/42")}");
}
Matching '/home': Handler: HomePage
Matching '/users/42': Handler: UserProfile, id: 42 using uCalcSoftware; var uc = new uCalc(); using (var router = new uCalc.Transformer()) { // Define routes router.FromTo("/home", "Handler: HomePage"); router.FromTo("/users/{id}", "Handler: UserProfile, id: {id}"); // Test routes Console.WriteLine($"Matching '/home': {router.Transform("/home")}"); Console.WriteLine($"Matching '/users/42': {router.Transform("/users/42")}"); }
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
int main() {
uCalc uc;
{
uCalc::Transformer router;
router.Owned(); // Causes router to be released when it goes out of scope
// Define routes
router.FromTo("/home", "Handler: HomePage");
router.FromTo("/users/{id}", "Handler: UserProfile, id: {id}");
// Test routes
cout << "Matching '/home': " << router.Transform("/home") << endl;
cout << "Matching '/users/42': " << router.Transform("/users/42") << endl;
}
}
Matching '/home': Handler: HomePage
Matching '/users/42': Handler: UserProfile, id: 42 #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; int main() { uCalc uc; { uCalc::Transformer router; router.Owned(); // Causes router to be released when it goes out of scope // Define routes router.FromTo("/home", "Handler: HomePage"); router.FromTo("/users/{id}", "Handler: UserProfile, id: {id}"); // Test routes cout << "Matching '/home': " << router.Transform("/home") << endl; cout << "Matching '/users/42': " << router.Transform("/users/42") << endl; } }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
Using router As New uCalc.Transformer()
'// Define routes
router.FromTo("/home", "Handler: HomePage")
router.FromTo("/users/{id}", "Handler: UserProfile, id: {id}")
'// Test routes
Console.WriteLine($"Matching '/home': {router.Transform("/home")}")
Console.WriteLine($"Matching '/users/42': {router.Transform("/users/42")}")
End Using
End Sub
End Module
Matching '/home': Handler: HomePage
Matching '/users/42': Handler: UserProfile, id: 42 Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() Using router As New uCalc.Transformer() '// Define routes router.FromTo("/home", "Handler: HomePage") router.FromTo("/users/{id}", "Handler: UserProfile, id: {id}") '// Test routes Console.WriteLine($"Matching '/home': {router.Transform("/home")}") Console.WriteLine($"Matching '/users/42': {router.Transform("/users/42")}") End Using End Sub End Module
ID: 1436
using uCalcSoftware;
var uc = new uCalc();
using (var router = new uCalc.Transformer()) {
// --- Define Routes ---
// General rules first (lower precedence)
router.FromTo("/products/{category}/{id}", "Handler: ProductDetail, category: {category}, id: {id}");
router.FromTo("/users/{id}", "Handler: UserProfile, id: {id}");
// Specific rule last (higher precedence)
router.FromTo("/users/new", "Handler: CreateUserPage");
// --- Simulate Requests ---
string[] urls = {"/users/123", "/users/new", "/products/electronics/567", "/contact"};
foreach(var url in urls) {
var originalUrl = url;
var result = router.Transform(url);
if (result.Text == originalUrl) {
Console.WriteLine($"URL: {originalUrl} -> 404 Not Found");
} else {
Console.WriteLine($"URL: {originalUrl} -> {result}");
}
}
}
URL: /users/123 -> Handler: UserProfile, id: 123
URL: /users/new -> Handler: CreateUserPage
URL: /products/electronics/567 -> Handler: ProductDetail, category: electronics, id: 567
URL: /contact -> 404 Not Found using uCalcSoftware; var uc = new uCalc(); using (var router = new uCalc.Transformer()) { // --- Define Routes --- // General rules first (lower precedence) router.FromTo("/products/{category}/{id}", "Handler: ProductDetail, category: {category}, id: {id}"); router.FromTo("/users/{id}", "Handler: UserProfile, id: {id}"); // Specific rule last (higher precedence) router.FromTo("/users/new", "Handler: CreateUserPage"); // --- Simulate Requests --- string[] urls = {"/users/123", "/users/new", "/products/electronics/567", "/contact"}; foreach(var url in urls) { var originalUrl = url; var result = router.Transform(url); if (result.Text == originalUrl) { Console.WriteLine($"URL: {originalUrl} -> 404 Not Found"); } else { Console.WriteLine($"URL: {originalUrl} -> {result}"); } } }
#include
#include "uCalc.h"
using namespace std;
using namespace uCalcSoftware;
int main() {
uCalc uc;
{
uCalc::Transformer router;
router.Owned(); // Causes router to be released when it goes out of scope
// --- Define Routes ---
// General rules first (lower precedence)
router.FromTo("/products/{category}/{id}", "Handler: ProductDetail, category: {category}, id: {id}");
router.FromTo("/users/{id}", "Handler: UserProfile, id: {id}");
// Specific rule last (higher precedence)
router.FromTo("/users/new", "Handler: CreateUserPage");
// --- Simulate Requests ---
vector urls = {"/users/123", "/users/new", "/products/electronics/567", "/contact"};
for(auto url : urls) {
auto originalUrl = url;
auto result = router.Transform(url);
if (result.Text() == originalUrl) {
cout << "URL: " << originalUrl << " -> 404 Not Found" << endl;
} else {
cout << "URL: " << originalUrl << " -> " << result << endl;
}
}
}
}
URL: /users/123 -> Handler: UserProfile, id: 123
URL: /users/new -> Handler: CreateUserPage
URL: /products/electronics/567 -> Handler: ProductDetail, category: electronics, id: 567
URL: /contact -> 404 Not Found #include <iostream> #include "uCalc.h" using namespace std; using namespace uCalcSoftware; int main() { uCalc uc; { uCalc::Transformer router; router.Owned(); // Causes router to be released when it goes out of scope // --- Define Routes --- // General rules first (lower precedence) router.FromTo("/products/{category}/{id}", "Handler: ProductDetail, category: {category}, id: {id}"); router.FromTo("/users/{id}", "Handler: UserProfile, id: {id}"); // Specific rule last (higher precedence) router.FromTo("/users/new", "Handler: CreateUserPage"); // --- Simulate Requests --- vector<string> urls = {"/users/123", "/users/new", "/products/electronics/567", "/contact"}; for(auto url : urls) { auto originalUrl = url; auto result = router.Transform(url); if (result.Text() == originalUrl) { cout << "URL: " << originalUrl << " -> 404 Not Found" << endl; } else { cout << "URL: " << originalUrl << " -> " << result << endl; } } } }
Imports System
Imports uCalcSoftware
Public Module Program
Public Sub Main()
Dim uc As New uCalc()
Using router As New uCalc.Transformer()
'// --- Define Routes ---
'// General rules first (lower precedence)
router.FromTo("/products/{category}/{id}", "Handler: ProductDetail, category: {category}, id: {id}")
router.FromTo("/users/{id}", "Handler: UserProfile, id: {id}")
'// Specific rule last (higher precedence)
router.FromTo("/users/new", "Handler: CreateUserPage")
'// --- Simulate Requests ---
Dim urls() As String = {"/users/123", "/users/new", "/products/electronics/567", "/contact"}
For Each url In urls
Dim originalUrl = url
Dim result = router.Transform(url)
If result.Text = originalUrl Then
Console.WriteLine($"URL: {originalUrl} -> 404 Not Found")
Else
Console.WriteLine($"URL: {originalUrl} -> {result}")
End If
Next
End Using
End Sub
End Module
URL: /users/123 -> Handler: UserProfile, id: 123
URL: /users/new -> Handler: CreateUserPage
URL: /products/electronics/567 -> Handler: ProductDetail, category: electronics, id: 567
URL: /contact -> 404 Not Found Imports System Imports uCalcSoftware Public Module Program Public Sub Main() Dim uc As New uCalc() Using router As New uCalc.Transformer() '// --- Define Routes --- '// General rules first (lower precedence) router.FromTo("/products/{category}/{id}", "Handler: ProductDetail, category: {category}, id: {id}") router.FromTo("/users/{id}", "Handler: UserProfile, id: {id}") '// Specific rule last (higher precedence) router.FromTo("/users/new", "Handler: CreateUserPage") '// --- Simulate Requests --- Dim urls() As String = {"/users/123", "/users/new", "/products/electronics/567", "/contact"} For Each url In urls Dim originalUrl = url Dim result = router.Transform(url) If result.Text = originalUrl Then Console.WriteLine($"URL: {originalUrl} -> 404 Not Found") Else Console.WriteLine($"URL: {originalUrl} -> {result}") End If Next End Using End Sub End Module
This page last modified on: