I am currently learning my way around in NestJS. Now I am experimenting with the Swagger feature. I followed the explanations on the NestJS site and I am getting a nice Swagger page displayed. However, now I am no longer able to use my controller pathes.
Example:
I have a path /api/users that will return a list of user records. After adding the Swagger feature I get the Swagger UI on /api. When I try to request /api/users I also get the swagger UI, this time empty.
When I click the "Try it out" button for the "user" API /users instead of /api/users will be executed, of course with a 404 response.
What am I doing wrong? Please help.
I'm assuming you have set the global prefix of your app to /api. Then you also have to set the base path for swagger accordingly. Also, you should mount your swagger docs to an unused path:
// Set the global prefix for all controllers to /api
app.setGlobalPrefix('api');
const document = SwaggerModule.createDocument(
app,
new DocumentBuilder()
// Set the base path for swagger accordingly
.setBasePath('api')
.build(),
);
// Choose an unused path to mount your swagger module
SwaggerModule.setup('docs', app, document);
// ^^^^^^
I was able to achieve this by below code:
app.setGlobalPrefix("api");
setupSwagger(app);
app.setGlobalPrefix("");
setupSwagger definition:
export const setupSwagger = (app: INestApplication) => {
const options = new DocumentBuilder()
.setTitle(SWAGGER_API_NAME)
.setDescription(SWAGGER_API_DESCRIPTION)
.setVersion(SWAGGER_API_CURRENT_VERSION)
.build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup(SWAGGER_API_ROOT, app, document);
};
Related
I'm new to the Next js and developing the Next js website. I am stuck in multiple authentications with different routes and roles. How can I handle it in the next js?
Frontend: Next js
Backend: Node js with JWT (JSON web token).
Please guide me on what I should use to authenticate.
Thanks in advance.
I am assuming you have done a couple things with my answer below:
you are setting a http only authenticated cookie / signing it, expiring it etc
On api requests, you are validating this cookie
You can create a middleware.ts / .js file on the root of your project, something like the following (note I was using typescript, you can just remove the types if using javascript):
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
const protectedPages = ["/something", "/foo", "/profile"];
export function middleware(request: NextRequest) {
if (protectedPages.find((page) => page === request.nextUrl.pathname)) {
const token = request.cookies.get("YOUR_TOKEN_NAME");
if (!token) {
// send the user back to the sign in / home page or wherever
const url = request.nextUrl.clone();
url.pathname = "/home";
return NextResponse.redirect(url);
}
}
}
You do not need to import this anywhere, just do this, get the cookie and you are done. No Cookie with the name you gave it, show them the door.
Take a read of the docs from if you want to know more, they explain things better than me :) https://nextjs.org/docs/advanced-features/middleware
Can also combine this with the above suggestion with getServerSideProps to pass the data as a prop to the component.
I am making a full-stack web-application using Next JS where I allow the user to create and manage letters (applications) based on pre-defined templates. So when the user successfully creates an application, it is sent to the database (POSTGRES) which is hosted on Supabase. On the home page, the applications created by the user are fetched and displayed in the form of a list. Here on, when the user chooses to preview an application, dynamic routing is put in place where the application IDs work as the dynamic parameter. By using getStaticPaths() to get the route parameters from the database, and then fetching the data for the page from the database based on the application ID in the getStaticProps() method at build time, we render the page. It works seamlessly on localhost but not on Vercel. The interesting part however is,that dynamic routing works on Vercel for past applications for every deployment, that is if the user wants to preview their past applications they can do so without any problem, but when they create an application and then try to preview it, they are prompted with the 404 error. But if I trigger a redeployment either manually or by a commit to the main branch of my repository, the error is fixed for the particular application which was giving the error. `
export const getStaticPaths = async () => {
var APIendpoint;
if (process.env.NODE_ENV === 'development') {
APIendpoint = 'http://localhost:3000/api/fetchApplication'
}
else if (process.env.NODE_ENV === 'production') {
APIendpoint = 'https://templaterepo.vercel.app/api/fetchApplication';
}
const data = await getPaths(APIendpoint)
const paths = data.map((application) => {
return {
params: { id: application.appid.toString() }
}
})
return {
paths,
fallback: 'blocking'
}
}
export async function getStaticProps(context) {
const appID = context.params.id;
var APIendpoint;
if (process.env.NODE_ENV === 'development') {
APIendpoint = 'http://localhost:3000/api/fetchApplicationwithID'
}
else if (process.env.NODE_ENV === 'production') {
APIendpoint = 'https://templaterepo.vercel.app/api/fetchApplicationwithID';
}
let data = await getPageData(APIendpoint, appID);
return {
props: { data }
}
}
Here is the code for the dynamic [id].js page where in I first get the paths based on the application IDs and then in the getStaticProps() function I fetch the data for the page corresponding to the application ID at build time. It works as expected in localhost but in Vercel deployment, even before the functions are executed, I get a 404 error.
Note: Vercel Framework Preset is set to Next.js.
I tried a variety of solutions including adding to and as parameters in the Link component. Also I changed my vercel.json file to the below configuration
`
{
"rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
}
`
But nothing seems to work.
When they create an application and then try to preview it, they are
prompted with the 404 error. But if I trigger a redeployment either
manually or by a commit to the main branch of my repository, the error
is fixed for the particular application which was giving the error.
This is expected, the data necessary for each dynamic page to be built is fetched ONLY at build time. Since you are using getStaticProps, you can implement ISR by adding a revalidate prop in getStaticProps, that way when a page (like a new application) has not been generated at build-time, Next.js will server-render it on first request and then cache it for subsequent requests.
On development mode, both getStaticProps and getStaticPaths run per-request (much like getServerSideProps), that's why you don't have this issue on the dev environment. Reference to this on the docs.
If you decide to implement ISR and want to display a loading UI while the page is being server-rendered, make sure to set fallback: true on getStaticPaths and at component level, you can access the router.isFallback flag to display the loading UI accordingly, otherwise, leave it as you already have with fallback: 'blocking'.
Also, make sure you write the server-side code directly in getStaticProps and getStaticPaths instead of calling your own API endpoints on these functions. This according to the docs.
When I make a GET request without queryparams my backend provides the data no problem, but if I pass any queryparams the request gets rejected.
[Example of Rejection in network tab, status column says CORS ERROR][1]
The fetch being made is this (it's within a react useEffect)
fetch('http://localhost:8000/gems/' + new URLSearchParams({
filters: 'all'
}))
If I remove the + params it works just fine, but removing the trailing slash also causes the issue.
in package.json I have added this
"proxy": "https://localhost:8000/",
The backend view is this (going to overwrite get_queryset to read the params)
class GemViewSet(viewsets.ModelViewSet):
queryset = Gem.objects.all()
serializer_class = GemSerializer
and I've installed the cors app, added the middleware and set
CORS_ALLOW_ALL_ORIGINS = True
If someone could set me on the right track I'd be very grateful.
[1]: https://i.stack.imgur.com/g0dIp.png
I have .env file like
DATABASE_URL="sqlserver://srv:50119;initial catalog=mydb;user=aaa;password=bbb;"
and then schema.prisma like
datasource db {
provider = "sqlserver"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
previewFeatures = ["microsoftSqlServer"]
}
I generate a client using:
npx prisma generate
and then Prisma works great in my express app using:
const prisma = new PrismaClient();
Say I wanted to use a different db for user for multi-tenancy, how can I achieve this? Ideally I'd want to switch the db connection at runtime but it seems that DATABASE_URL is only read during prisma generate and not at runtime so the generated client ends up with a hardcoded db url.
You can use the datasource property to create a new PrismaClient instance and pass a dynamic URL.
datasources
Programmatically overrides properties of the datasource block in the schema.prisma file - for example, as part of
an integration test. See also: Data sources
I serve Swagger on Nestjs with something like
main.ts
*****
const docBuilder = new DocumentBuilder();
const options = docBuilder
.setTitle(process.env.npm_package_name)
.setDescription('WHATEVER')
.setVersion(process.env.npm_package_version)
.addBearerAuth()
.addTag('FOO')
.build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup('api', app, document);
*****
And then, I can access to my Swagger on
http://localhost:PORT/api
http://localhost:PORT/api/#/swagger-ui.html
However, for the environment that I have on production and the requirements of the project I would need this url to be without hashtag, like
http://localhost:PORT/api/swagger-ui.html
Does anyone know how to customise this URL in Nestjs?
Any help would be really appreciated, thanks in advance