NestJS provides a sweet tool to generate all the boilerplate require to setup REST endpoints. Using the CURD generator Before using the CRUD generator, please install the following package:
npm install @nestjs/mapped-types
In the root of your project, just type in:
nest g resource tasks
Then select a REST API:
? What transport layer do you use? (Use arrow keys)
❯ REST API
GraphQL (code first)
GraphQL (schema first)
Microservice (non-HTTP)
WebSockets
Then choose YES
? Would you like to generate CRUD entry points? (Y/n)
You should have the following output:
CREATE src/tasks/tasks.controller.spec.ts (566 bytes)
CREATE src/tasks/tasks.controller.ts (890 bytes)
CREATE src/tasks/tasks.module.ts (247 bytes)
CREATE src/tasks/tasks.service.spec.ts (453 bytes)
CREATE src/tasks/tasks.service.ts (609 bytes)
CREATE src/tasks/dto/create-task.dto.ts (30 bytes)
CREATE src/tasks/dto/update-task.dto.ts (169 bytes)
CREATE src/tasks/entities/task.entity.ts (21 bytes)
UPDATE src/app.module.ts (312 bytes)
The NestJS CLI has just generated a lot of boilerplate code for you. The generated files including tasks.service.ts, tasks.controller.ts, tasks.module.ts, app.module.ts.
The bootstrap function (in main.ts) is where you're going to instantiate the OpenAPI module.
import { NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { AppModule } from './app.module';
import * as YAML from 'yaml';
import * as fs from 'fs';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors({
origin: 'http://localhost:3000',
});
const config = new DocumentBuilder()
.setTitle('Tasks')
.setDescription('The tasks API description')
.setVersion('1.0')
.addTag('tasks')
.build();
const document = SwaggerModule.createDocument(app, config);
// fs.writeFileSync('./swagger-spec.yaml', YAML.stringify(document));
console.log('document:', document);
SwaggerModule.setup('api', app, document);
const yamlString: string = YAML.stringify(document, {});
console.log('yamlString:', yamlString);
fs.writeFileSync('./swagger-open-api.yaml', yamlString); // generate file swagger-open-api.yaml
const file = fs.readFileSync('./swagger-open-api.yaml', 'utf8');
await app.listen(3001);
}
bootstrap();
Now we can run the following command to start the HTTP server:
npm run start
While the application is running, open your browser and navigate to http://localhost:3000/api. You should see the Swagger UI.
As you can see, the SwaggerModule automatically reflects all of your endpoints. And in the swagger-open-api.yaml, you will see the OpenAPI yaml document as below:
We use rapini with npx, which is pre-bundled with npm since npm version 5.2.0, it's pretty much a standard nowadays.
In the package.json of your Nestjs Project shown as below, you can modify the scripts to meet your own needs:
"scripts": {
...
"rapini:react-query": "npx rapini react-query v4 -pv 1.0.11 -p ./swagger-open-api.yaml -n hello-tom-rapini-demo -o hello-tom-rapini-demo",
"generate:react-query-bundle": "cd hello-tom-rapini-demo && npm install && npm run build",
"pulish:react-query-bundle": "cd hello-tom-rapini-demo && npm config set @tom:registry https://registry.npmjs.org && npm publish",
"remove:react-query-bundle":"mv -f ./hello-tom-rapini-demo ../",
"generate:sdk":"npm run rapini:react-query && npm run generate:react-query-bundle && npm run pulish:react-query-bundle && npm run remove:react-query-bundle"
},
Rapini CLI Arguments & Options can be reference https://github.com/rametta/rapini
"rapini:react-query": "npx rapini react-query v4 -p ./swagger-open-api.yaml -n hello-tom-rapini-demo -pv 1.0.8 -o hello-tom-rapini-demo",
Options:
-p, --path <path> Path to OpenAPI file
-n, --name [name] Name to use for the generated package (default: "rapini-generated-package")
-pv, --package-version [version] Semver version to use for the generated package (default: "1.0.0")
-o, --output-dir [directory] Directory to output the generated package (default: "rapini-generated-package")
-b, --base-url [url] Prefix every request with this url
-r, --replacer [oldString] [newString...] Replace part(s) of any route's path with simple string replacements. Ex: `-r /api/v1 /api/v2` would replace the v1 with v2 in every route
-h, --help display help for command
The script of generate:react-query-bundle:
"generate:react-query-bundle": "cd hello-tom-rapini-demo && npm install && npm run build",
// cd hello-tom-rapini-demo, enter into the react query code dir
// npm install, install npm package
// npm run build, generate js code from ts file
To publish, you must be a user of the npm registry. If you have a user account of the npm registry you publish packge to, use npm login to access your account from your ternimal. The script of "pulish:react-query-bundle":
"pulish:react-query-bundle": "cd hello-tom-rapini-demo && npm config set @tom:registry https://registry.npmjs.org && npm publish",
// npm config set @tom:registry https://registry.npmjs.org, config the registry you publish package to
// npm publish, publish a package to your npm registry
The script of "remove:react-query-bundle",
"remove:react-query-bundle":"mv -f ./hello-tom-rapini-demo ../",
// cd .., back to project directory,
// cd .. && mv -f ./hello-tom-rapini-demo ../, move the react-query-bundle package from the project directory
Then we can run the following command to generate the React Query code with package.json, and publish it your own registry.
npm run generate:sdk
As you can see, the React Query npm package ispublished to the registry automatically.
in the react app project directory app, execute the following:
npm install axios@0.27.2
npm install @tanstack/react-query@4.36.1
The version of axios and @tanstack/react-query must be consistent with the version of axios and @tanstack/react-query in the package of hello-tom-rapini-demo shown as below:
insert the script into the packages shown as below:
"scripts": {
...
"update:sdk": "npm update hello-tom-rapini-demo --save"
},
Used to configure an axios instance so that it is preconfigured to reach to NestJS.
import axios from "axios";
const axiosInstance = axios.create({
baseURL: `http://localhost:3001`
});
export default axiosInstance;
then import and use it like this:
import { initialize } from "hello-tom-rapini-demo";
import axiosInstance from "../rapini/axios-instance";
export default function Example() {
const config = initialize(axiosInstance);
const { useTasksControllerFindOne } = config.queries;
const id = "fake id";
const { isLoading, isError, data } = useTasksControllerFindOne(`${id}`);
if (isLoading) return <div>Loading...</div>;
if (isError) return <div>An error has occurred</div>;
return <div>Test {data?.title}</div>
}
Now, if you go on http://localhost:3000/ in your browser, you should see the message fake title.
If the version of api changes and is pushed to the npm registry, you can execute the following command to update sdk.
npm run update:sdk