POST request freezes after add body-parser - vue.js

I'm build vue app, and for mine app need api request to server from client, also necessary proxy any request.
It's mine vue.config.js
const producer = require('./src/kafka/producer');
const bodyParser = require('body-parser')
module.exports = {
devServer: {
setup: function (app, server) {
app.use(bodyParser.json())
app.post('/send-message', function (req, res) {
producer.send(req.body)
.then(() => {
res.json({result: true, error: null});
})
.catch((e) => {
res.status(500).json({result: false, error: e});
})
});
},
proxy: {
'/v2/order/by-number': {
target: 'http://address-here'
}
}
}
};
As you can see so i'm use body-parser app.use(bodyParser.json())
After I added it, proxying stopped working for me. Request to /send-message freezes after show me error
Proxy error: Could not proxy request path-here from localhost:8080
to http://address-here
Internet searches have not led to a solution.

For a long time, i find a solution:
Add second param jsonParser to app.post()
See full example
const producer = require('./src/kafka/producer');
const bodyParser = require('body-parser')
const jsonParser = bodyParser.json({limit: '1mb'});
module.exports = {
devServer: {
setup: function (app, server) {
app.post('/send-message', jsonParser, function (req, res) {
producer.send(req.body)
.then(() => {
res.json({result: true, error: null});
})
.catch((e) => {
res.status(500).json({result: false, error: e});
})
});
},
proxy: {
'path': {
target: 'http://address-here'
}
}
}
};

Related

Shopify node.js and react.js plugin with vite.js not working

I've created a plugin in shopify using node.js & vite.js.
shopify app create node
After running using npm run dev, it generates a url like this: https://b136-0000-7400-56-bc78-5000-178b-d6f3-6000.ngrok.io/login?shop=shopname.myshopify.com
When I open this link, it start reloading infinite with error
This is my index.js:
import { resolve } from "path";
import express from "express";
import cookieParser from "cookie-parser";
import { Shopify, LATEST_API_VERSION } from "#shopify/shopify-api";
import "dotenv/config";
import applyAuthMiddleware from "./middleware/auth.js";
import verifyRequest from "./middleware/verify-request.js";
const USE_ONLINE_TOKENS = true;
const TOP_LEVEL_OAUTH_COOKIE = "shopify_top_level_oauth";
const PORT = parseInt(process.env.PORT || "8081", 10);
const isTest = process.env.NODE_ENV === "test" || !!process.env.VITE_TEST_BUILD;
Shopify.Context.initialize({
API_KEY: process.env.SHOPIFY_API_KEY,
API_SECRET_KEY: process.env.SHOPIFY_API_SECRET,
SCOPES: process.env.SCOPES.split(","),
HOST_NAME: process.env.HOST.replace(/https:\/\//, ""),
API_VERSION: LATEST_API_VERSION,
IS_EMBEDDED_APP: true,
// This should be replaced with your preferred storage strategy
SESSION_STORAGE: new Shopify.Session.MemorySessionStorage(),
});
// Storing the currently active shops in memory will force them to re-login when your server restarts. You should
// persist this object in your app.
const ACTIVE_SHOPIFY_SHOPS = {};
Shopify.Webhooks.Registry.addHandler("APP_UNINSTALLED", {
path: "/webhooks",
webhookHandler: async (topic, shop, body) => {
delete ACTIVE_SHOPIFY_SHOPS[shop];
},
});
// export for test use only
export async function createServer(
root = process.cwd(),
isProd = process.env.NODE_ENV === "production"
) {
const app = express();
app.set("top-level-oauth-cookie", TOP_LEVEL_OAUTH_COOKIE);
app.set("active-shopify-shops", ACTIVE_SHOPIFY_SHOPS);
app.set("use-online-tokens", USE_ONLINE_TOKENS);
app.use(cookieParser(Shopify.Context.API_SECRET_KEY));
applyAuthMiddleware(app);
app.post("/webhooks", async (req, res) => {
try {
await Shopify.Webhooks.Registry.process(req, res);
console.log(`Webhook processed, returned status code 200`);
} catch (error) {
console.log(`Failed to process webhook: ${error}`);
if (!res.headersSent) {
res.status(500).send(error.message);
}
}
});
app.get("/products-count", verifyRequest(app), async (req, res) => {
const session = await Shopify.Utils.loadCurrentSession(
req,
res,
app.get("use-online-tokens")
);
const { Product } = await import(
`#shopify/shopify-api/dist/rest-resources/${Shopify.Context.API_VERSION}/index.js`
);
const countData = await Product.count({ session });
res.status(200).send(countData);
});
app.post("/graphql", verifyRequest(app), async (req, res) => {
try {
const response = await Shopify.Utils.graphqlProxy(req, res);
res.status(200).send(response.body);
} catch (error) {
res.status(500).send(error.message);
}
});
app.use(express.json());
app.use((req, res, next) => {
const shop = req.query.shop;
if (Shopify.Context.IS_EMBEDDED_APP && shop) {
res.setHeader(
"Content-Security-Policy",
`frame-ancestors https://${shop} https://admin.shopify.com;`
);
} else {
res.setHeader("Content-Security-Policy", `frame-ancestors 'none';`);
}
next();
});
app.use("/*", (req, res, next) => {
const { shop } = req.query;
// Detect whether we need to reinstall the app, any request from Shopify will
// include a shop in the query parameters.
if (app.get("active-shopify-shops")[shop] === undefined && shop) {
res.redirect(`/auth?${new URLSearchParams(req.query).toString()}`);
} else {
next();
}
});
/**
* #type {import('vite').ViteDevServer}
*/
let vite;
if (!isProd) {
vite = await import("vite").then(({ createServer }) =>
createServer({
root,
logLevel: isTest ? "error" : "info",
server: {
port: PORT,
hmr: {
protocol: "ws",
host: "localhost",
port: 64999,
clientPort: 64999,
},
middlewareMode: "html",
},
})
);
app.use(vite.middlewares);
} else {
const compression = await import("compression").then(
({ default: fn }) => fn
);
const serveStatic = await import("serve-static").then(
({ default: fn }) => fn
);
const fs = await import("fs");
app.use(compression());
app.use(serveStatic(resolve("dist/client")));
app.use("/*", (req, res, next) => {
// Client-side routing will pick up on the correct route to render, so we always render the index here
res
.status(200)
.set("Content-Type", "text/html")
.send(fs.readFileSync(`${process.cwd()}/dist/client/index.html`));
});
}
return { app, vite };
}
if (!isTest) {
createServer().then(({ app }) => app.listen(PORT));
}
The app is installing fine but it's getting refreshed again and again due to failed connection to ws (as mentioned in the screenshot). I tried a few things around changing the settings of the HMR but doesn't seem to be connecting.

Nextjs API inaccessiable in production

I am trying to host a NextJS app and everything seems to be working fine locally. I am able to get the data from the site and I can go to the site and see the raw json that is being returned, but when I try to get things working on production the API is completely inaccessible through the browser and through the Axios requests.
The server just returns 500 or Internal Server Error.
I have tried deploying on DigitalOcean App Platform and AWS Amplify, but both fail to connect to the API routes.
I followed this tutorial for the NextJS SSR method that says to build and start using
// next.config.js
const path = require('path')
const Dotenv = require('dotenv-webpack')
require('dotenv').config()
module.exports = {
webpack: (config) => {
config.plugins = config.plugins || []
config.module.rules.push({
test: /\.svg$/,
use: ["#svgr/webpack"]
});
config.plugins = [
...config.plugins,
// Read the .env file
new Dotenv({
path: path.join(__dirname, '.env'),
systemvars: true
})
]
return config
},
sassOptions: {
includePaths: [path.join(__dirname, 'styles')]
}
}
// package.json
...
"scripts": {
"dev": "next dev",
"build": "next build",
"digitalocean": "next start -H 0.0.0.0 -p ${PORT:-8080}",
"start": "next start"
},
...
// api.js
const axios = require('axios')
const {getS3URL} = require('./aws')
require('dotenv').config()
export default async (req, res) => {
const config = {
bucket: 'bucket',
key: 'folder/data.json'
}
const request = await axios.get(await getS3URL(config));
try {
res.status(200).json(JSON.stringify(request.data))
} catch {
res.status(500).json({ error: '500', response })
res.status(400).json({ error: '400', response })
}
}
// frontend.js
...
const getData = async () => {
console.log(`${host}api/daily-trip-stats`)
const trips = await axios.get(`${host}api/daily-trip-stats`)
const routes = await axios.get(`${host}api/daily-route-stats`)
const stops = await axios.get(`${host}api/daily-stops-routes`)
const cleanUp = async (data) => {
return await data.map(fea => fea.properties)
}
return {
routes: await cleanUp(routes.data.features),
trips: await cleanUp(trips.data.features),
stops: await cleanUp(stops.data.features)
}
};
...
Checked the server logs and found that the default region was not being set properly.
var { S3Client, GetObjectCommand, Config} = require('#aws-sdk/client-s3');
import { getSignedUrl } from "#aws-sdk/s3-request-presigner";
const getS3URL = async ({bucket, key}) => {
const client = new S3Client({
region: 'us-east-1' // !!! FORGOT TO SET THE DEFAULT REGION
})
var params = {
Bucket: bucket,
Key: key,
Expires: 60,
ContentType: 'blob'
};
const s3Data = new GetObjectCommand(params);
const url = await getSignedUrl(client, s3Data, { expiresIn: 3600 });
return url
};
module.exports = {getS3URL}

Restarting express server in esbuild

I am trying to create a simple express server with esbuild. These are my code
import express from "express";
const app = express();
const port = 3000;
const stopServer = {
stop: () => {},
};
export const createServer = async () => {
app.get("/", async (req, res) => {
res.json({
first: "Hello",
});
});
const server = app.listen(port, () => {
console.log(`Listening on port: ${port}`);
});
stopServer.stop = () => {
server.close();
};
};
export const stop = () => {
stopServer.stop();
stopServer.stop = () => {};
};
esbuild.config.js
const esbuild = require("esbuild");
const path = require("path");
const restartPlugin = () => {
return {
name: "restart-express",
setup(build) {
build.onEnd(async (res) => {
const { stop, createServer } = await import("../dist/server.js");
stop();
createServer();
});
},
};
};
const run = async () => {
await esbuild.build({
entryPoints: [path.resolve(__dirname, "../src/server.ts")],
outdir: path.resolve(__dirname, "../dist"),
platform: "node",
sourcemap: true,
format: "cjs",
watch: {
onRebuild: async (err, res) => {
if (err) {
console.error(err);
} else {
console.log("There is some change");
}
},
},
plugins: [restartPlugin()],
});
};
run();
Reference for plugin : https://github.com/evanw/esbuild/issues/1258#issuecomment-834676530
If you were to run this application It i will work initially but when you change the code, the server wont get updated even if you refresh the page.
I am not really sure where I am making mistake, Any help please
The problem is that node cache the import("..dist/server.js"), as a result it will never return new module. To solve this problem we will write a function
const purgeAppRequireCache = (buildPath) => {
for (let key in require.cache) {
if (key.startsWith(buildPath)) {
delete require.cache[key];
}
}
};
Which will remove the cache from the node. We can also use this function in this manner. Which solves my problem
const esbuild = require("esbuild");
const path = require("path");
const startPlugin = () => {
return {
name: "startPlugin",
setup(build) {
build.onEnd((res) => {
const serverPath = path.resolve(__dirname, "../dist/server.js");
const { stop } = require("../dist/server.js");
stop();
purgeAppRequireCache(serverPath);
purgeAppRequireCache(path.resolve(__dirname, "../src"));
const { listen } = require("../dist/server");
listen();
});
},
};
};
const run = async () => {
await esbuild.build({
entryPoints: [path.resolve(__dirname, "../src/server.tsx")],
outdir: path.resolve(__dirname, "../dist"),
platform: "node",
sourcemap: true,
format: "cjs",
watch: true,
bundle: true,
plugins: [startPlugin()],
});
};
run();
const purgeAppRequireCache = (buildPath) => {
for (let key in require.cache) {
if (key.startsWith(buildPath)) {
delete require.cache[key];
}
}
};
If you not reload runtime, the global's object and sub require(xxx) maby have same error.
You can use kill and fork cluster when change you code, it's same fast like require(xxx), there have example codes: https://github.com/ymzuiku/bike/blob/master/lib/index.js
If you need see kill and fork cluster example, here's a same feature package, also use esbuild, but it use fs.watch: https://www.npmjs.com/package/bike
Hope there could help you :)
#es-exec/esbuild-plugin-serve or #es-exec/esbuild-plugin-start are two alternative esbuild plugins that you can try. They run your bundles or any command line script for you after building your project (supports watch mode for rebuilding on file changes).
The documentation can be found at the following:
#es-exec/esbuild-plugin-serve
#es-exec/esbuild-plugin-start
Disclaimer: I am the author of these packages.

Nextjs with Expressjs POST route not found

I have recently integrated Expressjs with my Nextjs project and was trying to run as POST request to an API.
But I'm getting an error message
Cannot POST /api/auth/signin/`
I do not receive the same when I make a GET request. Based on the way I integrated ExpressJS from a tutorial, I'm curious if the error message for POST requests stems from not attaching the .post() method to the express server in my server side server file. Does this sound like the source of the issue?
ssr-server.js:
const express = require('express')()
const next = require('next')
const bodyParser = require('body-parser')
// Session Management
const session = require('express-session')
const redis = require('redis');
const redisClient = redis.createClient({
host: process.env.REDIS_HOST || 'localhost',
port: process.env.REDIS_PORT || '6379',
url: process.env.REDIS_URL || ''
});
const redisStore = require('connect-redis')(session);
redisClient.on_connect("error", function(error){
console.error(error);
})
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
console.log("Test")
app.prepare()
.then(() => {
const server = express()
// Session Management
server.use(session({
store: new redisStore({client: redis.RedisClient}),
secret: process.env.SESSION_SECRET,
saveUninitialized: false,
resave: false,
cookie: {
secure: process.env.SESSION_SECURE || false,
httpOnly: true,
}
}))
// Form body parsing
server.use(bodyParser.json())
server.use(bodyParser.urlencoded({extended: true}))
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(3000, (err) => {
if (err) throw err
console.log('> Ready on http://localhost:3000')
})
})
.catch((ex) => {
console.error(ex.stack)
process.exit(1)
})
/api/auth/signin.js:
export default (req, res) => {
if (req.method === 'POST') {
if (res.statusCode = 200){
return res.json({ body: req.body, message: 'Success' })
} else {
return res.json({ message: 'Error on POST'})
}
} else {
return res.json({ message: 'Error' })
}
}

Apollo Server as Nuxt serverMiddleware

I've managed to have a express + Apollo Backend as a serverMiddleware in Nuxtjs.
Everything works fine(auth, cache, datasources, queries, mutations) but now I'm trying to get subscriptions(websockets) running and its giving me a hard time.
I tried this example https://www.apollographql.com/docs/apollo-server/data/subscriptions/#subscriptions-with-additional-middleware but even letting the httpServer listening didn't work.
This is my API file which I require through the nuxt.config.js with '~/api/index' :
module.exports = async () => {
const app = require('express')()
const server = await require("./apollo")() // apollo-server-express w/ typeDefs and resolvers
// apply Apollo to Express
server.applyMiddleware({ app });
console.log(`🚀 ApolloServer ready at ${server.graphqlPath}`);
const httpServer = http.createServer(app);
server.installSubscriptionHandlers(httpServer);
console.log(`🚀 ApolloSubscriptions ready at ${server.subscriptionsPath}`);
return {
path: '/api',
handler: httpServer
}
}
Now my playground is giving me this error: "Could not connect to websocket endpoint ws://192.168.150.98:3000/api/graphql. Please check if the endpoint url is correct."
TypeDefs:
type Subscription {
postAdded: Post
}
type Post {
author: String
comment: String
}
type Query {
posts: [Post]
}
type Mutation {
addPost(author: String, comment: String): Post
}
Resolvers:
Query: {
posts(root, args, context) {
return Posts;
}
}
Mutation: {
addPost(root, args, context) {
pubsub.publish(POST_ADDED, { postAdded: args });
return Posts.add(args);
}
},
Subscription: {
postAdded: {
// Additional event labels can be passed to asyncIterator creation
subscribe: () => pubsub.asyncIterator([POST_ADDED]),
},
}
First question here, thank u in advance! :)
it can also be a little easier
1.
yarn add apollo-server-express
or
npm install apollo-server-express
create file ./server/index.js
import { ApolloServer, gql } from 'apollo-server-express'
// Construct a schema, using GraphQL schema language
const typeDefs = gql`
type Query {
hello: String
}
`
// Provide resolver functions for your schema fields
const resolvers = {
Query: {
hello: () => 'Hello world!',
},
}
const server = new ApolloServer({ typeDefs, resolvers })
export default server
add in your nuxt.config.js
import server from './server'
export default {
// ... your nuxt config stuff
// ...
hooks: {
render: {
async before({
nuxt: {
server: { app },
},
}) {
await server.applyMiddleware({ app, path: '/api' })
console.log(`🚀 ApolloServer ready at /api`)
},
},
}
}
I found a hacky way to achieve it, import the code as a nuxt module:
import http from 'http'
export default function () {
this.nuxt.hook('render:before', async () => {
const server = require("./apollo")()
// apply Apollo to Express
server.applyMiddleware({ app: this.nuxt.renderer.app });
console.log(`🚀 ApolloServer ready at ${server.graphqlPath}`);
const httpServer = http.createServer(this.nuxt.renderer.app);
// apply SubscriptionHandlers to httpServer
server.installSubscriptionHandlers(httpServer);
console.log(`🚀 ApolloSubscriptions ready at ${server.subscriptionsPath}`);
// overwrite nuxt.server.listen()
this.nuxt.server.listen = (port, host) => new Promise(resolve => httpServer.listen(port || 3000, host || 'localhost', resolve))
// close this httpServer on 'close' event
this.nuxt.hook('close', () => new Promise(httpServer.close))
})
}
Tho I'm now using a probably more stable way, using nuxt programmatically!
With hapi instead of express, since express is giving me trouble compiling and not showing the loading-screen(progress of building).
Just use npx create-nuxt-app and create an app with a hapi server backend.
The code with hapi would look like this:
const consola = require('consola')
const Hapi = require('#hapi/hapi')
const HapiNuxt = require('#nuxtjs/hapi')
async function start () {
const server = require('./apollo/index')()
const app = new Hapi.Server({
host: process.env.HOST || '127.0.0.1',
port: process.env.PORT || 3000
})
await app.register({
plugin: HapiNuxt
})
app.route(await require('./routes')())
await server.applyMiddleware({
app,
path: '/graphql'
});
console.log(`🚀 ApolloServer ready at ${server.graphqlPath}`);
await server.installSubscriptionHandlers(app.listener)
console.log(`🚀 ApolloSubscriptions ready at ${server.subscriptionsPath}`);
await app.start()
consola.ready({
message: `Server running at: ${app.info.uri}`,
badge: true
})
}
process.on('unhandledRejection', error => consola.error(error))
start().catch(error => console.log(error))
Maybe i can help somebody
An easier way is to use the getMiddleware() method of Apollo Server Express:
Create a file under ./api/index.js:
const { ApolloServer, gql } = require('apollo-server-express')
const express = require('express')
const typeDefs = gql`
type Query {
hello: String
}
`
const resolvers = {
Query: {
hello: () => 'Hello world!',
},
}
const server = new ApolloServer({ typeDefs, resolvers })
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(server.getMiddleware())
module.exports = app
and then register it in ./nuxt.config.js:
{
// other nuxt config ...
serverMiddleware: [{ path: '/api', handler: '~/api/index.js' }],
}