🌌 A NestJS module that enables REST API consumers to expand related resources in the payload, similar to GraphQL
Installations
npm install nestjs-expanse
Developer Guide
Typescript
Yes
Module System
CommonJS, ESM
Node Version
20.17.0
NPM Version
10.8.2
Score
63.6
Supply Chain
97.1
Quality
79.8
Maintenance
100
Vulnerability
100
License
Releases
Unable to fetch releases
Contributors
Unable to fetch Contributors
Languages
TypeScript (98.25%)
JavaScript (1.75%)
Developer
Download Statistics
Total Downloads
510
Last Day
1
Last Week
15
Last Month
28
Last Year
510
GitHub Statistics
1 Stars
27 Commits
1 Watching
1 Branches
1 Contributors
Bundle Size
2.15 kB
Minified
883.00 B
Minified + Gzipped
Package Meta Information
Latest Version
1.2.8
Package Id
nestjs-expanse@1.2.8
Unpacked Size
118.70 kB
Size
33.67 kB
File Count
22
NPM Version
10.8.2
Node Version
20.17.0
Publised On
30 Aug 2024
Total Downloads
Cumulative downloads
Total Downloads
510
Last day
0%
1
Compared to previous day
Last week
400%
15
Compared to previous week
Last month
115.4%
28
Compared to previous month
Last year
0%
510
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Peer Dependencies
2
Dev Dependencies
6
🌌 NestJS-Expanse
A NestJS module that enables REST API consumers to expand related resources in the payload, similar to GraphQL.
Motivation
Consider a REST API endpoint /users/1
that returns a user:
1{ 2 "id": 1, 3 "name": "Josephus Miller", 4 "posts": [{ 5 "id": 1, 6 "title": "Review of my new hat", 7 "categories": [{ 8 "id": 1, 9 "name": "Life" 10 }] 11 }], 12 "photos": [{ 13 "id": 1, 14 "url": "/avatar.jpg" 15 }] 16}
Note that the response body will always include posts
and photos
fields, and each post will contain categories
, which might not be necessary for every API consumer use case. While this approach will work well for small projects, as the API grows, you may start noticing performance issues because there is no way to conditionally load or unload related entities.
At this moment, you might think of GraphQL. Although it's a powerful technology, it might not be suitable for every use case due to its complexity. Many large API providers have opted not using GraphQL, instead implementing an expansion system on top of REST (e.g. X and Atlassian). This library aims to solve the problem in a similar way.
To get the same payload as mentioned above, the API consumer can now call the endpoint as follows: /users/1?expand=posts.categories,photos
(or /users/1?expand[]=posts.categories&expand[]=photos
).
Quick Guide
Installation
1npm install nestjs-expanse --save
Entity Decorators
As you decorate your relations with Expandable
, NestJS-Expanse will be able to detect all the available expansions (including the deep ones).
1import { Expandable } from 'nestjs-expanse'; 2 3export class UserEntity { 4 id!: number; 5 name!: string; 6 7 @Expandable(() => PostEntity) 8 posts?: PostEntity[]; 9}
Obtaining Requested Expansions
1import { Expansions } from 'nestjs-expanse'; 2 3@Controller('users') 4export class UserController { 5 constructor(private readonly userService: UserService) {} 6 7 @Get('current') 8 async findCurrent( 9 @Expansions(UserEntity) expansions: string[], 10 ) { 11 // Do whatever you want with `expansions`. Pass it to a service for example: 12 this.userService.findCurrent(expansions); 13 } 14}
Behavior On Error
NestJS-Expanse throws an InvalidExpansionException
if any of the requested expansions are unavailable. This exception class extends BadRequestException and provides a sensible default message, resulting in an HTTP 400 response with a human-readable error by default, which should suffice for most cases. However, you can handle the exception yourself using Nest's exception filters
ORM Integration
One of the library's features is its integration with ORMs, minimizing the need for boilerplate code.
TypeORM
1import { relationsFromExpansions } from 'nestjs-expanse/typeorm'; 2 3class UserService { 4 constructor( 5 @InjectRepository(User) 6 private readonly userRepository: Repository<User>, 7 ) {} 8 9 findAll(expansions: string[] = []) { 10 return this.userRepository.find({ 11 relations: relationsFromExpansions(expansions), 12 }); 13 } 14}
Prisma
1import { includeFromExpansions } from 'nestjs-expanse/prisma'; 2 3class UserService { 4 constructor(private readonly prismaService: PrismaService) {} 5 6 findAll(expansions: string[] = []) { 7 return this.prismaService.user.findMany({ 8 include: includeFromExpansions(expansions), 9 }); 10 } 11}
![Empty State](/_next/static/media/empty.e5fae2e5.png)
No vulnerabilities found.
![Empty State](/_next/static/media/empty.e5fae2e5.png)
No security vulnerabilities found.