@owlmeans/client-route
v0.1.1
Published
Client-side routing library for OwlMeans applications that extends the base `@owlmeans/route` package with client-specific functionality.
Downloads
318
Readme
@owlmeans/client-route
Client-side routing library for OwlMeans applications that extends the base @owlmeans/route package with client-specific functionality.
Overview
The @owlmeans/client-route package is a client-side extension of the @owlmeans/route module, providing additional functionality specifically designed for frontend applications. It extends the base routing capabilities with client-specific features such as partial path preservation and parameter extraction.
This package is part of the OwlMeans Common library suite and follows the OwlMeans Common Module approach (described in @owlmeans/context). Like other modules in the suite, it's designed to work within the OwlMeans Common Module ecosystem and is not self-sufficient.
Key Features
- Client Route Models - Extends base route models with client-specific behavior
- Partial Path Preservation - Maintains original path patterns for client-side processing
- Parameter Extraction - Utility functions for extracting route parameters
- Promise-based Resolution - Manages asynchronous route resolution with state tracking
- Type Safety - Full TypeScript support with proper type definitions
Installation
npm install @owlmeans/client-routeNote: This package depends on @owlmeans/route and @owlmeans/client-context, which will be installed automatically.
Core Concepts
Client Route
A client route extends the base CommonRoute with additional client-specific properties, particularly the partialPath which preserves the original path pattern for client-side processing.
Client Route Model
A client route model wraps a client route with additional behavior, including promise-based resolution tracking and client-specific resolution logic.
Parameter Extraction
The package provides utilities to extract parameters from route paths, useful for client-side routing and navigation.
API Reference
Types
ClientRoute
Extended route interface with client-specific properties.
interface ClientRoute extends CommonRoute {
partialPath: string // Original path pattern preserved for client use
}Properties:
- partialPath:
string- The original path pattern before resolution, useful for client-side routing logic
ClientRouteModel
Extended route model with client-specific resolution behavior.
interface ClientRouteModel extends CommonRouteModel {
route: ClientRoute // The wrapped client route
_resolved?: Promise<void> // Promise tracking resolution state
_client: true // Client route marker
}Properties:
- route:
ClientRoute- The wrapped client route object - _resolved:
Promise<void>- Optional promise that tracks the resolution state - _client:
true- Marker indicating this is a client route model
ClientRouteOptions
Options for configuring client routes.
interface ClientRouteOptions {
overrides?: Partial<ClientRoute> // Route parameter overrides
}Properties:
- overrides:
Partial<ClientRoute>- Optional route parameter overrides
Core Functions
route(route, opts?)
Wraps a base route model with client-specific functionality.
const route: (route: CommonRouteModel, opts?: ClientRouteOptions) => ClientRouteModelParameters:
route: CommonRouteModel- Base route model from@owlmeans/routeopts?: ClientRouteOptions- Optional configuration options
Returns: ClientRouteModel - Client route model with enhanced functionality
Features:
- Preserves original path as
partialPath - Adds promise-based resolution tracking
- Provides client-specific resolution logic
- Supports parameter overrides
Example:
import { route as baseRoute } from '@owlmeans/route'
import { route as clientRoute } from '@owlmeans/client-route'
// Create a base route
const userRoute = baseRoute('user', '/users/:id')
// Wrap with client functionality
const clientUserRoute = clientRoute(userRoute, {
overrides: {
secure: true
}
})
// Use client-specific features
console.log(clientUserRoute.route.partialPath) // '/users/:id'
const resolved = await clientUserRoute.resolve(context)Helper Functions
isClientRouteModel(route)
Type guard to check if a route object is a client route model.
const isClientRouteModel: (route: Object) => route is ClientRouteModelParameters:
route: Object- Object to check
Returns: boolean - True if the object is a client route model
Example:
import { isClientRouteModel } from '@owlmeans/client-route'
if (isClientRouteModel(routeObject)) {
// TypeScript knows this is a ClientRouteModel
console.log(routeObject.route.partialPath)
}extractParams(path)
Extracts parameter names from a route path.
const extractParams: (path: string) => string[]Parameters:
path: string- Route path pattern
Returns: string[] - Array of parameter names
Example:
import { extractParams } from '@owlmeans/client-route'
const params = extractParams('/users/:id/posts/:postId')
console.log(params) // ['id', 'postId']
const simpleParams = extractParams('/api/users/:userId')
console.log(simpleParams) // ['userId']
const noParams = extractParams('/api/users')
console.log(noParams) // []Usage Examples
Basic Client Route Creation
import { route as baseRoute } from '@owlmeans/route'
import { route as clientRoute } from '@owlmeans/client-route'
// Create a base route
const apiRoute = baseRoute('api', '/api/users/:id')
// Wrap with client functionality
const clientApiRoute = clientRoute(apiRoute)
// Access client-specific features
console.log(clientApiRoute.route.partialPath) // '/api/users/:id'
console.log(clientApiRoute._client) // trueRoute Resolution with State Tracking
import { route as baseRoute } from '@owlmeans/route'
import { route as clientRoute } from '@owlmeans/client-route'
const userRoute = baseRoute('user', '/users/:id')
const clientUserRoute = clientRoute(userRoute)
// Resolve the route
const resolved = await clientUserRoute.resolve(context)
// The partial path is preserved
console.log(resolved.partialPath) // '/users/:id'
console.log(resolved.path) // '/users/123' (resolved)Parameter Extraction
import { extractParams } from '@owlmeans/client-route'
// Extract parameters from different path patterns
const userParams = extractParams('/users/:id')
console.log(userParams) // ['id']
const nestedParams = extractParams('/users/:userId/posts/:postId/comments/:commentId')
console.log(nestedParams) // ['userId', 'postId', 'commentId']
// Handle paths with no parameters
const staticParams = extractParams('/api/health')
console.log(staticParams) // []Type Guards and Validation
import { isClientRouteModel } from '@owlmeans/client-route'
import { route as baseRoute } from '@owlmeans/route'
import { route as clientRoute } from '@owlmeans/client-route'
const baseRouteModel = baseRoute('api', '/api')
const clientRouteModel = clientRoute(baseRouteModel)
console.log(isClientRouteModel(baseRouteModel)) // false
console.log(isClientRouteModel(clientRouteModel)) // true
// Type-safe access
if (isClientRouteModel(someRoute)) {
console.log(someRoute.route.partialPath) // TypeScript knows this exists
}Route Overrides
import { route as baseRoute } from '@owlmeans/route'
import { route as clientRoute } from '@owlmeans/client-route'
const baseUserRoute = baseRoute('user', '/users/:id')
// Override route properties
const clientUserRoute = clientRoute(baseUserRoute, {
overrides: {
secure: true,
method: RouteMethod.GET
}
})
console.log(clientUserRoute.route.secure) // true
console.log(clientUserRoute.route.partialPath) // '/users/:id'Integration with OwlMeans Context
The client-route package integrates seamlessly with the OwlMeans context system and works in conjunction with other OwlMeans Common modules:
import { route as baseRoute, frontend } from '@owlmeans/route'
import { route as clientRoute } from '@owlmeans/client-route'
import { makeClientContext } from '@owlmeans/client-context'
// Create a frontend route
const homeRoute = baseRoute('home', '/', frontend())
// Wrap with client functionality
const clientHomeRoute = clientRoute(homeRoute)
// Use with client context
const context = makeClientContext(config)
const resolved = await clientHomeRoute.resolve(context)Advanced Usage
Custom Resolution Logic
import { route as baseRoute } from '@owlmeans/route'
import { route as clientRoute } from '@owlmeans/client-route'
const baseRoute = baseRoute('api', '/api/:version')
const clientApiRoute = clientRoute(baseRoute)
// The client route preserves the original path pattern
const resolved = await clientApiRoute.resolve(context)
// Use partial path for client-side routing
const navigationPath = clientApiRoute.route.partialPath
const resolvedPath = resolved.path
console.log(navigationPath) // '/api/:version' (for client routing)
console.log(resolvedPath) // '/api/v1' (resolved for actual requests)Parameter-Based Navigation
import { extractParams } from '@owlmeans/client-route'
const buildNavigationUrl = (pathPattern: string, params: Record<string, string>) => {
const paramNames = extractParams(pathPattern)
let url = pathPattern
paramNames.forEach(param => {
url = url.replace(`:${param}`, params[param] || '')
})
return url
}
// Usage
const pattern = '/users/:userId/posts/:postId'
const url = buildNavigationUrl(pattern, { userId: '123', postId: '456' })
console.log(url) // '/users/123/posts/456'Error Handling
The package provides comprehensive error handling:
- SyntaxError - Thrown when attempting to resolve a route that's already resolved without proper promise handling
- Type Guards - Use
isClientRouteModelto ensure type safety - Promise Management - The
_resolvedpromise prevents multiple resolution attempts
Best Practices
- Use Type Guards - Always use
isClientRouteModelwhen working with mixed route types - Handle Promises - Properly handle the
_resolvedpromise to avoid resolution conflicts - Preserve Partial Paths - Use the
partialPathproperty for client-side routing logic - Parameter Extraction - Use
extractParamsfor dynamic route handling - Integration - Combine with other OwlMeans Common modules for full functionality
Related Modules
- @owlmeans/route - Base routing functionality (required dependency)
- @owlmeans/client-context - Client-side context management (required dependency)
- @owlmeans/context - Core context system for route resolution
- @owlmeans/server-route - Server-side route implementations
Migration from @owlmeans/route
If you're upgrading from using @owlmeans/route directly in a client application:
// Before
import { route } from '@owlmeans/route'
const userRoute = route('user', '/users/:id')
// After
import { route as baseRoute } from '@owlmeans/route'
import { route as clientRoute } from '@owlmeans/client-route'
const userRoute = clientRoute(baseRoute('user', '/users/:id'))
// Additional client functionality is now available
console.log(userRoute.route.partialPath) // '/users/:id'