nesties 1.1.18 → 1.1.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +157 -1
- package/dist/index.cjs +1224 -78
- package/dist/index.cjs.map +4 -4
- package/dist/index.mjs +1201 -46
- package/dist/index.mjs.map +4 -4
- package/dist/src/abortable-module/abortable.token.d.ts +1 -1
- package/dist/src/api-inject.d.ts +1 -0
- package/dist/src/resolver.d.ts +5 -3
- package/dist/src/utility/collect-info-from-injection-token.d.ts +9 -0
- package/dist/src/utility/create-mutate-inject.d.ts +11 -0
- package/dist/src/utility/index.d.ts +1 -0
- package/dist/src/utility/injection-token-map.d.ts +2 -0
- package/dist/src/utility/param-resolver-swagger-info.type.d.ts +5 -0
- package/dist/src/utility/resolver-swagger-map.d.ts +3 -0
- package/dist/src/utility/swagger-injection-collector.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -676,7 +676,163 @@ This pattern is useful when you want to reuse the same resolver logic in guards,
|
|
|
676
676
|
- `ApiFromResolver(input: ParamResolverInput, extras?: ApiHeaderOptions | ApiQueryOptions)`
|
|
677
677
|
Convenience helper to generate Swagger decorators from resolver inputs.
|
|
678
678
|
|
|
679
|
-
###
|
|
679
|
+
### ApiInject: Making API Contracts Explicit via Dependency Injection
|
|
680
|
+
|
|
681
|
+
In real-world Nest.js applications, many API contracts are *implicit* rather than declared directly on controllers.
|
|
682
|
+
|
|
683
|
+
Common examples include:
|
|
684
|
+
|
|
685
|
+
- Authentication tokens read from headers
|
|
686
|
+
- Tenant or locale identifiers propagated through services
|
|
687
|
+
- Feature flags or internal routing hints extracted from requests
|
|
688
|
+
|
|
689
|
+
These values are often accessed deep inside services, guards, or interceptors—far away from the controller layer where API documentation (Swagger) is usually defined.
|
|
690
|
+
|
|
691
|
+
This creates a long-standing tension:
|
|
692
|
+
|
|
693
|
+
- **Dependency Injection (DI)** knows what a controller *depends on*
|
|
694
|
+
- **Swagger decorators** describe what an API *expects from the client*
|
|
695
|
+
- But the two are traditionally maintained **separately and manually**
|
|
696
|
+
|
|
697
|
+
`@ApiInject()` exists to bridge this gap.
|
|
698
|
+
|
|
699
|
+
---
|
|
700
|
+
|
|
701
|
+
#### What `@ApiInject()` Does
|
|
702
|
+
|
|
703
|
+
`@ApiInject()` is an explicit opt-in decorator that behaves like `@Inject()`, but additionally allows Nesties to **infer API contract metadata from the dependency graph** and attach the corresponding Swagger documentation automatically.
|
|
704
|
+
|
|
705
|
+
In other words:
|
|
706
|
+
|
|
707
|
+
> If a controller explicitly injects something that depends on request parameters,
|
|
708
|
+
> then those parameters are part of the API contract and should be documented.
|
|
709
|
+
|
|
710
|
+
---
|
|
711
|
+
|
|
712
|
+
#### Why This Is Explicit (Not Magic)
|
|
713
|
+
|
|
714
|
+
A key design principle of Nesties is that **API contracts should never be inferred silently**.
|
|
715
|
+
|
|
716
|
+
`@ApiInject()` is intentionally *not* a drop-in replacement for `@Inject()`.
|
|
717
|
+
|
|
718
|
+
By choosing to write:
|
|
719
|
+
|
|
720
|
+
```ts
|
|
721
|
+
@ApiInject()
|
|
722
|
+
private readonly articleService: ArticleService;
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
you are explicitly stating:
|
|
726
|
+
|
|
727
|
+
> “This dependency participates in the public API contract of this controller.”
|
|
728
|
+
|
|
729
|
+
Only dependencies injected via `@ApiInject()` are eligible for automatic Swagger inference.
|
|
730
|
+
Regular `@Inject()` remains side-effect free.
|
|
731
|
+
|
|
732
|
+
This makes the behavior:
|
|
733
|
+
- Predictable
|
|
734
|
+
- Auditable
|
|
735
|
+
- Easy to reason about in code review
|
|
736
|
+
|
|
737
|
+
---
|
|
738
|
+
|
|
739
|
+
#### How Swagger Metadata Is Inferred
|
|
740
|
+
|
|
741
|
+
`@ApiInject()` works in combination with `ParamResolver` and request-scoped providers.
|
|
742
|
+
|
|
743
|
+
At a high level:
|
|
744
|
+
|
|
745
|
+
1. `ParamResolver` declares **how** a value is resolved from a request (header, query, or dynamic logic)
|
|
746
|
+
2. `toRequestScopedProvider()` turns that resolver into an injectable token
|
|
747
|
+
3. Services depend on those tokens through standard Nest.js DI
|
|
748
|
+
4. `@ApiInject()` walks the dependency graph starting from the injected token
|
|
749
|
+
5. Any Swagger metadata declared by resolvers is automatically applied to the controller
|
|
750
|
+
|
|
751
|
+
This ensures that:
|
|
752
|
+
|
|
753
|
+
- Swagger documentation reflects *actual runtime requirements*
|
|
754
|
+
- API headers and query parameters are documented once, at their source
|
|
755
|
+
- Changes to resolver logic propagate consistently across all consumers
|
|
756
|
+
|
|
757
|
+
---
|
|
758
|
+
|
|
759
|
+
#### Example: Documenting Headers via Dependency Injection
|
|
760
|
+
|
|
761
|
+
```ts
|
|
762
|
+
const userTokenResolver = new ParamResolver({
|
|
763
|
+
paramType: 'header',
|
|
764
|
+
paramName: 'x-user-token',
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
const userTokenProvider = userTokenResolver.toRequestScopedProvider();
|
|
768
|
+
|
|
769
|
+
@Injectable()
|
|
770
|
+
class ArticleService {
|
|
771
|
+
constructor(
|
|
772
|
+
@userTokenProvider.inject()
|
|
773
|
+
private readonly userToken: string | undefined,
|
|
774
|
+
) {}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
@Controller('articles')
|
|
778
|
+
export class ArticleController {
|
|
779
|
+
constructor(
|
|
780
|
+
@ApiInject()
|
|
781
|
+
private readonly articleService: ArticleService,
|
|
782
|
+
) {}
|
|
783
|
+
|
|
784
|
+
@Get()
|
|
785
|
+
list() {
|
|
786
|
+
// ...
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
In this example:
|
|
792
|
+
|
|
793
|
+
- `ArticleService` depends on `x-user-token`
|
|
794
|
+
- The controller explicitly opts into API inference via `@ApiInject()`
|
|
795
|
+
- `x-user-token` is automatically documented in Swagger
|
|
796
|
+
- No manual `@ApiHeader()` is required on the controller
|
|
797
|
+
|
|
798
|
+
---
|
|
799
|
+
|
|
800
|
+
#### Design Philosophy
|
|
801
|
+
|
|
802
|
+
`@ApiInject()` is based on a simple idea:
|
|
803
|
+
|
|
804
|
+
> **Dependency Injection already encodes API contracts — we should not ignore that information.**
|
|
805
|
+
|
|
806
|
+
Rather than duplicating knowledge across:
|
|
807
|
+
- controllers (Swagger decorators)
|
|
808
|
+
- services (request access logic)
|
|
809
|
+
- guards and interceptors
|
|
810
|
+
|
|
811
|
+
Nesties treats DI as the single source of truth and lets Swagger documentation follow from it.
|
|
812
|
+
|
|
813
|
+
This approach improves:
|
|
814
|
+
- Consistency between implementation and documentation
|
|
815
|
+
- Maintainability in large codebases
|
|
816
|
+
- Confidence that documented APIs match actual runtime behavior
|
|
817
|
+
|
|
818
|
+
---
|
|
819
|
+
|
|
820
|
+
#### When to Use (and Not Use) `@ApiInject()`
|
|
821
|
+
|
|
822
|
+
Use `@ApiInject()` when:
|
|
823
|
+
- A dependency influences how requests are interpreted
|
|
824
|
+
- A resolver reads from headers or query parameters
|
|
825
|
+
- The dependency represents part of the public API contract
|
|
826
|
+
|
|
827
|
+
Avoid `@ApiInject()` when:
|
|
828
|
+
- The dependency is purely internal
|
|
829
|
+
- It does not depend on request data
|
|
830
|
+
- You do not want it reflected in Swagger documentation
|
|
831
|
+
|
|
832
|
+
Keeping this distinction explicit is what allows Nesties to scale safely in large teams.
|
|
833
|
+
|
|
834
|
+
|
|
835
|
+
### 10. DTO Classes
|
|
680
836
|
|
|
681
837
|
- **BlankReturnMessageDto**: A basic DTO for standardized API responses.
|
|
682
838
|
- **BlankPaginatedReturnMessageDto**: A DTO for paginated API responses.
|