Problem with CORS in Nest.js app after deployment on Vercel - node.js

POST request in my Nest.js app not working after deployment on Vercel and I receive CORS error, but cors in my app is enable and when I send GET request all working. When I test my request in postman all working. I am not sure but maybe this error can happen through that I use React Query or problem with vercel and I not right deployment my app.
I receive such error:
Access to XMLHttpRequest at 'https://server-store.vercel.app/api/auth/login' from origin 'https://next-store-liard-three.vercel.app' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
And I enabled CORS such method:
app.enableCors({
origin: ['http://localhost:3000', 'https://next-store-liard-three.vercel.app'],
allowedHeaders: ['Accept', 'Content-Type'],
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
preflightContinue: false,
optionsSuccessStatus: 204,
credentials: true,
});
This is my file vercel.json:
{
"version": 2,
"name": "next-store-server",
"buildCommand": "npm start",
"installCommand": "npm install",
"builds": [
{
"src": "dist/main.js",
"use": "#vercel/node"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "dist/main.js",
"methods": ["GET", "POST", "PATCH", "PUT", "DELETE"]
}
]
}
Also I try enable CORS other way, but it is not help me.
I try enable CORS, such method:
const app = await NestFactory.create(AppModule, { cors: true });
On client I using Next.js, reactQuery and axios for sending request
import axios from "axios";
import { FAuth, IUser } from "./Auth.types";
const AuthService = {
async registration(dto: IUser) {
const { data } = await axios.post<FAuth>(
`${process.env.NEXT_PUBLIC_SERVER_API_URL}/api/auth/registration`,
dto,
);
return data;
},
async login(dto: IUser) {
const { data } = await axios.post<FAuth>(`${process.env.NEXT_PUBLIC_SERVER_API_URL}/api/auth/login`, dto);
return data;
},
};
This my custom useMutation hooks
export const useRegistration = () =>
useMutation((dto: Omit<IUser, "_id">) => AuthService.registration(dto), {
onSuccess: () => {
toast.success("Success", {
theme: "colored",
});
},
onError: (data: any) => {
toast.error(data.response.data.message, {
theme: "colored",
});
},
});
export const useLogin = () =>
useMutation((dto: Omit<IUser, "_id">) => AuthService.login(dto), {
onSuccess: () => {
toast.success("Success", {
theme: "colored",
});
},
onError: (data: any) => {
toast.error(data.response.data.message, {
theme: "colored",
});
},
});

Try to add "OPTIONS" into methods, this worked for me
vercel.json:
{
"version": 2,
"builds": [{ "src": "src/main.ts", "use": "#vercel/node" }],
"routes": [
{
"src": "/(.*)",
"dest": "src/main.ts",
"methods": ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]
}
]
}

Related

NestJS cors error when do request from client on Next.js

Deploy my api project on vercel, but have cors error, when I do http request from a client on Next.js.
My Nest configuration is like in docs.
const app = await NestFactory.create(AppModule, { cors: true });
But I also tried diferent configurations
app.enableCors({
origin: ['http://localhost:3000', 'https://api-filmgen-pearl.vercel.app'],
methods: ['GET', 'POST'],
credentials: true,
});
//or
app.enableCors();
//or
app.enableCors({
credentials: true,
origin: [/localhost:\d+$/, /\.vercel\.app$/, /\.herokuapp\.com$/],
allowedHeaders: 'origin, content-type, accept, application/json',
});
In Postmar, Swagger or local everything is ok.
UPD: My nest config
/** #type {import('next').NextConfig} */
const { i18n } = require('./next-i18next.config');
const nextConfig = {
webpack(config) {
config.module.rules.push({
test: /\.svg$/i,
issuer: /\.[jt]sx?$/,
use: ['#svgr/webpack'],
});
return config;
},
reactStrictMode: true,
compiler: {
styledComponents: true
},
i18n
}
module.exports = nextConfig
In React client app requests are also falling
Since Heroku is a separate domain than Vercel which is also https, use the secure: true and sameSite: 'none' flags in your CORS config.
Next.js mentions in their Caveats section that requests are by-default same-origin. They also provide a guide on how to customize route CORS behavior in the CORS Request Helpers guide.
Add options to vercel config
{
"version": 2,
"builds": [
{
"src": "src/main.ts",
"use": "#vercel/node"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "src/main.ts",
"methods": ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]
}
]
}

Deploy Angular App w/ Proxy for One Route

I have an Angular app w/ a proxy that's working well in local. There's one route that utilizes it with a Node API call.
Node.js
const express = require('express');
const api_service = require('./apiService');
const app = express();
app.get('/getData/:date', (req, res) => {
const date = req.params.date;
api_service.fetchData(...)
.then(response => {
res.json(response)
})
.catch(error => {
res.send(error)
})
})
app.listen(3000, () => {
console.log("Server started in port 3000!");
});
Function in my Angular Service:
fetchData(date: string) {
const requestOptions: Object = {
responseType: 'text',
};
this._http
.get<string>('/api/getData/' + date)
.pipe(
map((data) => {
this.result = data;
})
)
.subscribe((data) => {
this.mediaSource.next(this.result);
if (Object.keys(this.result).length != 0) {
this.history.push(this.result);
}
});
}
proxy-prod.config.json
{
"/api/*": {
"target": "https://example.com",
"secure": false,
"changeOrigin": true,
"logLevel": "debug",
"pathRewrite": { "^/api": "" }
}
}
proxy-local.conf.json
{
"/api/*": {
"target": "http://localhost:3000",
"pathRewrite": {
"^/api": ""
},
"secure": false,
"changeOrigin": true,
"logLevel": "debug"
}
}
angular.json
"serve": {
"builder": "#angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "ui-dev:build",
"proxyConfig": "proxy-local.conf.json"
},
"configurations": {
"production": {
"browserTarget": "ui-dev:build:production",
"proxyConfig": "proxy-prod.config.json"
}
}
},
ng serve works perfectly.
ng serve --prod and ng build --aot --prod --output-hashing none do not.
The error I'm getting is:
headers: d, status: 200, statusText: 'OK', url: 'myexample.com', ok: false
I've tried this in my request but they cause errors too:
const headers = new HttpHeaders().set('Content-Type', 'text/plain; charset=utf-8');
{ headers, responseType: 'text'}
Been searching, testing, and dissecting code for many hours and not sure how to proceed. Can you anyone assist?
Thanks

Trouble connecting express api to nuxt app and mongodb

It's been seriously 10 days since i'm trying to deploy my web app online. i've gone back and forth between heroku and digital ocean. nothing solved. i've asked questions here all i get is a long post with technical terms i' not able to understand. Here's my problem :
i have a nuxt app with express.js in the backend and mongodb as the database. At first i had trouble with configuring host and port for my nuxt app. once i fixed it, anoither problem appeared : i'm not receiving data from the database. i don't if it's something related to database connection or with the express api configuration.
here's my nuxt config
export default {
ssr: false,
head: {
titleTemplate: 'Lokazz',
title: 'Lokazz',
meta: [
{ charset: 'utf-8' },
{
name: 'viewport',
content: 'width=device-width, initial-scale=1'
},
{
hid: 'description',
name: 'description',
content:
'Lokazz'
}
],
link: [
{
rel: 'stylesheet',
href:
'https://fonts.googleapis.com/css?family=Work+Sans:300,400,500,600,700&amp;subset=latin-ext'
}
]
},
css: [
'swiper/dist/css/swiper.css',
'~/static/fonts/Linearicons/Font/demo-files/demo.css',
'~/static/fonts/font-awesome/css/font-awesome.css',
'~/static/css/bootstrap.min.css',
'~/assets/scss/style.scss'
],
plugins: [
{ src: '~plugins/vueliate.js', ssr: false },
{ src: '~/plugins/swiper-plugin.js', ssr: false },
{ src: '~/plugins/vue-notification.js', ssr: false },
{ src: '~/plugins/axios.js'},
{ src: '~/plugins/lazyLoad.js', ssr: false },
{ src: '~/plugins/mask.js', ssr: false },
{ src: '~/plugins/toastr.js', ssr: false },
],
buildModules: [
'#nuxtjs/vuetify',
'#nuxtjs/style-resources',
'cookie-universal-nuxt'
],
styleResources: {
scss: './assets/scss/env.scss'
},
modules: ['#nuxtjs/axios', 'nuxt-i18n','vue-sweetalert2/nuxt', '#nuxtjs/auth-next', "bootstrap-vue/nuxt"],
bootstrapVue: {
bootstrapCSS: false, // here you can disable automatic bootstrapCSS in case you are loading it yourself using sass
bootstrapVueCSS: false, // CSS that is specific to bootstrapVue components can also be disabled. That way you won't load css for modules that you don't use
},
i18n: {
locales: [
{ code: 'en', file: 'en.json' },
],
strategy: 'no_prefix',
fallbackLocale: 'en',
lazy: true,
defaultLocale: 'en',
langDir: 'lang/locales/'
},
router: {
linkActiveClass: '',
linkExactActiveClass: 'active',
},
server: {
port: 8080, // default: 3000
host: '0.0.0.0' // default: localhost
},
auth: {
strategies: {
local: {
token: {
property: "token",
global: true,
},
redirect: {
"login": "/account/login",
"logout": "/",
"home": "/page/ajouter-produit",
"callback": false
},
endpoints: {
login: { url: "/login", method: "post" },
logout: false, // we don't have an endpoint for our logout in our API and we just remove the token from localstorage
user:false
}
}
}
},
};
here's my package.json
{
"name": "martfury_vue",
"version": "1.3.0",
"description": "Martfury - Multi-purpose Ecomerce template with vuejs",
"author": "nouthemes",
"private": true,
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate"
},
"config": {
"nuxt": {
"host": "0.0.0.0",
"port": "8080"
}
},
}
here's my repository.js file
import Cookies from 'js-cookie';
import axios from 'axios';
const token = Cookies.get('id_token');
const baseDomain = 'https://lokazzfullapp-8t7ec.ondigitalocean.app';
export const customHeaders = {
'Content-Type': 'application/json',
Accept: 'application/json'
};
export const baseUrl = `${baseDomain}`;
export default axios.create({
baseUrl,
headers: customHeaders
});
export const serializeQuery = query => {
return Object.keys(query)
.map(key => `${encodeURIComponent(key)}=${encodeURIComponent(query[key])}`)
.join('&');
};
an example of an api call i make locally that works without a problem :
import Repository, { serializeQuery } from '~/repositories/Repository.js';
import { baseUrl } from '~/repositories/Repository';
import axios from 'axios'
const url = baseUrl;
export const actions = {
async getProducts({ commit }, payload) {
const reponse = await axios.get(url)
.then(response => {
commit('setProducts', response.data);
return response.data;
})
.catch(error => ({ error: JSON.stringify(error) }));
return reponse;
},
}
here's my index.js (express file)
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose')
const cors = require('cors');
//const url = 'mongodb://localhost:27017/lokazz'
const url = 'mongodb+srv://lokazz:zaki123456#cluster0.hsd8d.mongodb.net/lokazz?retryWrites=true&w=majority'
const jwt = require('jsonwebtoken')
const con = mongoose.connection
mongoose.connect(url, {useNewUrlParser:true}).then(()=>{
const app = express();
// middlleware
app.use(express.json())
app.use(cors());
//products routes
const products = require('./product/product.router');
app.use('/', products)
//users routes
const users = require('./user/user.router');
app.use('/', users)
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Server started on port ${port}`));
}).catch(error => console.log(error.reason));
con.on('open', () => {
console.log('connected...')
})
My directory structure
the error i get after the api request, meaning it's not receving any data.
ebd1ecd.js:2 TypeError: Cannot read properties of undefined (reading 'username')
at f.<anonymous> (c88240c.js:1)
at f.t._render (ebd1ecd.js:2)
at f.r (ebd1ecd.js:2)
at wn.get (ebd1ecd.js:2)
at new wn (ebd1ecd.js:2)
at t (ebd1ecd.js:2)
at f.In.$mount (ebd1ecd.js:2)
at init (ebd1ecd.js:2)
at ebd1ecd.js:2
at v (ebd1ecd.js:2)
idk if it's a problem with mongodb connection cluster or the api call.

"RESTAPI-INVALIDREQ: (err:FOER0000) Invalid request: reason: invalid patch for uri urlList.json: invalid path: /test/

I have a marklogic database with the following JSON document named urlList.json
{
"test": {
"ip": "10.10.10.10",
"fqdn": "www.test.test"
}
}
I am trying to add to the test object with the marklogic rest API using patch. I am using Node with the request-promise module here is the code
var options = {
method: 'PATCH',
url: 'https://test:8000/v1/documents',
qs: { database: databaseName, uri: 'urlList.json' },
headers:
{
'Content-Type': 'application/json',
Accept: 'application/json'
},
strictSSL: false,
auth: {
user: userName,
pass: password,
sendImmediately: false
},
body: JSON.stringify({
"patch": [
{
"insert": {
"context": "/test/",
"position": "last-child",
"content": { "test": "test"}
}
}
]
})
};
request(options)
.then(results => {
return resolve(results);
})
.catch(err => {
return reject(err);
})
The desired outcome when it runs is
{
"test": {
"ip": "10.10.10.10",
"fqdn": "www.test.test",
"test": "test"
}
}
I get the following error every time I run it
"400 - "{\"errorResponse\":{\"statusCode\":400, \"status\":\"Bad
Request\", \"messageCode\":\"RESTAPI-INVALIDREQ\",
\"message\":\"RESTAPI-INVALIDREQ: (err:FOER0000) Invalid request:
reason: invalid patch for uri urlList.json: invalid path: /test/\"}}""
Here is the body that is sent
"{"patch":[{"insert":{"context":"/test/","position":"last-
child","content":{"test":"test"}}}]}"
A path must select a node. For that reason, a path can't end with a separator. That's what the message attempts to convey.
Does it work with a path of /test?
By the way, MarkLogic provides a Node.js API with support for promises. That might be easier to work with.
Hoping that helps,

Can't make serverside axios api call behind a firewall

I'm looking into axios to use for some node.js http calls to APIs while inside a corp firewall - and i'm falling down at the first hurdle.
I found an example that uses axios to do a server http call below
const axios = require('axios');
const API = 'https://jsonplaceholder.typicode.com';
/* GET api listing. */
router.get('/', (req, res) => {
res.send('api works');
});
// Get all posts
router.get('/posts', (req, res) => {
// Get posts from the mock api
axios.get(`${API}/posts`, { proxy: { host: 'http://proxy.com', port: 8080}})
//axios.get(`${API}/posts`)
.then(posts => {
res.status(200).json(posts.data);
})
.catch(error => {
res.status(500).send(error)
});
});
module.exports = router;
but when i'm behind the firewall i get an error below
// http://localhost:3000/api/posts
{
"code": "ENOTFOUND",
"errno": "ENOTFOUND",
"syscall": "getaddrinfo",
"hostname": "http://proxy.com",
"host": "http://proxy.com",
"port": 8080,
"config": {
"transformRequest": {
},
"transformResponse": {
},
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"headers": {
"Accept": "application/json, text/plain, */*",
"User-Agent": "axios/0.15.3",
"host": "jsonplaceholder.typicode.com"
},
"method": "get",
"proxy": {
"host": "http://proxy.com",
"port": 8080
},
"url": "https://jsonplaceholder.typicode.com/posts"
it works find when i switch to a direct connection to the internet and the proxy setting are what i use for npm - i'm not sure if the final solution will be inside or outside of the firewall but i can't figure out to do this either specific to this api or even globally just for dev.. any help would be appreciated..
I believe that axios just wants the host in the proxy config, not the URL with protocol:
"proxy": {
"host": "proxy.com",
"port": 8080
}

Resources