Next Js and axios instance with base url not working - rest

I have created an axios instance like so for making api request to external server. My project contains a rest api server built with express js, frontend with next js. In dev it all works fine but after publishing to vercel all call to rest server looks like this
https://sandbox.{domain}.com/api.sandbox..com
but it should be
https://api.sandbox.{domain}.com
axios config
const instance = axios.create({
baseURL: `${API_ROOT}/v1`,
withCredentials: true,
});
my next.config.js looks like this
const nextConfig = {
reactStrictMode: false,
swcMinify: true,
images: {
domains: [
"images.unsplash.com",
"images.pexels.com",
],
},
};
I don't really where to look
I tried putting the domain directly as axios baseUrl but did not work.

Related

CORS headers missing when using Axios in NextJS

I'm using a NestJS backend with a NextJS frontend, both hosted seperately.
NestJS Backend
I enabled CORS in the backend as follows:
app.enableCors({ credentials: true, origin: process.env.FRONTEND_URL });
When using cors-test.codehappy.dev to check the CORS headers everything looks good. All headers are present and the access-control-allow-origin header points to the right domain where the front-end is hosted on.
NextJS Frontend
On the NextJS frontend I'm using Axios to make request to the backend (the exact same url as used above).However, when creating a request the preflight request in Chrome is missing all CORS headers. The Axios instance below is imported when a HTTP request is needed.
import Axios from 'axios';
const api = Axios.create({
baseURL: process.env.BACKENDURL,
withCredentials: true
});
export default api;
The error in the console:
The preflight request:
in next.config.js
module.exports = {
//avoiding CORS error, more here: https://vercel.com/support/articles/how-to-enable-cors
async headers() {
return [
{
// matching all API routes
source: "/api/:path*",
headers: [
{ key: "Access-Control-Allow-Credentials", value: "true" },
{ key: "Access-Control-Allow-Origin", value: "*" },
{ key: "Access-Control-Allow-Methods", value: "GET,OPTIONS,PATCH,DELETE,POST,PUT" },
{ key: "Access-Control-Allow-Headers", value: "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" },
]
}
]
},
}

Swagger Tools Production Build Node js

We implemented the swagger in our nodeJs application. As of now we are created production build using webpack and remove the controller and services file.
bin/www.js
const YAML = require('yamljs');
const swaggerTools = require('swagger-tools');
const swaggerDoc = YAML.safeLoad('./swagger.yaml');
// swaggerRouter configuration
const swaggerOptions = {
controllers: path.join(__dirname, '../public/javascripts/controllers'),
useStubs: true, // Conditionally turn on stubs (mock mode)
};
// Initialize the Swagger middleware
swaggerTools.initializeMiddleware(swaggerDoc, (middleware) => {
// Interpret Swagger resources and attach metadata to request - must be first in swagger-tools middleware chain
app.use(middleware.swaggerMetadata());
// validate the security using JWT token
app.use(middleware.swaggerSecurity({
Bearer: auth.verifyToken
}));
// Validate Swagger requests
app.use(middleware.swaggerValidator({
validateResponse: true
}));
// Route validated requests to appropriate controller
app.use(middleware.swaggerRouter(swaggerOptions));
// Serve the Swagger documents and Swagger UI
app.use(middleware.swaggerUi());
});
If we did the same in production build and the swagger middleware expecting the same path to resolve. after build we delete the public folder.
Webpack code
const path = require('path');
const nodeExternals = require('webpack-node-externals');
module.exports = {
entry: {
server: './bin/www',
},
output: {
path: path.join(__dirname, 'dist'),
publicPath: '/',
filename: 'server.build.js',
},
target: 'node',
node: {
// Need this when working with express, otherwise the build fails
__dirname: false, // if you don't put this is, __dirname
__filename: false, // and __filename return blank or /
},
externals: [nodeExternals()],
module: {
rules: [
{
// Transpiles ES6-8 into ES5
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
],
},
};
Pleas help us to create a build using swagger middleware
Thanks in advance
Swagger tools is not a package bundler like webpack. So you will still need to provide it the controller files. Since you are deleting /public from prod then there is no way for swagger tools middleware to get the files it needs. Webpack in this case is basically building a dist from your code which is why it's ok to delete the controller and services.

Why is axios not using the settings in nuxt.config.js?

The axios settings for baseURL and browserBaseURL in nuxt.config.js are not being used by axios and the requests are going to localhost instead.
Here's an extract of nuxt.config.js:
modules: [
'#nuxtjs/axios'
],
axios: {
baseURL: 'http://192.168.8.137:8081',
browserBaseURL: 'http://192.168.8.137:8081'
},
And here's the code in the vue file:
<template>
<v-treeview
v-model="tree"
:open="open"
:items="items"
activatable
item-key="id"
:load-children="listDir"
:active.sync="active"
return-object
>
....
</template>
<script>
import axios from 'axios'
export default {
....
methods: {
async listDir(item) {
// let url = 'http://192.168.8.137:8081/filemanager/ls' // Works fine if hardcoded here
let url = '/filemanager/ls'
await axios.get(url)
.then(....
I think the problem is that I'm using axios.get(url) and not $this.axios.get(url), however my method is being called from a vuetify treeview component and $this is not available.
How do I get hold of $this.axios?
The code works fine if I hardcode the URL into the axios call.
using
import axios from 'axios'
you are importing "clean" axios module.
You need to use axios instance created by nuxt itself.
In component (or in Vue actions) use just (without importing axios)
this.$axios.get(...)
or (convenient $get method returns response data instead response object)
this.$axios.$get(...)

Parse Server - Image files' path returns localhost

I have deployed 2 Ubuntu servers on Azure. First, I have installed the Parse Server and the second, I installed MongoDB. (I have also put a ready db there from my previous server via mongorestore)
Everything works fine! Both Parse Server and MongoDB server. They also communicate well. The thing is, when I run my iOS app, it brings all data correctly, except images. I print the URL of an image and here's what it returned: http://localhost:1337/parse/files/filename.jpeg
If I replace localhost with my server's ip, the image is being fetched nicely!
Here's what I have on my index.js:
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var ParseDashboard = require('parse-dashboard');
var allowInsecureHTTP = true;
var path = require('path');
var databaseUri = process.env.DATABASE_URI || process.env.MONGODB_URI;
if (!databaseUri) {
console.log('DATABASE_URI not specified, falling back to localhost.');
}
var api = new ParseServer({
databaseURI: databaseUri || 'mongodb://IP:27017/db',
cloud: './cloud/main.js',
appId: process.env.APP_ID || 'xxx',
masterKey: process.env.MASTER_KEY || 'xxx', //Add your master key here. Keep it secret!
fileKey: 'xxx',
serverURL: process.env.SERVER_URL || 'http://localhost:1337/parse', // Don't forget to change to https if needed
// Enable email verification
verifyUserEmails: false,
// The public URL of your app.
// This will appear in the link that is used to verify email addresses and reset passwords.
// Set the mount path as it is in serverURL
publicServerURL: 'http://localhost:1337/parse',
});
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
// If you wish you require them, you can set them as options in the initialization above:
// javascriptKey, restAPIKey, dotNetKey, clientKey
var app = express();
// Serve static assets from the /public folder
app.use('/public', express.static(path.join(__dirname, '/public')));
// Serve the Parse API on the /parse URL prefix
var mountPath = process.env.PARSE_MOUNT || '/parse';
app.use(mountPath, api);
// Parse Server plays nicely with the rest of your web routes
app.get('/', function(req, res) {
res.status(200).send('Make sure to star the parse-server repo on GitHub!');
});
// There will be a test page available on the /test path of your server url
// Remove this before launching your app
app.get('/test', function(req, res) {
res.sendFile(path.join(__dirname, '/public/test.html'));
});
var port = process.env.PORT || 1337;
var httpServer = require('http').createServer(app);
httpServer.listen(port, function() {
console.log('parse-server-example running on port ' + port + '.');
});
// Set up parse dashboard
var config = {
"allowInsecureHTTP": true,
"apps": [
{
"serverURL": "http://localhost:1337/parse",
"appId": "xxx",
"masterKey": "xxx",
"appName": "name",
"production": true
}
],
"users": [
{
"user":"username",
"pass":"pass"
}
]
};
var dashboard = new ParseDashboard(config, config.allowInsecureHTTP);
var dashApp = express();
// make the Parse Dashboard available at /dashboard
dashApp.use('/dashboard', dashboard);
// Parse Server plays nicely with the rest of your web routes
dashApp.get('/', function(req, res) {
res.status(200).send('Parse Dashboard App');
});
var httpServerDash = require('http').createServer(dashApp);
httpServerDash.listen(4040, function() {
console.log('dashboard-server running on port 4040.');
});
One thing I noticed at Parse's documentation, is this: When using files on Parse, you will need to use the publicServerURL option in your Parse Server config. This is the URL that files will be accessed from, so it should be a URL that resolves to your Parse Server. Make sure to include your mount point in this URL.
The thing is that this documentation was written having in mind MongoDB, is on the same server with Parse, which in my case isn't.
Any ideas on what to do?
I had to replace the publicServerURL of parse server's config, from http://localhost:1337/parse to http://publicIP:1337/parse and everything worked out great!
If you want to work with files(images) download them, just use publicServerURL as mentioned #Sotiris Kaniras
I would add that the config.json is in ~/stack/parse/config.json. Also here is the difference between serverURL and publicServerURL
Difference between serverURL and publicServerURL on ParseServer
In my case, I needed to add publicServerURL parameter alongside with serverURL because it hasn't existed yet.
So both parameters(publicServerURL & serverURL) are complement, not mutually exclusive, use them both.

Using Grunt to Mock Endpoints

I'm using Yeoman, Grunt, and Bower, to construct a platform for building a frontend independently of a a backend. The idea would be that all of my (AngularJS) controller, services, factories, etc live in this project, and get injected afterwards into my serverside codebase based off the result of grunt build.
My question is:
How can I mock endpoints so that the Grunt server responds to the same endpoints as my (Rails) App will?
At the moment I am using:
angular.module('myApp', ['ngResource'])
.run(['$rootScope', function ($rootScope) {
$rootScope.testState = 'test';
}]);
And then in each of my individual services:
mockJSON = {'foo': 'myMockJSON'}
And on every method:
if($rootScope.testState == 'test'){
return mockJSON;
}
else {
real service logic with $q/$http goes here
}
Then after grunt build, testState = 'test' gets removed.
This is clearly a relatively janky architecture. How can I avoid it? How can I have Grunt respond to the same endpoints as my app (some of which have dynamic params) apply some logic (if necessary), and serve out a json file (possibly dependent on path params)?
I've fixed this issue by using express to write a server that responds with static json.
First I created a directory in my project called 'api'. Within that directory I have the following files:
package.json:
{
"name": "mockAPI",
"version": "0.0.0",
"dependencies": {
"express": "~3.3.4"
}
}
Then I run npm install in this directory.
index.js:
module.exports = require('./lib/server');
lib/server.js:
express = require('express');
var app = express();
app.get('/my/endpoint', function(req, res){
res.json({'foo': 'myMockJSON'});
});
module.exports = app
and finally in my global Gruntfile.js:
connect: {
options: {
port: 9000,
hostname: 'localhost',
},
livereload: {
options: {
middleware: function (connect, options) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app),
require('./api')
];
}
}
},
Then the services make the requests, and the express server serves the correct JSON.
After grunt build, the express server is simply replaced by a rails server.
As of grunt-contrib-connect v.0.7.0 you can also just add your custom middleware to the existing middleware stack without having to manually rebuild the existing middleware stack.
livereload: {
options: {
open: true,
base: [
'.tmp',
'<%= config.app %>'
],
middleware: function(connect, options, middlewares) {
// inject a custom middleware into the array of default middlewares
middlewares.push(function(req, res, next) {
if (req.url !== '/my/endpoint') {
return next();
}
res.writeHead(200, {'Content-Type': 'application/json' });
res.end("{'foo': 'myMockJSON'}");
});
return middlewares;
}
}
},
See https://github.com/gruntjs/grunt-contrib-connect#middleware for the official documentation.
Alternatively you can use the grunt-connect-proxy to proxy everything that is missing in your test server to an actual backend.
It's quite easy to install, just one thing to remember when adding proxy to your livereload connect middleware is to add it last, like this:
middleware: function (connect) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app),
proxySnippet
];
}
grunt-connect-prism is similar to the Ruby project VCR. It provides an easy way for front end developers to record HTTP responses returned by their API (or some other remote source) and replay them later. It's basically an HTTP cache, but for developers working on a Single Page Application (SPA). You can also generate stubs for API calls that don't exist, and populate them the way you want.
It's useful for mocking complex & high latency API calls during development. It's also useful when writing e2e tests for your SPA only, removing the server from the equation. This results in much faster execution of your e2e test suite.
Prism works by adding a custom connect middleware to the connect server provided by the grunt-contrib-connect plugin. While in 'record' mode it will generate a file per response on the filesystem with content like the following:
{
"requestUrl": "/api/ponies",
"contentType": "application/json",
"statusCode": 200,
"data": {
"text": "my little ponies"
}
}
DISCLAIMER: I'm the author of this project.
You can use Apache proxy and connect your REST server with gruntjs.
Apache would do this:
proxy / -> gruntjs
proxy /service -> REST server
you would use your application hitting Apache and angular.js application would think that is talking with itself so no cross domain problem.
Here is a great tutorial on how to set this up:
http://alfrescoblog.com/2014/06/14/angular-js-activiti-webapp-with-activiti-rest/
Just my alternative way that based on Abraham P's answer. It does not need to install express within 'api' folder. I can separate the mock services for certain files. For example, my 'api' folder contains 3 files:
api\
index.js // assign all the "modules" and then simply require that.
user.js // all mocking for user
product.js // all mocking for product
file user.js
var user = function(req, res, next) {
if (req.method === 'POST' && req.url.indexOf('/user') === 0) {
res.end(
JSON.stringify({
'id' : '5463c277-87c4-4f1d-8f95-7d895304de12',
'role' : 'admin'
})
);
}
else {
next();
}
}
module.exports = user;
file product.js
var product = function(req, res, next) {
if (req.method === 'POST' && req.url.indexOf('/product') === 0) {
res.end(
JSON.stringify({
'id' : '5463c277-87c4-4f1d-8f95-7d895304de12',
'name' : 'test',
'category': 'test'
})
);
}
else {
next();
}
}
module.exports = product;
index.js just assigns all the "modules" and we simply require that.
module.exports = {
product: require('./product.js'),
user: require('./user.js')
};
My Gruntfile.js file
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost',
livereload: 35729
},
livereload: {
options: {
open: true,
middleware: function (connect) {
return [
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app),
require('./api').user,
require('./api').product,
];
}
}
}