Skip to content

feat: ServiceRouter — auto-discovery, dynamic routing, and caching#399

Merged
usernane merged 4 commits into
devfrom
feat/service-router
Jun 14, 2026
Merged

feat: ServiceRouter — auto-discovery, dynamic routing, and caching#399
usernane merged 4 commits into
devfrom
feat/service-router

Conversation

@usernane

Copy link
Copy Markdown
Member

Summary

Complete ServiceRouter integration: auto-discover API routes from namespaces, dynamic runtime resolution, DI container integration, CLI tooling, and production route caching.

Motivation

Eliminate boilerplate of manually registering every API service. Developers create a #[RestController] class and it is routable. Supports traditional WebService and WebServicesManager classes too.

Changes

  • ServiceRouter::discover() — scans namespace, registers routes for #[RestController], WebService, and WebServicesManager classes
  • ServiceRouter::dynamic() — registers catch-all route for runtime resolution
  • ServiceRouter::handle() — resolves controller name to class at request time (404 if not found)
  • RouteOption::NS constant for namespace-based routing
  • RouteCache — caches discovery results using app cache backend (file/Redis)
  • ServicesListCommand (services:list) — lists all discovered services
  • RoutesCacheCommand (routes:cache) — builds route cache
  • RoutesClearCommand (routes:clear) — clears route cache
  • Recursive scanning with kebab-case path derivation from directory structure
  • DI container integration for service instantiation
  • #[RestController] name with / rejected (name is identifier, not path)

How to Test / Verify

vendor/bin/phpunit --filter "ServiceRouterTest|RouteCacheTest|ServicesListCommandTest"

37 tests covering all features. RouteCache has 100% line coverage.

Breaking Changes and Migration Steps

None. All existing routing (Router::api(), WebServicesManager) works unchanged. ServiceRouter is opt-in.

Checklist

  • I reviewed my own diff before requesting review
  • My commits follow Conventional Commits
  • I added/updated tests (or explained why not)
  • I updated docs (if needed) Docs Repo
  • I ran lint/cs-fixer (if applicable)
  • I considered backward compatibility
  • I considered security

Related issues

Closes #382
Closes #383
Closes #384
Closes #385
Closes #386

Ibrahim BinAlshikh added 4 commits June 14, 2026 12:21
Scans a namespace for routable classes and registers API routes:
- #[RestController] attributed classes (uses attribute name or derived)
- WebService subclasses without attribute (uses getName())
- WebServicesManager subclasses (registered as manager routes)
- Non-service classes are skipped

Includes DI container integration for service instantiation.

Closes #382
Closes #384
- ServiceRouter::dynamic() registers catch-all route for namespace
- ServiceRouter::handle() resolves controller at request time, 404 if not found
- RouteOption::NS constant for namespace-based routing
- ServicesListCommand lists all discovered services with name, class, type, path

Closes #383
Closes #385
- discover() accepts recursive flag for subdirectory scanning
- Subdirectory names become kebab-cased URL path segments
- Class names converted to kebab-case via CaseConverter
- #[RestController] name with '/' is rejected (skipped)
- Explicit attribute name is always flat (ignores directory nesting)
- Non-recursive remains the default
- RouteCache class: build/load/clear cached service discovery results
- Uses app's existing cache backend (file, Redis, etc.)
- routes:cache CLI command to build cache
- routes:clear CLI command to clear cache
- Enabled via ROUTE_CACHE_ENABLED env variable
- 100% test coverage (12 tests, 35/35 lines)

Closes #386
@usernane usernane merged commit f4d8f58 into dev Jun 14, 2026
0 of 5 checks passed
@usernane usernane deleted the feat/service-router branch June 14, 2026 10:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant