Nuxt.js multiple external API calls with axios proxy - proxy

I'm using multiple external APIs with Nuxt.js and axios, bet I have problems with SSR. When requests are coming from client-side this config is working and proxy is changing url, bet when requests are coming from server (on app page reload) proxy not hitting and axios using baseURL, which is one for all requests.
nuxt.config.js
axios: {
proxy: true
},
proxy: {
'/api/': {
target: process.env.FIRST_API_URL,
pathRewrite: {
'^/api/': ''
}
},
'/api2/': {
target: process.env.SECOND_API_URL,
pathRewrite: {
'^/api2/': ''
}
}
},
Api call in one of Vuex store actions as example:
export const actions: ActionTree<CoreState, RootState> = {
async fetchItems ({ commit }) {
await this.$axios.$get('/api2/items').then((response) => {
commit('SET_ITEMS', response.data)
})
}
}
Action is dispatching from component asyncData method:
async asyncData ({ store }) {
await store.dispatch('items/fetchItems')
}
How to make this work both from client-side and server-side ?

Related

Get POST request body in Vite server.proxy["/api"].configure

I am migrating a project from Webpack to Vite and have run into an issue with proxying requests to one of the endpoints in the MVC.Net backend.
Due to circumstances of the existing project, I need to handle certain calls manually - such as on initial page load of login page, check whether user is already authenticated and redirect to the main page.
I am trying to figure out how to use server.proxy.configure to handle these requests. I am managing fine with the GET requests, but I cannot seem to receive the POST request's body data.
Here is what I have at the moment:
server: {
proxy: {
"/api": {
target: "https://my.local.environment/",
changeOrigin: true,
configure: (proxy: HttpProxy.Server, options: ProxyOptions) => {
proxy.on("proxyReq", (proxyReq, req, res, options) => {
if (req.method === "GET") {
//handle simple get requests. no problems here
//...
} else {
const buffer = [];
console.log("received post request");
proxyReq.on("data", (chunk) => {
console.log("received chunk");
buffer.push(chunk);
});
proxyReq.on("end", () => {
console.log("post request completed");
const body = Buffer.concat(buffer).toString();
const forwardReq = http.request(
{
host: "https://my.local.environment",
port: 443,
method: "POST",
path: req.url,
headers: {
"Content-Type": "application/json",
"Content-Length": data.length,
},
},
(result) => {
result.on("data", (d) => {
res.write(d);
res.end();
});
}
);
forwardReq.on("error", (error) => {
console.log(error);
});
forwardReq.write(data);
forwardReq.end();
});
}
});
},
secure: false,
},
}
}
The problem is that neither proxyReq.on("data", (chunk) => { nor proxyReq.on("end", (chunk) => { ever actually trigger.
Additionally, req.body is undefined.
I have absolutely no idea where I am supposed to be getting the POST request's body.
I ended up finding a different question about the bypass option and this gave me the solution I was looking for. Ended up only handling the specific GET requests that I need to handle locally instead of forwarding to my deployed environment, and everything else gets handled automatically by vite.
"/api": {
target: "https://my.local.environment/",
changeOrigin: true,
agent: new https.Agent({
keepAlive: true,
}),
bypass(req, res, proxyOptions) {
if (req.method === "GET") {
//... here I get what I need and write to the res object
// and of course call res.end()
}
//all other calls are handled automatically
},
secure: false,
},

calling back-end api (laravel) from getServerSideProps() in next js

I am using next js as a front-end and laravel as a back-end. and i want to call back-end (laravel) api from getServerSideProps() method. as shown below
export async function getServerSideProps(context) {
const response = await Axios.request({
url: 'http://localhost:8000/api/event',
method: 'get',
headers: {
Cookie: context.req.headers.cookie,
},
})
const events = response.events
console.log(response)
return {
props: { events },
}
}
so i have also set the cookie but i am getting response with message unauthenticated like below
I just wanted to say a huge THANK YOU to Riaz Kahn for his answer. After a lot of banging my face against a wall this was the answer. I'm going to post a working example of my getServerSideProps function for anyone arriving here in the future. The getUser({[configObject]}) function is just returning a promise from an axios.get('my-user/route', config) call. This is working properly in a Next 13 app using standard pages functionality (not using experimental app directory).
export const getServerSideProps = async (context: any) => {
const {req, res} = context;
try {
const {data: user} = await getUser({
headers: {...req.headers}
});
return {
props: {
fallback: {user}
}
}
} catch (e) {
res.writeHead(302, {Location: '/login'});
res.end();
}
}

Pubsub publish multiple events Apollo Server

I am using Apollo Server and I want to publish 2 events in the row from same resolver. Both subscriptions are working fine but only if I dispatch only one event. If I try to dispatch both, second subscription resolver never gets called. If I comment out the first event dispatch second works normally.
const publishMessageNotification = async (message, me, action) => {
const notification = await models.Notification.create({
ownerId: message.userId,
messageId: message.id,
userId: me.id,
action,
});
// if I comment out this one, second pubsub.publish starts firing
pubsub.publish(EVENTS.NOTIFICATION.CREATED, {
notificationCreated: { notification },
});
const unseenNotificationsCount = await models.Notification.find({
ownerId: notification.ownerId,
isSeen: false,
}).countDocuments();
console.log('unseenNotificationsCount', unseenNotificationsCount);// logs correct value
// this one is not working if first one is present
pubsub.publish(EVENTS.NOTIFICATION.NOT_SEEN_UPDATED, {
notSeenUpdated: unseenNotificationsCount,
});
};
I am using default pubsub implementation. There are no errors in the console.
import { PubSub } from 'apollo-server';
import * as MESSAGE_EVENTS from './message';
import * as NOTIFICATION_EVENTS from './notification';
export const EVENTS = {
MESSAGE: MESSAGE_EVENTS,
NOTIFICATION: NOTIFICATION_EVENTS,
};
export default new PubSub();
Make sure, that you use pubsub from context of apollo server, for example:
Server:
const server = new ApolloServer({
schema: schemaWithMiddleware,
subscriptions: {
path: PATH,
...subscriptionOptions,
},
context: http => ({
http,
pubsub,
redisCache,
}),
engine: {
apiKey: ENGINE_API_KEY,
schemaTag: process.env.NODE_ENV,
},
playground: process.env.NODE_ENV === 'DEV',
tracing: process.env.NODE_ENV === 'DEV',
debug: process.env.NODE_ENV === 'DEV',
});
and example use in resolver, by context:
...
const Mutation = {
async createOrder(parent, { input }, context) {
...
try {
...
context.pubsub.publish(CHANNEL_NAME, {
newMessage: {
messageCount: 0,
},
participants,
});
dialog.lastMessage = `{ "orderID": ${parentID}, "text": "created" }`;
context.pubsub.publish(NOTIFICATION_CHANNEL_NAME, {
notification: { messageCount: 0, dialogID: dialog.id },
participants,
});
...
}
return result;
} catch (err) {
log.error(err);
return sendError(err);
}
},
};
...
It has been a while since this moment.
I have also been a struggle with pubsub not working problem.
and I would like to see your ApolloClient setup code.
I changed my configurations with regard to graphql version and client-side setup.
graphql version : 14.xx.xx -> 15.3.0
const client = new ApolloClient({
uri: 'http://localhost:8001/graphql',
cache: cache,
credentials: 'include',
link: ApolloLink.from([wsLink, httpLink])
});
I want you to clarify link order, especially about httpLink, if you use in your case, "HttpLink is a terminating Link.", according to Apollo official site.
At first, I used link order [httpLink, wsLink].
Therefore, pubsub.publish didn't work.
I hope this answer will help some of graphql users.

Nuxt: Proxy VS Async data VS Reload page

I am building a nuxt application and I am facing an issue with Proxy and Async data.
This is my nuxt.config (simplified)
modules: [
'#nuxtjs/axios',
'#nuxtjs/proxy'
],
axios: {
proxy: true
},
proxy: {
'/api': {
target: 'http://www.example.com',
pathRewrite: {
'^/api': '/'
}
}
}
This is my asyncData code fragment (simplified):
async asyncData ({ store }) {
await store.dispatch('fetchData')
}
Store action fetchData code (simplified):
async fetchData({ commit }) {
const response = await myService.fetchData()
commit('setData', response.data)
}
And at last, myService function (simplified):
fetchData () {
return axios.get('/api/path-to-my-resource')
}
What is expected:
To have the service triggering a call to the proxied endpoint, on both cases: visiting the page through a link or refreshing the page
What is happening:
When I hit refresh on the page, instead of firing a call to the http://www.example.com/path-to-my-resource, I see that it tries to do it at /api/path/to-my-resource and of course it fails. From what I understand, when I refresh the page, the proxy is not working inside the asyncData hook.
I am pretty sure that there is something that I attempt wrongly, but I cannot find it. Can someone point me towards the right direction?
Try something like:
proxy: {
'/api/': { target: 'http://www.example.com', pathRewrite: {'^/api/': ''} }
// ^^^^^ ^^^^^^ ^^
// Note the ending slashes.
// And the rewrite rule.
}
That's how the docs are written:
http (ky) module: https://http.nuxtjs.org/api/#proxy
Axios module: https://axios.nuxtjs.org/options#proxy

Webpack-dev-server not sending requests to external domain via proxy

I'm trying to use the webpack-dev-server proxy configuration to send api requests to an external domain and I can't seem to get it working.
Here's my config:
var path = require('path')
module.exports = {
entry: './client/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'public/assets'),
publicPath: 'assets'
},
devServer: {
contentBase: 'public',
proxy:{
'/api/v1*': {
target: 'http://laravelandwebpack.demo/',
secure: false
}
}
}
}
So, anytime my app makes a request with the uri /api/v1... it should send that request to http://laravelandwebpack.demo.
In my Vue app, I'm using the vue-resource to make the requests and I'm defaulting all requests with the needed uri prefix:
var Vue = require('vue')
Vue.use(require('vue-resource'))
new Vue({
el: 'body',
http: {
root: '/api/v1', // prefix all requests with this
headers:{
test: 'testheader'
}
},
ready: function (){
this.$http({
url: 'tasks',
method: 'GET'
}).then(function (response){
console.log(response);
}, function (response){
console.error(response);
})
}
})
The URL's are being constructed correctly, but they're still pointing to localhost:8080 which is the webpack-dev-server:
I read and re-read the docs for webpack-dev-server and I can't figure out where I have it set up wrong. Any ideas?
#Linus Borg is right.
The URL's are being constructed correctly, but they're still pointing to localhost:8080 which is the webpack-dev-server:
This doesn't matter.
In my case, I want to get http://m.kugou.com/?json=true. And I am using #Vue/cli ^3.0.0-beta.15, maybe you need to modify your code according to situation.
So, here is what I did:
App.vue
axios.get('/proxy_api/?json=true').then(data => {
console.log('data', data)
})
vue.config.js
module.exports = {
devServer: {
proxy: {
// proxy all requests whose path starting with /proxy_api to http://m.kugou.com/proxy_api then remove '/proxy_api' string
'/proxy_api': {
target: 'http://m.kugou.com',
pathRewrite: {
'^/proxy_api': '/'
}
}
}
//or just change the origin to http://m.kugou.com
// proxy: 'http://m.kugou.com'
}
}
I use /proxy_api/?json=true then update it to http://m.kugou.com/?json=true by target and pathRewrite.
'/proxy_api' is used to distinguish if the url should be proxied.
Why would I use /proxy_api? Easy to distinguish.
I got the data from http://m.kugou.com/?json=true while the url in the dev-tool is http://localhost:8080/proxy_api/?json=true.
See? that doesn't matter.
I found a workaround solution for that issue. In my case I need to proxy requests to my backend for any /api/* path, so I'm bypassing any requests which does not starts with api.
Sample:
proxy: {
'*': {
target: 'http://localhost:8081',
secure: false,
rewrite: function(req) {
console.log('rewriting');
req.url = req.url.replace(/^\/api/, '');
},
bypass: function(req, res, proxyOptions) {
if (req.url.indexOf('api') !== 0) {
console.log('Skipping proxy for browser request.');
return '/index.html';
}else{
return false;
}
}
}
}

Resources