Dynamic Routes
Overview
Section titled “Overview”Dynamic routes allow you to capture URL segments as parameters with type safety. StratusTS uses a typed parameter syntax that makes routes explicit and predictable.
Current Status
Section titled “Current Status”What’s Working:
- ✅ Typed parameter syntax (
<id:int>,<slug:str>) - ✅ Multiple parameters in single route
- ✅ Route matching and registration
Under Development:
- 🚧 Parameter value extraction in controllers
- 🚧 Automatic type conversion (int, str, etc.)
- 🚧 Parameter validation
Not tested yet!
- Wildcard routes ⏳
Planned Features:
- 📋 Optional parameters
- 📋 Parameter constraints (min, max, pattern)
Parameter Syntax
Section titled “Parameter Syntax”StratusTS uses an explicit typed syntax for parameters:
<parameter_name:type>Supported types:
int- Integer numbers (e.g., 1, 42, 999)str- Strings (e.g., “hello”, “my-slug”, “user-123”)bool- Boolean (spacific: true,false) its a nish case*- Any (e.g., “hello”, “my-slug”, 123) but it’s Returns as String
Examples:
<id:int> // Matches: 1, 42, 999<slug:str> // Matches: hello, my-post, about-us<userId:int> // Matches: 1, 2, 3<username:str> // Matches: john, alice, bob-smith<is-active:bool> // Matches: true, false<any:*> // Matches: john, alice, 123Basic Dynamic Parameters
Section titled “Basic Dynamic Parameters”Single Integer Parameter
Section titled “Single Integer Parameter”Route definition:
import { Router } from 'stratus-ts';import { getUser } from './controllers';
const { routes, route } = Router();
route.get('/<id:int>', getUser);
export default routes;Matches:
/1 ✅ Matches (id = 1)/42 ✅ Matches (id = 42)/999 ✅ Matches (id = 999)/abc ❌ No match (not an integer)/1.5 ❌ No match (not an integer)Single String Parameter
Section titled “Single String Parameter”Route definition:
route.get('/<slug:str>', getPost);Matches:
/hello-world ✅ Matches (slug = "hello-world")/my-first-post ✅ Matches (slug = "my-first-post")/about ✅ Matches (slug = "about")/123 ✅ Matches (slug = "123")Multiple Parameters
Section titled “Multiple Parameters”StratusTS supports multiple parameters in a single route.
Two Parameters
Section titled “Two Parameters”Route definition:
route.get('/<userId:int>/posts/<postId:int>', getUserPost);Matches:
/1/posts/5 ✅ Matches (userId=1, postId=5)/42/posts/123 ✅ Matches (userId=42, postId=123)/1/posts/abc ❌ No match (postId not int)Mixed Parameter Types
Section titled “Mixed Parameter Types”Route definition:
route.get('/<year:int>/<month:int>/<slug:str>', getBlogPost);Matches:
/2024/01/my-post ✅ Matches/2024/12/hello-world ✅ Matches/2024/abc/my-post ❌ No match (month not int)Controller (when parameter extraction is implemented):
Section titled “Controller (when parameter extraction is implemented):”const getBlogPost: ControllerType<{ year: number month: number slug: string}> = async (question, reply) => { const { year, month, slug } = question.params(); // all the params
const post = await Post.findOne({ where: { year, month, slug, }, });
reply.status(ok()).json({ data: post });};Type Safety Benefits
Section titled “Type Safety Benefits”The typed parameter syntax provides several benefits:
1. Clear Route Intent
Section titled “1. Clear Route Intent”// others way (ambiguous)route.get('/:id', getUser); // Is id a number? String? UUID?
// stratus-ts way (explicit)route.get('/<id:int>', getUser); // Clearly an integer2. Automatic Type Conversion
Section titled “2. Automatic Type Conversion”When parameter extraction is implemented, types will be automatically converted:
// others way:const id = parseInt(request.params.id); // Manual conversion
// No manual parsing neededconst { id } = question.params(); // Already a number!3. Route Validation
Section titled “3. Route Validation”Routes that don’t match the type won’t trigger the controller:
route.get('/<id:int>', getUser);
// /users/abc → 404 (doesn't match route)// /users/123 → Calls getUser with id=123Route Order and Specificity
Section titled “Route Order and Specificity”More specific routes should come before general ones:
// ✅ Correct orderroute.get('/featured', getFeaturedPosts); // Static route firstroute.get('/recent', getRecentPosts); // Static routeroute.get('/<slug:str>', getPost); // Dynamic last
// ❌ Wrong orderroute.get('/<slug:str>', getPost); // Matches everything!route.get('/featured', getFeaturedPosts); // Never reachedRule: Define routes from most specific to least specific.
Optional Parameters (Planned)
Section titled “Optional Parameters (Planned)”Planned syntax:
route.get('/posts/<id:int>?', listOrGetPost);Intended behavior:
/posts → List all posts (id is undefined)/posts/5 → Get post 5 (id = 5)Custom Types (Planned)
Section titled “Custom Types (Planned)”Planned syntax:
route.get('/<id:uuid>', getUser);route.get('/<date:date>', getPostsByDate);Intended matching:
<id:uuid> → Matches UUID format only<date:date> → Matches date format (YYYY-MM-DD)Parameter Constraints (Planned)
Section titled “Parameter Constraints (Planned)”Planned syntax:
route.get('/<id:int:min=1:max=9999>', getUser);route.get('/<slug:str:pattern=[a-z-]+>', getPost);Wildcard Routes
Section titled “Wildcard Routes”Planned syntax:
route.get('/files/<path:path>', serveFile);Would match:
✅ /files/guide.pdf✅ /files/logo.png✅ /files/file.txtBest Practices
Section titled “Best Practices”1. Use Descriptive Parameter Names
Section titled “1. Use Descriptive Parameter Names”// ✅ Good - clear what the parameter isroute.get('/<userId:int>/posts/<postId:int>', getPost);
// ❌ Bad - unclear parameter namesroute.get('/<a:int>/posts/<b:int>', getPost);2. Choose Appropriate Types
Section titled “2. Choose Appropriate Types”// ✅ Good - use int for numeric IDsroute.get('/<id:int>', getUser);
// ✅ Good - use str for slugsroute.get('/<slug:str>', getPost);
// ❌ Bad - using str for numeric IDroute.get('/<age:str>', getUser); // Should be int3. Keep Routes Simple
Section titled “3. Keep Routes Simple”// ✅ Good - reasonable nestingroute.get('/<userId:int>/posts/<postId:int>', getPost);
// ⚠️ Consider simplifying - too nestedroute.get( '/<userId:int>/posts/<postId:int>/comments/<commentId:int>/replies/<replyId:int>',getReply);Complete Example
Section titled “Complete Example”Here’s a complete example using typed dynamic routes:
// src/blog/routes.tsimport { Router } from 'stratus-ts';import { listPosts, getPost, getPostsByYear, getPostsByYearMonth, getUserPosts,} from './controllers';
const { routes, route } = Router();
// Static routes firstroute.get('/', listPosts);route.get('/featured', getFeaturedPosts);
// Dynamic routes (more specific first)route.get('/<year:int>/<month:int>/<slug:str>', getPostsByYearMonth);route.get('/<year:int>/<slug:str>', getPostsByYear);route.get('/user/<userId:int>', getUserPosts);route.get('/<slug:str>', getPost);
export default routes;// src/blog/controllers.tsimport { type ControllerType, ok } from 'stratus-ts';
export const getPostsByYearMonth: ControllerType<{ year: number month: number slug: string}> = async (question, reply) => { const { year, month, slug } = question.params(); // year: number, month: number, slug: string
const post = await Post.findOne({ where: { year, month, slug }, });
reply.status(ok()).json({ data: post });};Development Timeline
Section titled “Development Timeline”Current
Section titled “Current”- ✅ Typed parameter syntax implemented
- ✅ Route matching works
- ✅ Wildcard routes
- 🚧 Parameter extraction in development
Next Release
Section titled “Next Release”- 🚧 Complete parameter extraction
- 🚧 Automatic type conversion
- 🚧 Better error messages
Future Releases
Section titled “Future Releases”- 📋 Optional parameters
- 📋 Custom types
- 📋 Parameter constraints
Providing Feedback
Section titled “Providing Feedback”We value your input on dynamic routing!
Report Issues
Section titled “Report Issues”Found a bug? Open an issue
Include:
- Route definition
- Expected behavior
- Actual behavior
- Example code
Request Features
Section titled “Request Features”Want a feature? Start a discussion
Share:
- Your use case
- Example of desired syntax
- Why it’s important
Stay Updated
Section titled “Stay Updated”- GitHub: Watch the repository for updates
- Changelog: Check release notes
- This page: Updates as features land
Questions?
Section titled “Questions?”Dynamic routing is actively evolving. Have questions?
- Documentation: Check back for updates
- GitHub Issues: Report problems
- Discussions: Ask questions
- Examples: See Examples for working code
Thank you for your patience as we complete this feature!