Nextjs api "pages/api" doesn't work on vercel server - reactjs

Hello guys may you help me?
I'm trying to configure my fake API to create some personal projects but in my case, the method using the /pages/api folder only works for me in localhost when I deploy to the server on Vercel the project can't find my endpoints.
In my case I'm using the src/ folder method to develop my app and I don't know if this structure can cause problems with api folder.
One thing that I tried and worked is deploying to vercel using the api folder at the root of the application (out of /src folder) but the api stop working on localhost.
This structure works on localhost but doesn't work on server:
├───public/
├───src/
├───api/
├───pages/
...
next.config.js
package.json
This structure works on server but doesn't work on localhost:
├───api/
├───public/
├───src/
├───pages/
...
next.config.js
package.json
This is the method that I'm using to get data:
AXIOS API:
import axios from 'axios'
const api = axios.create({
baseURL: '/api/'
})
export default api
SWR HOOK:
import api from 'src/services/api'
import useSWR from 'swr'
function SwrFetchHook<Data = any, Error = any>(url: string) {
const { data, error } = useSWR<Data, Error>(url, async url => {
const response = await api.get(url)
return response.data
})
return { data, error }
}
export default SwrFetchHook
SWR callback:
const { data } = SwrFetchHook<INavItem[]>('categories')
I hope that I could explain, my question here is how is the best way to work with this feature because the /src folder is common to use with nextjs but I don't know if this is the real problem with the api folder.
Thanks!

Not 100% sure if this is the same issue. I had this warning in my build phase:
warn - Statically exporting a Next.js application via `next export` disables API routes. This command is meant for static-only hosts, and is not necessary to make your application static.
Make sure you are using the correct build command in out package.json scripts.
I'm my case:
"next build && next export" needed to be changed to "build": "next build"
Note: I removed && next export
This disabled the static export feature and allowed the use of pages/api when running yarn start note: yarn start relies on the build script within Vercel's build pipeline. So do not override the default settings unless it is needed.
Also normal Node/JS projects you can define a source folder in the scripts area ie "start": "<SOME_COMMAND> ./src"....but Next.js does this automatically so I do not think having an src file is the issue. I too have an src file in my project and it is a very common way (preferred way) of organizing your JS project. You shouldn't have to touch this if you are using next.

I tried deploying my app on digital ocean and it worked cuz vercel was not providing a server. I was not able to call my api from POSTMAN as well. Deployed it on digitalOcean and then it ran a server just like my localhost.

Related

Change all api calls URL react when in production

I would like to know if it is possible to alter all the api calls made from my react app to my backend server. I used to have the static files to sit around in my project root directory, so when I made an api call with axios like await axios.get('/api/my-endpoint') it all worked fine and my requests were translated to GET https://www.example-url.com/api/my-endpoint. But now I am migrating to AWS EC2 and decided to serve static files from AWS S3. So now since the api is in a remote server all my api calls are broken. I need to replace all api calls to https://www.another-example-url.com/api/.... I know I can set the new URL in an environment variable, but that would force me to manually alter all of the api URLs in my front-end codebase. I would not be very happy to do this, since there are almost a thousand of them.
I tried to set the axios baseURL like so:
import axios from "axios";
const instance = axios.create({
baseURL: "www.another-example-url.com"
});
export default instance;
but then all the requests were translated to GET https://www.example-url.com/www.another-example-url.com/api/my-endpoint
Is there a lazy way of doing this? Or do I have to manually alter them all?
You can easily set this using "proxy" field in package.json file of client side. Just add following line
...
"proxy": "https://www.another-example-url.com",
...
edit: I almost forgot that you were asking for production build. So react-amazing-proxy is an alternate to create-react-app proxy which can have feature to use proxy in production build.
Another lazy way, if you are familiar with docker, would be to Dockerize your development built.

locally host firebase backend with react frontend together, for debugging

I am building a react website with firebase functions backend.
I'm using firebase serve to locally host the node.js backend that I connect to my react code through express API endpoints, and I am using react-scripts start to test my react frontend app.
all my get requests in my react app use /some endpoint to communicate with my firebase localserver. But they are running on different ports. firebase serves it on localhost:5000 while react live server hosts it at localhost:3000.
I tried many things and couldn't get any useful way to make this work. I at last added my react project as a subfolder in my firebase project and made the hosting public path at firebase.json to my react build directory. It works now but I always have to run npm run build on my react app on every change, to make it compile my app into the build directory, which is painfully slow.
What is the proper way to do this? debug react app and firebase backend together.
I finally enabled cross-origin-requests on my server using cors module
Serverside code
const cors = require("cors");
app.get("/test", (req, res) => {
return cors()(req, res, async () => {
res.send("working...");
});
});
Serverside code
And then adding a simple config file in the react side, to switch between debugging and deployed testing really helped.
config.js
var domain = "";
// domain = "http://localhost:5000";
export {domain}
then whenever I use apis in react, I simply comment/uncomment the second line to switch between local and deployed testing.
Then whenever I use APIs, I append `domain` before every url in all references, eg fetch requests
import { domain } from "config.js";
fetch(domain + "/int-search", ...
Then it worked fine running both the firebase backend and the react application on localhost, using firebase serve and npm start for my react app.

How to deploy Next.js app without Node.js server?

I was hoping to deploy a Next.js app with Laravel API. I had developed React apps with CRA and in those I used the API server to serve the index.html of the CRA as the entry point of the app.
But in Next.js, after development I get to know that it needs a Node.js server to serve (which is my bad, didn't notice that). There is an option next export that builds a static representation of the Next.js app and it has an index.html. I am serving the index.html as the entry of the app by my Laravel API. It is serving the page, but just some of the static contents.
What I was hoping to know is it possible to host the aPI and the Next app from a single PHP shared hosting without any node server? If so, how? If not so, what could be the alternatives?
Actually the acepted answer is completly wrong, when you do yarn build and in your package.json is set like "build": "next build && next export", you will get an out folder which all the items in there are used to build without node.js server
Now since you are using laravel, and you use the out folder you will only load half of the page because the routes are not set properly. for that to work you need to edit your next.config.js edit it to
module.exports = {
distDir: '/resources/views',
assetPrefix: '/resources/views',
}
These will set the root directory to the root one in Laravel. now this will work for SPA (single page application) only for the dynamic routes you need to match with a view file for each one that you have in your out folder
For each route that you have you need to create a new "get" route in laravel
Route::get('/', function () {
return require resource_path('views/index.html');
});
Route::get('/contacts', function () {
return require resource_path('views/contacts.html');
});
Route::get('/post/{slug}', function () {
return require resource_path('views/post/[slug].html');
});
Notice that you can pass a wildcard for dynamic routes and they are all gonna work. once you do that and you deploy route out folder inside /resources/views in Laravel it's going to work
Apparently there is no alternative to nodejs server, which is not an option for me currently, so I unfortunately had to abandon next.js and create a CRA app and used as much from the next.js as I could.

Django+React integration

I have Django Rest Framework server running in a terminal and React running in another terminal.
I consume Django API's in React using axios as mentioned below
axios.get('http://localhost:8000/songs/').then(res=>console.log(res)
It work well,in production mode I will hook main.js (created by npm run build, the build file of React) to Django template.
Will this method work in server ? Is it recommended ?
I used to integrate Django + React with this guid (https://www.valentinog.com/blog/drf/) but it do not support some npm packages
create constant.js file in your src react folder that contains all the api endpoints URLs. Like this:
const localhost = 'http://127.0.0.1:8000';
const apiURL = '/api';
export const endpoint = `${localhost}${apiURL}`;
export const productListURL = `${endpoint}/products/`;
export const productDetailURL = id => `${endpoint}/products/${id}/`;
export const addToCartURL = `${endpoint}/add-to-cart/`;
export const orderSummaryURL = `${endpoint}/order-summary/`;
Otherwise, you will have to change the endpoint domain on each request on the front end which can be time consuming.
I deploy apps on actual web-server like; ubuntu droplet on digital ocean, using NGINX.
You can have both react, and Django app deployed on the same droplet. You just need to write extra configurations for nginx. And configure the webserver correctly.
react deployment docs:
https://www.digitalocean.com/community/tutorials/how-to-deploy-a-react-application-to-digitalocean-app-platform
django deployment docs:
https://www.digitalocean.com/community/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-ubuntu-20-04
Once you finish those both tutorials, you will understand how to configure your nginx for MVC.
Yes, it will work. There are several ways to deploy React and Django together.
However, my preferable way to deploy it is to use docker-compose and deploy it with nginx reverse-proxy.
Can you tell more details why some npm packages are not supported in Valentino Gagliardi tutorial?
found useful document
https://cuckootechnologies.medium.com/integrating-django-rest-framework-with-react-js-9bf9d7f051a1
Django will run in one terminal and React will run in another terminal. The API from the Django server will be consumed by React using Axios.

How to inject API server URL when deploying react frontend?

Disclaimer: I am a React noob so perhaps what I am trying to do is not the React Way
I am writing a React front-end that will be deployed to be served statically by some cloud provider, e.g. S3 or Google Storage or whatever. This front-end interacts with several API servers that live somewhere in the cloud, maybe in the same provider, maybe not. Furthermore, while developing the UI or part of it, those servers' addresses might be local or testing instances.
How do I inject the API server(s) URLs into my react application in a flexible so that I can deploy in dev, staging or prod using different addresses?
SOLUTION: I finally ended up using a combination of solutions proposed:
use .env.production and .env.development files (exact names) to store the variable REACT_APP_API_URI = 'host'
this is automatically picked-up by create-react-app's build scaffolding and available in UI code as process.env.REACT_APP_API_URI
Note this somewhat goes against principles from 12 Factor Apps, e.g. storing env variables in files in version control but it does the job ATM.
You can try this:
// http.js
const getBaseUrl = () => {
let url;
switch(process.env.NODE_ENV) {
case 'production':
url = 'https://stackoverflow.com';
break;
case 'development':
default:
url = 'https://google.com';
}
return url;
}
export default axios.create({
baseURL: getBaseUrl(),
});
Using this package https://github.com/toddbluhm/env-cmd you could create an env file for your environment
for example create .env.staging and .env file with this code
// .env.staging file
API_URL=https://staging.url.com/api/
// .env file
API_URL=https://url.com/api/
How to fetch with API_URL from env variable:
fetch(process.env.API_URL)
Then you can just add some extra scripts in your package.json:
{
"scripts": {
"build:staging": "env-cmd .env.staging yarn build",
"build:prod": "env-cmd .env yarn build"
}
}
You can use .env file if the API's are constant for development or production environment. after build you can't change these parameters.
If you want to change the URL after build, add a js file lets say config.js
Include the conf.js in index.html
Add URL in conf.js like
var URL1 = 'https://www.google.com'
You can access the parameter like :
export const {URL1} = window;
You can do that making use of environment variables on the build step for example.
You can use something like .env that allows you to define environment variables and load them on your webpack file for example (assuming you use webpack). But you can really use it with any bundler.
.env file:
API=http://localhost:3000
On your webpack you could make use of the DefinePlugin
example taken from docs: add your API env
...
require('dotenv').config()
...
new webpack.DefinePlugin({
API_ENDPOINT: process.env.API,
PRODUCTION: JSON.stringify(true),
VERSION: JSON.stringify('5fa3b9'),
BROWSER_SUPPORTS_HTML5: true,
TWO: '1+1',
'typeof window': JSON.stringify('object')
});
Anyway, this is just one way. I like this way because it makes my project ready for defining API keys and other useful stuff for different environments.
NOTE: You can even define different .env files for local, staging and production and load the respective one in the webpack depending on the build type.

Resources