modular_api 0.4.5
modular_api: ^0.4.5 copied to clipboard
Use-case centric API toolkit for Dart — Shelf UseCase base class, HTTP adapters, CORS middleware, and automatic OpenAPI documentation.
Changelog #
All notable changes to this project will be documented in this file.
The format loosely follows Keep a Changelog and the project adheres to Semantic Versioning.
Documentation #
0.4.5 - 2026-03-28 #
Added #
serversparameter inModularApiconstructor — configures the OpenAPIserversfield so Swagger UI "Try it out" targets the correct host (LAN IP, domain, reverse proxy URL). Defaults tolocalhost:{port}when omitted.corsMiddleware()— configurable CORS middleware replacingexampleCorsMiddleware(). Acceptsorigin(String or List),methods, andallowedHeaders. Aligned with TypeScriptcors()and Pythoncors_middleware().SchemaField.object()— factory constructor for nested JSON object fields (type: 'object'). Enables webhook payloads with arbitrary nested objects to be declared, validated, and documented in OpenAPI (issue #8).objectcase in_isJsonTypeValid— validates that a field declared asobjectreceives aMapvalue; rejects strings, arrays, and other types.Mapcase in_inferOpenApiType— infers'object'forMapvalues in example-based schema generation.
Fixed #
useCaseHttpHandlercatch blocks use scoped logger —UseCaseExceptionand unexpected errors are now logged throughreq.context['modular.logger']instead ofstderr.writeln, enabling Loki correlation withtrace_id(issue #7).
Removed #
exampleCorsMiddleware()— replaced by the configurablecorsMiddleware()
0.4.4 - 2026-03-14 #
Changed #
- Swagger UI replaced with
@macss/docs-ui— the ~200-line inline HTML/CSS/JS reduced to a ~15-line bootloader that loads@macss/docs-ui@0.1from jsdelivr CDN - Dark mode now delegated to
docs-uipackage — single source of truth across all three SDKs
0.4.3 - 2026-03-13 #
Changed (BREAKING) #
execute()returnsFuture<O>— no longerFuture<void>; the handler reads the returned Output directly- Removed
outputfield fromUseCase— no mutable state;execute()returns the result - Removed
toJson()fromUseCase— the handler callsoutput.toJson()on the returned value inputExample/outputExamplenow required inModuleBuilder.usecase()— OpenAPI schema extraction uses them directly- Removed Strategy 2 fallback in OpenAPI schema extraction — no
factory({}).outputpath
Removed #
@Fieldannotation — was decorative only (no runtime effect in Dart);schemaFieldsgetter is the sole schema source
0.4.2 - 2026-03-12 #
Added #
- Auto-schema generation —
InputandOutputDTOs derive OpenAPI 3.0.3 schemas automatically fromschemaFieldsgetter +SchemaFieldmetadata @Fieldannotation — decorative per-field documentation (@Field(description: 'x'))SchemaFieldclass — metadata with factories:.string(),.integer(),.number(),.boolean(),.array()buildSchema()utility — convertsList<SchemaField>to OpenAPI 3.0.3-compatibleMap<String, dynamic>Input/Outputbase classes gain generative constructors and defaulttoSchema()fromschemaFields- Cross-language schema conformance tests against shared JSON fixtures
Changed #
- DTOs now use
extends Input/extends Outputinstead ofimplements(for inheritedtoSchema()default) - Manual
toSchema()override is deprecated — useschemaFieldsgetter instead (removal in v0.5.0)
0.4.1 - 2026-03-12 #
Changed #
- Replaced
shelf_swagger_uiwith built-in Swagger UI served via CDN — zero external UI dependencies - Built-in dark mode support for Swagger UI (system-aware via
prefers-color-scheme)
Added #
SwaggerDocs— internal handler serving the Swagger UI HTML page at/docs- Cross-language parity with TypeScript and Python implementations
0.4.0 - 2026-03-03 #
Removed #
- BREAKING:
useCaseTestHandler— removed from public API and deletedlib/src/core/usecase/usecase_test_handler.dart- Testing now uses direct constructor injection: instantiate the UseCase with its Input, call
validate(),execute(), and assert onoutputdirectly - Barrel export removed from
lib/modular_api.dart
- Testing now uses direct constructor injection: instantiate the UseCase with its Input, call
Added #
GET /openapi.json— returns the full OpenAPI 3.0 specification asapplication/jsonGET /openapi.yaml— returns the full OpenAPI 3.0 specification asapplication/x-yamlOpenApi.openapiJson/OpenApi.openapiYaml— Shelf handlers for raw spec accessOpenApi.jsonToYaml()— zero-dependency JSON-to-YAML converter- Spec is cached at startup alongside Swagger UI (no per-request rebuild)
- 18 new tests: jsonToYaml unit (8), /openapi.json integration (4), /openapi.yaml integration (5), consistency (1)
Changed #
- Updated testing guide (
doc/testing_guide.md) to document the constructor-injection approach - Updated
doc/usecase_implementation.mdanddoc/logger_guide.mdto removeuseCaseTestHandlerreferences - Updated
AGENTS.mdandREADME.mdexamples to reflect the new testing pattern
0.3.0 - 2026-02-26 #
Added #
- Structured JSON Logger — request-scoped logging compatible with Loki, Grafana, Elasticsearch, and any JSON log aggregator
LogLevelenum — 8 RFC 5424 severity levels (emergency..debug) with configurable filteringModularLoggerinterface — 8 logging methods (one per level) with optional structuredfieldsRequestScopedLogger— implementation with injectableStringSinkfor testabilityloggingMiddleware()— Shelf middleware that creates a per-request logger with uniquetrace_idtrace_idauto-generated (UUID v4, zero dependencies) or propagated fromX-Request-IDheaderX-Request-IDresponse header set on every response for client-side correlation- Logger injected as
UseCase.loggerproperty — zero breaking change toexecute()signature - Automatic status-to-level mapping: 2xx→info, 4xx→warning, 5xx→error
- Excluded routes:
/health,/metrics,/docs,/docs/(no request/response logs) logLevelparameter onModularApiconstructor (default:LogLevel.info)useCaseTestHandlernow accepts optionalloggerparameter for test observabilitygenerateUuidV4()— manual UUID v4 usingdart:math Random.secure()(no external deps)- Barrel exports:
LogLevel,ModularLoggerfrompackage:modular_api/modular_api.dart - 68 new tests: logger (27), uuid (6), middleware (23), integration (12)
- Documentation:
doc/logger_guide.md
0.2.0 - 2026-02-24 #
Added #
- IETF Health Check Response Format —
GET /healthnow returnsapplication/health+jsonfollowing draft-inadarei-api-health-check HealthCheckabstract class — implement to register custom health checks (database, cache, queue, etc.)HealthCheckResult— result DTO withstatus,responseTime(ms), and optionaloutputHealthStatusenum —pass,warn,failwith worst-status-wins aggregationHealthService— executes checks in parallel with per-check configurable timeout (default: 5s)HealthResponse— aggregated response withversion,releaseId,checksmap, andhttpStatusCode(200 for pass/warn, 503 for fail)healthHandler()— Shelf handler forGET /healthModularApi.addHealthCheck()— register health checks via method chainingModularApiconstructor now acceptsversionand optionalreleaseIdparametersreleaseIddefaults toversion-debug; override at compile time with--define=RELEASE_ID=x.y.z- Prometheus Metrics Endpoint — opt-in
GET /metricsin Prometheus text exposition format Counter,Gauge,Histogram— pure Dart metric types (zero runtime dependencies)MetricsRegistrar— public API for registering custom metrics viaapi.metricsmetricsEnabled,metricsPath,excludedMetricsRoutesconstructor parameters- Built-in HTTP instrumentation:
http_requests_total,http_request_duration_seconds,http_requests_in_flight,process_start_time_seconds
Changed #
- BREAKING:
GET /healthresponse changed from plaintextokto JSONapplication/health+json - BREAKING:
ModularApiconstructor signature changed — addedversionparameter (defaults to'0.0.0')
0.1.0 - 2026-02-21 #
Changed #
- BREAKING: Stripped to core-only — aligned Dart and TypeScript SDKs at feature parity
- Version bump from 0.0.10 to 0.1.0 (semver: new public API surface)
ModularApiconstructor no longer acceptsoauthServiceparameterModuleBuilder.usecase()no longer acceptsrequiredScopesparameter- Reduced dependencies from 14 to 3 (
shelf,shelf_router,shelf_swagger_ui) - Simplified
doc/INDEX.mdto core-only development flow - Example no longer uses
Env— hardcoded port for simplicity
Removed #
lib/src/auth/—JwtHelper,OAuthService,OAuthClient,PasswordHasher,TokenHasher, all OAuth2 typeslib/src/core/oauth_handler.dart—createOAuthTokenHandlerlib/src/middlewares/apikey.dart—exampleApiKeyMiddlewarelib/src/middlewares/bearer.dart—bearer(),requireAuth()lib/src/utils/env.dart—Envutilitylib/src/utils/get_local_ip.dart—getLocalIp- Dependencies:
http,ffi,dotenv,path,cryptography,bcrypt,dart_jsonwebtoken,crypto,ffigen - Documentation:
auth_implementation_guide.md,authentication_guide.md,http_client_guide.md
Kept (Core) #
UseCase<I, O>,Input,Output— abstract base classesUseCaseException— structured error handlingModularApi,ModuleBuilder— routing and module registrationuseCaseHttpHandler— Shelf HTTP adapteruseCaseTestHandler— unit test helperexampleCorsMiddleware— CORS middlewareOpenApi— automatic Swagger/OpenAPI docs at/docsGET /health— health check endpoint
0.0.10 - 2025-12-23 #
Added #
UseCaseException— Dedicated exception for use case execution errors:statusCode— HTTP status code to return (400, 404, 422, 500, etc.)message— Human-readable error messageerrorCode— Optional error code for client-side handlingdetails— Optional additional details (validation errors, context)- Automatically caught by
useCaseHttpHandlerand converted to appropriate HTTP responses - Allows fine-grained control over error responses instead of generic 500 errors
Changed #
- Updated
useCaseHttpHandlerto catchUseCaseExceptionand return the specified status code - Enhanced error handling with structured error responses
0.0.9 - 2025-12-15 #
Added #
- OAuth2 Client Credentials Support — full OAuth2 implementation:
OAuthService— manages client authentication and JWT token generationOAuthClient— represents registered clients with credentials and scopesTokenRequest,TokenResponse,TokenErrorResponse— OAuth2 data structuresAccessToken— decoded JWT with scope validation methodscreateOAuthTokenHandler— POST /oauth/token endpoint handlerbearer()middleware — validates Bearer tokens and enforces scopesrequireAuth()middleware — marks routes as requiring authentication- HS256 (HMAC-SHA256) JWT signing algorithm
- Scope-based authorization for protected endpoints
- Follows RFC 6749 OAuth2 specification
Changed #
- Exported auth utilities:
JwtHelper,hashPassword,verifyPassword,hashToken - Updated exports to include OAuth2 types and services
Removed #
- Removed
template/folder — Simplified project structure by removing the full example template- Template project has been removed to reduce repository complexity
- Only the minimal
example/folder remains for quick reference - Previous template code included extensive examples, tests, and infrastructure that were redundant
Documentation #
- Added comprehensive OAuth2 guides and examples
- Updated AGENTS.md with OAuth2 usage patterns
- Updated all documentation to remove references to
template/folder - Simplified examples to focus on the minimal
example/implementation - Cleaned up README.md, AGENTS.md, and guides to reflect simplified structure
0.0.8 - 2025-12-04 #
Added #
- Output.statusCode — customizable HTTP status code for UseCase responses:
Outputabstract class now includesint get statusCode => 200;getter- Override in your Output DTO to return custom HTTP status codes (e.g., 201 for created, 400 for bad request)
useCaseHttpHandlerusesoutput.statusCodeinstead of hardcoded 200- Enables proper RESTful responses without modifying the HTTP handler
Changed #
- Output DTOs now use
extends Outputinstead ofimplements Outputto inherit the defaultstatusCodegetter - Example and template Output classes updated to extend Output
Migration Guide #
If you have existing Output DTOs using implements Output, change them to extends Output:
// Before
class MyOutput implements Output { ... }
// After
class MyOutput extends Output { ... }
Alternatively, add the statusCode getter manually: @override int get statusCode => 200;
0.0.7 - 2025-11-04 #
Added #
- httpClient — intelligent HTTP client with automatic authentication:
- Automatic token attachment for authenticated requests (
auth: true) - Auto-capture of access and refresh tokens from login responses
- Transparent retry with refresh token on 401 responses
- Throws
AuthReLoginExceptionwhen refresh fails (signals re-login required) - Per-user token management via
userparameter
- Automatic token attachment for authenticated requests (
- Token (in-memory session) — static class for managing access tokens:
Token.accessToken— current access tokenToken.accessExp— access token expiration timestampToken.isAuthenticated— check if user has valid tokenToken.isExpired— check if current token is expiredToken.clear()— clear session
- TokenVault (persistent storage) — configurable adapter for refresh tokens:
TokenVault.saveRefresh(userId, token)— persist refresh tokenTokenVault.readRefresh(userId)— retrieve refresh tokenTokenVault.deleteRefresh(userId)— delete specific refresh tokenTokenVault.deleteAll()— clear all tokensTokenVault.configure(adapter)— set storage adapter- Includes
MemoryStorageAdapter(default) andFileStorageAdapterwith optional encryption
- JwtHelper — JWT generation and validation utilities:
generateAccessToken({userId, username})— create access tokens (15 min)generateRefreshToken({userId, tokenId})— create refresh tokens (7 days)verifyToken(token)— validate and decode JWTcalculateRefreshTokenExpiration()— get refresh token expiry date- Reads secret from
JWT_SECRETenvironment variable
- PasswordHasher — bcrypt password hashing:
hash(password, {cost = 12})— generate bcrypt hashverify(password, hash)— verify password against hashneedsRehash(hash, {cost})— check if hash needs update
- TokenHasher — SHA-256 token hashing for secure storage:
hash(token)— generate SHA-256 hash (64 hex chars)verify(token, expectedHash)— verify token against hash
- AuthReLoginException — specialized exception for auth flow control
- Comprehensive authentication documentation:
- docs/auth_implementation_guide.md — Complete JWT authentication implementation guide with refresh tokens, including database setup, repository patterns, use cases, and client integration (Flutter & Dart)
- docs/http_client_guide.md — Focused guide for using httpClient in Flutter and pure Dart applications with configuration examples and best practices
- Complete E2E authentication test suite:
template/test/e2e/auth_flow_test.dart— 25+ comprehensive tests covering login, refresh, logout, protected endpoints, concurrent requests, auto-refresh behavior, and re-login exception handling
Changed #
- All documentation translated to English for consistency
0.0.6 - 2025-10-30 #
Added #
- Exported
useCaseTestHandlerin main library export (lib/modular_api.dart) for convenient unit testing of UseCases without starting an HTTP server. - Comprehensive documentation guides:
- AGENTS.md — Framework overview and implementation guide optimized for AI assistants
- docs/USECASE_DTO_GUIDE.md — Complete guide for creating Input/Output DTOs with type mapping reference and advanced examples
- docs/usecase_implementation.md — Step-by-step guide for implementing UseCases with validation, database access, and repository patterns
- docs/TESTING_GUIDE.md — Quick reference for testing UseCases using
useCaseTestHandler
- Complete test suite for template project:
template/test/module1/hello_world_test.dart— 5 tests for HelloWorld use casetemplate/test/module2/sum_case_test.dart— 7 tests for SumCase use casetemplate/test/module2/upper_case_test.dart— 7 tests for UpperCase use casetemplate/test/module3/lower_case_test.dart— 7 tests for LowerCase use casetemplate/test/module3/multiply_case_test.dart— 9 tests for MultiplyCase use case- All 35 tests demonstrate proper usage of
useCaseTestHandlerwith success and failure scenarios
0.0.5 - 2025-10-25 #
Changed #
Envnow initializes automatically on first access (lazy singleton pattern). No need to callEnv.init()explicitly, though it remains available for manual initialization if needed.- .usecase() now trims leading slashes from usecase names to prevent double slashes in registered paths.
0.0.4 - 2025-10-23 #
Changed #
Envbehavior: when a.envfile is not found the library reads values fromPlatform.environment. If a requested key is missing from both sources anEnvKeyNotFoundExceptionis thrown.
0.0.3 - 2025-10-23 #
Added #
- Automatic health endpoint: the server registers
GET /healthwhich responds withokon startup. Implemented inmodular_api.dart(exposes_root.get('/health', (Request request) => Response.ok('ok'));).
0.0.2 - 2025-10-21 #
Changed #
- refactor: improve OpenAPI initialization (now initialized automatically internally)
- Rename middlewares as examples
- rename example project to template
- Add a simple example
0.0.1 - 2025-10-21 #
Added #
- Initial release of modular_api. Main features:
- Use-case centric framework with
UseCase<I extends Input, O extends Output>base classes and DTO helpers (Input/Output). - HTTP adapter
useCaseHttpHandler()to expose UseCases as ShelfHandlers. - Built-in middlewares:
cors()andapiKey()for CORS handling and header-based API key authentication. - OpenAPI/Swagger generation helpers (
OpenApi.init,OpenApi.docs) that infer schemas from DTOtoSchema(). - Utilities:
Env.getString,Env.getInt,Env.setString(.env support via dotenv) andgetLocalIp. - Minimal ODBC
DbClient(DSN-based) exported for database access; example factories and usage provided inexample/(tested with Oracle and SQL Server; seeNOTICEfor provenance). - Example project demonstrating modules and usecases under
example/and unit-test helpers (useCaseTestHandler) undertest/. - Public API exports in
lib/modular_api.dartfor easy consumption.
- Use-case centric framework with