I'm creating a project that uses NestJs for the backend part and React for the frontend part. I would like to add users but there is an error that prevented it. When I make the request using Postman it works fine, but when I try it through the front, it sends a 431 error. I'm using redux/toolkit for sending requests. I'm using http://localhost:3001/. I tried to add a "start": "nest start -- --max-http-header-size=80000" for backend and frontend, but it didn't help me. Attached a request-response screen:
Frontend request
import { createApi, fetchBaseQuery } from "#reduxjs/toolkit/query/react";
import { CreateUserRequest } from "../dto/create-user-request.dto";
import { User } from "../models/User";
export const usersApi = createApi({
reducerPath: "usersApi",
baseQuery: fetchBaseQuery({
baseUrl: "/users",
}),
endpoints: (build) => ({
createUser: build.mutation<User, CreateUserRequest>({
query: (createUserRequest) => ({
url: "/",
method: "POST",
body: createUserRequest,
}),
}),
}),
});
export const { useCreateUserMutation } = usersApi;
backend main.ts
import { ValidationPipe } from '#nestjs/common';
import { NestFactory } from '#nestjs/core';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors();
app.useGlobalPipes(new ValidationPipe())
await app.listen(3000);
}
bootstrap();
users.controller.ts
import { Body, Controller, Post } from '#nestjs/common';
import { CreateUserRequest } from './dto/request/create-user-request.dto';
import { UserResponse } from './dto/response/user-response.dto';
import { UsersService } from './users.service';
#Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) { }
#Post()
async createUser(
#Body() createUserRequest: CreateUserRequest
): Promise<UserResponse> {
return this.usersService.createUser(createUserRequest)
}
}
Related
I created an Express.js Back-End that runs on port 4000. Also React (Vite) app runs on port 5173. I try to make some axios requests to my Back-End. Eventhough the URL looks wrong on DevTools when I make any request from my home page, it is still able to hit the Back-End and fetch the data (I can log the request on the Back-End console). But when I try to make a request from another page such as "127.0.0.1:5173/quiz", the request URL also includes "quiz". That's why I get 404.
So it shows "http://127.0.0.1:5173/quiz/api/quiz/:quizId"
But it needs to be "http://127.0.0.1:4000/api/quiz/:quizId"
But like I said, it works when I make a request on home page:
"http://127.0.0.1:5173/api/quiz" - This works, and fetches the quiz list.
Btw, to solve CORS issues, I tried to add "proxy" on package.json, but it didn't work. Then I add some configurations on vite.config.ts, it worked, but like I said I kept seeing "http://127.0.0.1:5173" on Dev Tools Network tab instead of "http://127.0.0.1:4000".
Here's my vite.config.ts:
import { defineConfig } from "vite";
import react from "#vitejs/plugin-react";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server: {
proxy: {
"/api": {
target: "http://localhost:4000",
changeOrigin: true,
secure: false,
},
},
},
});
Here's my request code
import { useState } from "react";
import { useAuthContext } from "./useAuthContext";
import { useQuizContext } from "./useQuizContext";
import { QuizType, Types as QuizActionTypes } from "../context/quiz/types";
import axios from "axios";
export const useQuiz = () => {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const { state: authState } = useAuthContext();
const { dispatch } = useQuizContext();
const getQuiz = async (id: string) => {
setIsLoading(true);
setError(null);
const queryParams: string[] = [];
// If it's a logged in user
if (authState.user.token) {
queryParams.push(`userId=${authState.user._id}`);
}
// If it's a participant who's done with the quiz
if (localStorage.getItem("gifQuizUser")) {
queryParams.push("participantCompleted=true");
}
const uri =
queryParams.length > 0
? `api/quiz/${id}?${queryParams.join("&")}`
: `api/quiz/${id}`;
console.log(uri);
// Fetch & Dispatch
try {
const response = await axios.get(uri);
if (!response.data.error) {
dispatch({
type: QuizActionTypes.GetQuiz,
payload: response.data,
});
setIsLoading(false);
}
} catch (err: any) {
if (err.response.data.error) {
setIsLoading(false);
setError(err.response.data.error);
}
}
};
return { isLoading, error, getQuizzes, getQuiz };
};
Thank you for your time.
I get issues when using #apollo/client: 3.5.10, aws-appsync:4.1.5.
There is my config
import { ApolloClient, ApolloLink, createHttpLink, InMemoryCache } from '#apollo/client';
import { createAuthLink } from 'aws-appsync-auth-link';
import { createSubscriptionHandshakeLink } from 'aws-appsync-subscription-link';
// Config
import { AWS_APPSYNC } from '../config';
const { graphqlEndpoint, region, apiKey } = AWS_APPSYNC;
const auth = {
type: AWS_APPSYNC.authenticationType,
apiKey: apiKey,
};
const httpLink = createHttpLink({ uri: graphqlEndpoint });
const link = ApolloLink.from([
// #ts-ignore
createAuthLink({ graphqlEndpoint, region, auth }),
// #ts-ignore
createSubscriptionHandshakeLink({ graphqlEndpoint, region, auth }, httpLink),
]);
export const client = new ApolloClient({
link,
cache: new InMemoryCache(),
});
and I am using
const {
data: subscription_message_data,
loading: subscription_message_loading,
error: subscription_message_error
} = useSubscription(
SUBSCRIPTION_NEW_MESSAGE, {
variables: { conversationId: conversationId }
});
But I got an error form useSubscription is: "Subscribe only available for AWS AppSync endpoint"
Does anyone have experience with this issue?
Had the exact same issue, and was baffled by this error message.
At the end the issue turned out to be the incorrect property name for the url used in the createAuthLink and createSubscriptionHandshakeLink input objects.
This was the fix that worked for me:
const link = ApolloLink.from([
createAuthLink({ url: graphQLEndpoint, region, auth }),
createSubscriptionHandshakeLink({ url: graphQLEndpoint, region, auth }, httpLink),
]);
I am trying to use this template to learn how to use graphql/apollo/prisma etc.
When I try to start the server, I get a confirmation in the console, but an error in the browser that says: GET query missing.
import "reflect-metadata"
import "dotenv/config"
import { ApolloServerPluginCacheControl, ApolloServerPluginLandingPageDisabled } from "apollo-server-core"
import { ApolloServer } from "apollo-server-express"
import jwt from "express-jwt"
import { buildSchema } from "type-graphql"
import { Container } from "typedi"
import { JWT_AUTH } from "./lib/config"
import { ExpressContext } from "./lib/express"
import { formatResponse } from "./lib/formatResponse"
import { ErrorInterceptor } from "./lib/globalMiddleware"
import { loadPrismaHooks } from "./lib/hooks"
import { loadCurrentUser } from "./lib/loadCurrentUser"
import { loadResolvers } from "./lib/loadResolvers"
import { prisma } from "./lib/prisma"
import { Server } from "./lib/server"
class App extends Server {
constructor() {
super()
this.init().catch((error) => {
this.logger.error(error)
process.exit(1)
})
}
async init() {
await this.setUpDb()
await this.setUpAuth()
await this.setupApollo()
this.start()
}
async setUpDb() {
await prisma.$connect()
loadPrismaHooks()
this.logger.info("DB ready")
}
async setUpAuth() {
this.app
.use(jwt(JWT_AUTH))
.use((err: any, _: any, __: any, next: any) => {
if (err.name === "UnauthorizedError") next()
})
.use(loadCurrentUser)
this.logger.info("Auth ready")
}
async setupApollo() {
const schema = await buildSchema({
container: Container,
resolvers: loadResolvers(),
globalMiddlewares: [ErrorInterceptor],
})
const apolloServer = new ApolloServer({
context: ({ req, res }: ExpressContext) => ({ req, res, prisma }),
formatResponse,
plugins: [ApolloServerPluginCacheControl(), ApolloServerPluginLandingPageDisabled()],
schema,
// playground: true,
// introspection: true
})
await apolloServer.start()
apolloServer.applyMiddleware({ app: this.app })
// I deleted cors: true from the above line
this.logger.info("Apollo setup hello")
}
}
new App()
I have seen other posts describing that cors is no longer needed (not sure what the basis for that is) and also suggesting that I add the playground and introspection arguments to the new ApolloServer. I tried this (as shown in the commented lines), but the playground is not recognised as a valid argument.
Server is defined in the lib folder as:
import "reflect-metadata"
import "dotenv/config"
import * as Sentry from "#sentry/node"
import * as Tracing from "#sentry/tracing"
import chalk from "chalk"
import express from "express"
import morgan from "morgan"
import { IS_PRODUCTION, PORT, SENTRY_DSN } from "./config"
export class Server {
private readonly _app: express.Application
readonly logger: {
info: (message: string) => void
error: (message: string) => void
}
constructor() {
this._app = express()
.use(Sentry.Handlers.requestHandler())
.use(Sentry.Handlers.tracingHandler())
.enable("trust proxy")
.use(
morgan("dev", {
skip: (req) => req.method === "OPTIONS",
stream: { write: (message) => console.log(message + "\n\n") },
}),
)
if (IS_PRODUCTION) {
Sentry.init({
dsn: SENTRY_DSN,
integrations: [
new Sentry.Integrations.Http({ tracing: true }),
new Tracing.Integrations.Express({ app: this._app }),
],
enabled: IS_PRODUCTION,
tracesSampleRate: 1.0,
})
}
this.logger = {
info: this.info,
error: this.error,
}
}
protected error(message: string) {
console.log(`[${chalk.red("ERROR")}] `, message)
}
protected info(message: string) {
console.log(`[${chalk.blue("INFO")}] `, message)
}
protected get app(): express.Application {
return this._app
}
start(): void {
this._app
.use(Sentry.Handlers.errorHandler())
.listen(PORT, () => this.logger.info(`Server started at http://localhost:${PORT}/graphql 🚀` + "\n"))
}
}
The console logs in the terminal print the server started confirmation, but the browser just generates the cannot GET message. I don't know what this message means, to be able to begin to try and figure out how to get to the playground.
Can anyone recommend current instructions for how to configure the server?
the reason for this problem seems to be related to the move to the graphql sandbox environment. If you add localhost555 to the sandbox address bar, the page loads without an error.
I am building a headless wordpress CMS(and using next.js template) .
I was able to successfully deploy to the vercel servers, I then started to add some content, in this case the Wordpress title field.. and this works great on my local server and display the title properly with no errors.. but when I update my git it kills the vercel deployment and I get this error.. I also get this error if I try to use content or dangerouslySetHTML
to clarify, if I remove this, it deploys fine
{ page.title }
Unhandled error during request: TypeError: Cannot read property 'title' of undefined
--
17:01:15.529 | at Page (/vercel/workpath0/.next/serverless/pages/[slug].js:1634:412)
this is my page code [slug].js
import Head from 'next/head'
import Link from 'next/link'
import Container from '../components/container'
import MoreStories from '../components/more-stories'
import HeroPost from '../components/hero-post'
import Intro from '../components/intro'
import Layout from '../components/layout'
import { getAllPagesWithSlug, getAllPagesBySlug } from '../lib/api'
import { CMS_NAME } from '../lib/constants'
import Header from '../components/header'
export default function Page( {page} ) {
return (
<>
<Layout>
<Head>
<title></title>
</Head>
<Header />
<Container>
{ page.title }
</Container>
</Layout>
</>
)
}
export async function getStaticProps({ params }) {
const data = await getAllPagesBySlug(params.slug)
console.log(data)
return {
props: {
page: data.page,
},
}
}
export async function getStaticPaths() {
const allPages = await getAllPagesWithSlug()
return {
//paths: [ { params: { slug: '${node.uri}' } } ],
paths: allPages.edges.map(({ node }) => `/${node.slug}`) || [],
fallback: true,
}
}
this is my query lib/api
const API_URL = process.env.WORDPRESS_API_URL
async function fetchAPI(query, { variables } = {}) {
const headers = { 'Content-Type': 'application/json' }
if (process.env.WORDPRESS_AUTH_REFRESH_TOKEN) {
headers[
'Authorization'
] = `Bearer ${process.env.WORDPRESS_AUTH_REFRESH_TOKEN}`
}
const res = await fetch(API_URL, {
method: 'POST',
headers,
body: JSON.stringify({
query,
variables,
}),
})
const json = await res.json()
if (json.errors) {
console.error(json.errors)
throw new Error('Failed to fetch API')
}
return json.data
}
export async function getAllPagesBySlug($id) {
const data = await fetchAPI(`
{
page(id: "${$id}", idType: URI) {
uri
slug
content
title
featuredImage {
node {
sourceUrl
}
}
}
}
`)
return data
}
I'm trying to render an XML file when pointing to www.example.com/sitemap.xml. Since the project was developed using Next.js, the routing works with the js files stored in the pages directory:
example.com/help -> help.js
example.com/info -> info.js
So, is there any way to achieve this by avoiding accessing the backend?
JS Version
/pages/sitemap.xml.jsx
import React from 'react'
class Sitemap extends React.Component {
static async getInitialProps({ res }) {
res.setHeader('Content-Type', 'text/xml')
res.write(`<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
...
</urlset>`)
res.end()
}
}
export default Sitemap
TS Version
/pages/sitemap.xml.tsx
import { GetServerSideProps } from 'next'
import React from 'react'
const Sitemap: React.FC = () => null
export const getServerSideProps: GetServerSideProps = async ({ res }) => {
if (res) {
res.setHeader('Content-Type', 'text/xml')
res.write(`<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
</urlset>`)
res.end()
}
return {
props: {},
}
}
export default Sitemap
API Version
/pages/api/sitemap.xml.tsx
import type { NextApiRequest, NextApiResponse } from 'next'
import { getAllContentPagesQuery, getAllShopProductsQuery } from './utils/requests'
export default async (req: NextApiRequest, res: NextApiResponse<string>) => {
const pages = await getAllContentPagesQuery()
const products = await getAllShopProductsQuery()
const frontUrl = "https://localhost:3000"
const pagesAndSlugs = [...pages, ...products].map(url => ({
url: `${frontUrl}${'Variations' in url ? '/product/' : '/'}${url.slug}`, // -> /page1, /product/myproduct...
updatedAt: url.updatedAt,
}))
const urls = pagesAndSlugs.map(
({ url, updatedAt }) => `
<url>
<loc>${url}</loc>
<lastmod>${new Date(updatedAt).toISOString()}</lastmod>
</url>
`
)
.join('')
res
.setHeader('Content-Type', 'text/xml')
.setHeader(
'Cache-Control',
'public, s-maxage=10, stale-while-revalidate=59'
)
.status(200)
.send(`<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls}
</urlset>`)
}
:D
Add a static file called sitemap.xml under public directory
public/sitemap.xml
after build you can access www.yourdomain.com/sitemap.xml
Read more on static files: https://nextjs.org/docs/basic-features/static-file-serving
You can use nextjs api routes.
path - pages/api/sitemap.ts
content -
import type { NextApiRequest, NextApiResponse } from 'next';
import { SitemapStream, streamToPromise } from 'sitemap';
async function sitemap(req: NextApiRequest, res: NextApiResponse<string>) {
try {
const smStream = new SitemapStream({
hostname: `https://${req.headers.host}`,
});
// List of posts
const posts: string[] = ['hello'];
// Create each URL row
posts.forEach(() => {
smStream.write({
url: `/post/hello`,
changefreq: 'daily',
priority: 0.9,
});
});
// End sitemap stream
smStream.end();
// XML sitemap string
const sitemapOutput = (await streamToPromise(smStream)).toString();
res.writeHead(200, {
'Content-Type': 'application/xml',
});
// Display output to user
res.end(sitemapOutput);
} catch (e) {
console.log(e);
res.send(JSON.stringify(e));
}
}
export default sitemap;
In robots.txt you can specify
Sitemap: https://[SITE_DOMAIN_HERE]/api/sitemap