How do I get the POST data from a nuxtjs server middleware? - express

How do I get the POST data from a nuxtjs server middleware? So far I've managed to do it for GET, but for POST the body is just not there. req.body is undefined.

Add this to nuxt.config.js:
serverMiddleware: [
'~/api/v1/index.js'
],
and then create a file /api/v1/index.js with:
const bodyParser = require('body-parser')
const app = require('express')()
module.exports = { path: '/api', handler: app }
app.use(bodyParser.json());
app.post('/newsletter/subscribe', (req, res) => {
res.json(req.body)
})
Key line is app.use(bodyParser.json())
Even if you are not using express, the code is still very similar.

You do not need to use express because nuxt server already running connect instance for this. Just do this for receiving the POST request:
yourservermiddleware.js -
export default {
path: '/yourservermiddlware',
async handler(req, res, next) {
req.on('data', async (data) => {
let payload = JSON.parse(data.toString())
console.log("received request", payload)
res.end(JSON.stringify('send back what you want'))
next()
})
}
}
P.S. and do not forget to register servermiddleware at the nuxt.config.js

Related

When trying to upload file, axios throw "Request failed with status code 404"

I'm using VueJs3, Multer middleware for file uploading, expressJs. Its pretty new for me, so probably it is just a small mistake and i couldn't find it... After submit in console axios throw this error : "Request failed with status code 404".
And console.log(formData.append("file", this.file)) gives 'undefined'.
Some code from component:
import axios from "axios"
export default {
name: "FileUpload",
data() {
return {
file: "",
message: "",
}
},
methods: {
onSelect() {
const file = this.$refs.file.files[0]
this.file = file
},
async onSubmit() {
const formData = new FormData()
formData.append("file", this.file)
try {
await axios.post("/upload", formData)
this.message = "Upload successfully"
} catch (err) {
console.log(err)
this.message = "Something went wrong :("
}
},
},
}
And back-end:
const express = require("express")
const dotenv = require("dotenv")
const cors = require("cors")
const bodyParser = require("body-parser")
// const db = require("./app/config/db.config")
const multer = require("multer")
dotenv.config()
const app = express()
const port = process.env.PORT || 8080
const upload = multer({
dest: "./uploads",
})
var corsOptions = {
origin: "http://localhost:8081",
}
app.use(cors())
app.use(express.json())
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))
app.post("/upload", upload.single("file"), (req, res) => {
res.json({ file: req.file })
})
app.listen(port, () => console.log(`Server started on port ${port}`))
I been trying to look for solutions in some tutorials, but probably mistake is to small for my rookie eyes at the moment...
Not sure which axios version you are using but you could try switching the versions because some versions handle multipart/form-data differently.
from docs
Starting from v0.27.0, Axios supports automatic object serialization to a FormData object if the request Content-Type header is set to multipart/form-data.
I take this to mean that the header needs to be defined explicitly
const formData = new FormData()
formData.append("file", this.file)
await axios.post("/upload", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
})
you can also try using the postForm method
docs
await axios.postForm("/upload", {file: this.file})
// or with multipart
await axios.postForm("/upload", {'files[]': [this.file]})
I would also recommend that you look at the network panel to see if that header is included, and try sending the request directly with something like postman or insomnia to determine definitively whether the issue is on the front-end or back-end.

BodyParser causes all API requests to hang. Even basic GET requests

As the title says, I simply don't understand what is going on here. Once I include the app.use(bodyParser.json) line, Postman just keeps handing on any request I make. I lost a good portion of the day thinking I messed up my routes.
I narrowed it down to it in this little testing file:
const express = require("express")
const bodyParser = require("body-parser")
const env = require("dotenv");
const app = express()
env.config();
app.use(bodyParser.json);
app.get("/", (req, res) => {
res.status(200).json({
message:"Hello World"
})
});
app.post("/data", (req, res) => {
req.status(200).json({
message: req.body
})
});
app.listen(process.env.PORT, ()=>{
console.log(`Server listening at port ${process.env.PORT}`);
})
Can anyone tell me what is happening and how I can fix it?
You need to call JSON body parser as a function (with brackets):
app.use(bodyParser.json());
There is another bug in the post method "data", You should call status from "res" object:
app.post("/data", (req, res) => {
res.status(200).json({
message: req.body
})
});

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' }],
}

Here-API 401 : "Invalid app_id app_code combination"

I am using an Angular front-end with a Nodejs backend. Im currently proxying all my front-end requests through my express server. However when I make my http request to the Here API I am rejected due to an invalid combination of app_id and app_code.
angular service
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http'
import { HttpParams } from '#angular/common/http'
#Injectable({
providedIn: 'root'
})
export class GetReqPlaces {
constructor(private http: HttpClient) { }
getPlaces(wLong,sLat,eLong,nLat){
// let obj = {params: {westLong: wLong, southLat: sLat, eastLong:eLong, northLat:nLat }};
let params = new HttpParams().set("westLong" , '-97.783').set("southLat", '30.231').set( "eastLong" , '-97.740').set("northLat", '30.329');
return this.http.get( 'api/find/places', { params : params}).subscribe(res=>console.log(res))
}
}
server.js
const express = require("express")
const bodyParser = require("body-parser")
const cors = require("cors")
const path = require("path")
const app = express();
const request = require("request")
const environment= require('./keys')
app.use(cors());
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
let reqPath = __dirname.substring(0,__dirname.length-7)
app.use(express.static(path.join(reqPath, '/dist/angular-places-search')));
app.get('/api/find/places', (req, res) => {
let appId = environment.environment.appId;
let appCode = environment.environment.appCode;
let URL= `https://places.cit.api.here.com/places/v1/discover/search?app_id={${appId}}&app_code={${appCode}}&in=${req.query.westLong},${req.query.southLat},${req.query.eastLong},${req.query.northLat}&pretty`;
console.log(URL)
request(URL, function (error, response, body) {
let data={
body:body,
};
console.log(error,response)
res.send(data);
});
});
app.get('/test', (req, res) => res.send('Well this route was a hit! Bada....tsss'));
// CATCH ALL
app.get('*', (req, res) => {
res.sendFile(path.join(reqPath, 'dist/angular-places-search/index.html'));
});
app.listen(4000, () => console.log(`Express server running on port 4000`));
Before this I was running into CORS and request issues but I think I sorted those out. Based on my research on this same error code (In the context of the framework that Im working in), people overwhelmingly suggest to wait for tokens to register with Here API. Waiting two days is enough I think, still doesnt work. Then there is the very popular solution of just scratching the Here freemium and starting a new project, which I did, and which did not solve my issue. Very few things I have 100% certainty on but I did copy my keys correctly and the URL path built is according to the required Here syntax.
If anyone has any insight you will be my Hero, and also the catalyst for my continued learning :D. Happy Sunday!
In addition the incoming message I get through express is :
method: 'GET',
path: '/places/v1/discover/search?app_id=%notmyid%7D&app_code=%normycode%7D&in=-97.783,30.231,-97.740,30.329&pretty'
However i dont know why it is setting the app_id=% instead of using {}, when i console log the URL it is correct, with my app_id and app_code
The %7D is the url encoded value of the symbol } (urlencoding) which is done by most libraries. For using the HERE API you should not enclose the app_id/app_code between {}. They should be provided directly as strings, check the examples

How to pass data from VUEX Store to serverMiddleware API?

Is it possible to pass data from Vuex Store to serverMiddleware in Nuxt.js?
async SET_DATA({commit}, payload) {
await this.$axios.$post('/api', { data: payload.data})
commit('SET_DATA', payload.data)
}
In nuxt.config
serverMiddleware: [
{ path: '/api', handler: '~/api/index' }
]
Then how do I access the data in api/index.js ?
export default function (req, res, next) {
// Get data from Store here
next()
}
Solution to my problem was found with bodyParser. Using app.use(bodyParser.json()).
The only way I found is;
readFile & writeFile functions.
In nuxt.config
modules: ['~/api/api.js'],
In api/api.js
I use this method, because of servermiddleware causes bug when you try to build app.
module.exports = function (moduleOptions) {
//Add middleware only with `nuxt dev` or `nuxt start`
var fs = require('fs');
// Save file from env or vuex anything comes with this
fs.writeFile('envTransfer.txt', JSON.stringify(this.options.env), function (err) {
if (err) throw err;
console.log('Saved!');
});
// Then call addServermiddleware
//Add middleware only with `nuxt dev` or `nuxt start`
if (this.options.dev || this.options._start) {
this.addServerMiddleware('~/api/index.js')
}
}
In the part api/index.js ( node & express )
const fs = require('fs');
const express = require('express');
const app = express()
....
let content="";
fs.readFile('envTransfer.txt', function(err, data) {
if (err) throw err;
content = data;
var obj = JSON.parse(content);
// do it what ever you want
app.get('/', (req, res, next) => {
// res.send('API root')
})
// export the server middleware
module.exports = {
path: '/api',
handler: app
}
});