I am trying to launch a post Axios request from my front to my back using React framework. When I use my localhost server its works but I use Heroku address, I have an error message (400 bad request) in my console.
I tried to launch other get Axios requests with heroku and it works. So I am wondering that the problem I have is related to Post Axios requests.
I will appreciate your comments
please find below my code (front react):
import React from "react";
import axios from "axios";
const Questions = () => {
const fetchData = async () => {
const response = await axios.post(
"https://formnest-back-certification.herokuapp.com/form/create",
{
title: "nouveau formulaire",
}
);
console.log(response.data);
};
fetchData();
return (
<>
<div>Hello form</div>
</>
);
};
export default Questions;
Here is my code in the back React:
router.post("/form/create", async (req, res) => {
try {
/* const titleForm = await Form.findOne({ title: req.fields.title });
console.log(titleForm);
if (titleForm) {
return res.status(400).json({ error: "title already used" });
} else { */
if (req.fields.title) {
const newForm = new Form({
title: req.fields.title,
/* questions: req.fields.questions,
answers: req.fields.answers, */
});
// Sauvegarde du formulaire
await newForm.save();
return res.json(newForm);
} else {
return res.status(400).json({ error: "Missing parameters" });
}
} catch (e) {
return res.status(400).json({ error: e.message });
}
/* console.log(req.fields); */
/*
res.json({ message: "form created" }); */
});
If you are using express framework for the POST request, you need to using body-parser module then using req.body to retrieve the request data.
req.fields is when you are using express-formidable module.
Related
I'm trying to return data fetched from a private API and display it on a page. My frontend use React JS and my backend use node with Express and Axion. My code work up to the point of returning the data. I get my APi Key and fetch my data but the data is not transferred to my page (Quotes.js).
Backend
app.js
import express from "express";
import { getCase } from "./getCase.js";
const app = express();
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});
app.get("/", function (req, res) {
console.log("app.js call getCase");
res.send(getCase());
//console.log(req);
});
//console.log(Quote.getQuote());
let port = process.env.PORT;
if (port == null || port == "") {
port = 5000;
}
app.listen(port, function () {
console.log(`Server started on port ${port}...`);
});
Backend getCase
import { getToken } from "./nsApiToken.js";
import axios from "axios";
let getData = "";
console.log("begin of getCase");
const getCase = async () => {
let tokenRes = await getToken();
const url =
"https://5156735-sb1.app.netsuite.com/app/site/hosting/restlet.nl?script=860&deploy=1&recordtype=supportcase&id=717986";
try {
const res = await axios.get(url, {
headers: {
Authorization: `Bearer ${tokenRes.data.access_token}`,
},
});
return res;
} catch (error) {
return error;
}
};
export { getCase };
Frontend App.js
import logo from "./logo.svg";
import "./App.css";
import Quotes from "./Quotes.js";
function App() {
return (
<div className="App">
<header className="App-header">
<Quotes />
</header>
</div>
);
}
export default App;
Frontend Quotes.js
import React, { useState, useEffect } from "react";
import axios from "axios";
const Quotes = async () => {
const [text, setText] = useState([]);
const [author, setAuthor] = useState("");
const getQuote = await axios
.get("http://localhost:5000", {
crossdomain: true,
})
.then((res) => res.data)
.then((data) => {
setText({
data: data,
});
console.log("res: ", text);
});
return (
<div>
<button onClick={getQuote}>Generate Quote</button>
<h1>{text}</h1>
<h3>{author}</h3>
</div>
);
};
export default Quotes;
Process:
When I run my process the front execute and call Quotes.js in the axios get process.
app.js then route to home ('/') and call getCase via the app.get.
The getCase process execute get the API token and add it in the headers Authorization. The process initiate the call and fetch the data (if I console.log(res.data.fields.phone) or console.log(res.data.id) I see the correct data.
In my Quotes.js I want to display the data but res.data is empty, yet I get back status 200.
I've been trying to understand why it is not passing the data from the backend to the frontend.
There are several problems and some improvements to be made.
Backend
Problem - You are sending the entire AxiosResponse in the response from your Express app
Just send the data
const getCase = async () =>
(
await axios.get(
"https://5156735-sb1.app.netsuite.com/app/site/hosting/restlet.nl",
{
params: {
script: 860,
deploy: 1,
recordtype: "supportcase",
id: 717986,
},
headers: {
Authorization: `Bearer ${(await getToken()).data.access_token}`,
},
}
)
).data; // Return the data, not the whole response
Problem - getCase() is async
You need to await the result
app.get("/", async (req, res, next) => {
try {
res.json(await getCase());
} catch (err) {
next(err); // send the error to the Express error handler
}
});
Improvement - Creating your own CORS middleware is a waste of time
By the time you create a comprehensive CORS middleware, it will look exactly the same as the standard one so just use that
import express from "express";
import cors from "cors";
const app = express();
express.use(cors());
Frontend
Problem - React function components cannot be async
Function components must return a valid JSX node. Remove async from Quotes
Problem - getQuote should be a function
In order to trigger getQuote by button click, it needs to be a function
// if text is an object, initialise it as one
const [text, setText] = useState({});
const getQuotes = async () => {
try {
// there is no "crossdomain" Axios option
const { data } = await axios.get("http://localhost:5000");
setText({ data });
} catch (err) {
console.error(err.toJSON());
}
};
Problem - the text state is an object
JSX cannot render plain objects, you instead need to reference properties that can be rendered.
<h1>{text.data?.some?.property}</h1>
No idea what your response object looks like so this is just generic advice
The reason why this is not working is for two reasons. Firstly, res.data is not an asynchronous function. And since you are doing await, you can just get data. Secondly, you need to make your API calls and setState in the useEffect hook or else it would just end up in an infinite rerender situation. You just have to do the following and it should work:
useEffect(() => {
const fetchData = async () => {
const {data} = await axios
.get('http://localhost:5000', {
crossdomain: true
})
setText(data)
}
fetchData()
}, [])
The component renders the error state just fine, but the exception is displayed as uncaught in the console and a dialogue is displayed in next dev on the browser. Is there a way to handle expected errors to squelch this behavior?
import { useMutation, gql } from "#apollo/client";
import { useEffect } from "react";
const CONSUME_MAGIC_LINK = gql`
mutation ConsumeMagicLink($token: String!) {
consumeMagicLink(token: $token) {
token
member {
id
}
}
}
`;
export default function ConsumeMagicLink({ token }) {
const [consumeMagicLink, { data, loading, error }] =
useMutation(CONSUME_MAGIC_LINK);
console.log("DATA", data, "loading:", loading, "error:", error);
useEffect(() => {
try {
consumeMagicLink({ variables: { token } });
} catch (e) {
console.log(e);
}
}, []);
var text = "Link has expired or has been used previously";
if (data) text = "SUCCESS: REDIRECTING";
if (loading) text = "Processing";
if (error) text = "Link has expired or has been used previously";
return (
<div>
<h2>{text}</h2>
</div>
);
}
Console Results:
Error Displayed in Browser:
The error is from the client instead of the mutation so your try-catch cannot catch it. To handle this you can add the error handling to the client, for example:
const errorLink = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors)
graphQLErrors.forEach(({ message, locations, path }) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
),
);
if (networkError) console.log(`[Network error]: ${networkError}`);
});
const httpLink = new HttpLink({
uri: "some invalid link"
});
const client = new ApolloClient({
link:from([httpLink,errorLink]),
cache: new InMemoryCache()
})
And as you got authorization error, I suggest you check your headers.
You can find additional information and examples of this approach here:
enter link description here
I have a React Native app using Axios.
Im trying to authenticate the user and then set the authorization header from the response but im getting a weird order of execution.
The setClientToken is not being called before the code after it to do a get request is to be called. ie this is what i get logged:
Loggin in....
Authenticating...
Getting Recipes...
Auth... undefined
Done.
... [Error: Request failed with status code 401] //getRecipes call
Setting token
So you see setting token is done last and that means every axios after that will work but not the recipe.js call.
//app.js
async componentDidMount() {
console.log("Loggin in....");
await LogIn(getUser().username, getUser().password);
console.log("Done.");
}
render () {
//Recipe component rendered.
}
//recipesApi.js
export function getRecipes(category, offset, count) {
console.log("Getting Recipes...");
const url = `search?category=${category}¤tPage=${offset}&pageSize=${count}`;
console.log("Auth...", APIKit.defaults.headers.common["Authorization"]);
return APIKit.get(getUrl(url));
}
//user.js
import APIKit, { setClientToken } from "./apiKit";
export default async function LogIn(email, password) {
console.log("Authenticating...");
APIKit.post("/users/authenticate", {
username: email,
password: password,
})
.then((token) => setClientToken(token))
.catch((error) => console.log(error));
}
//APIKit.js
import axios from "axios";
// Create axios client, pre-configured with baseURL
let APIKit = axios.create({
baseURL: "http://192.168.1.4:4000/api",
timeout: 10000,
});
APIKit.interceptors.response.use(function (response) {
return response.data;
});
export const setClientToken = (token) => {
console.log("Setting token...", token.token);
APIKit.interceptors.request.use(
function (config) {
config.headers.Authorization = `Bearer ${token.token}`;
return config;
}, null, { synchronous: true }
);
};
This question already has an answer here:
Fetch error when building Next.js static website in production
(1 answer)
Closed last year.
I created an API in next JS (in the pages/api folder) and I used it on a page in the pages folder.
When I run on the localhost (development stage), the API can be called correctly. But when I deploy to Vercel there is an error during build.
This is my code when i call the API which is in the pages/api folder
export const getStaticProps = async () => {
const baseUrlDribble = 'https://api.dribbble.com/v2';
const baseUrl = process.env.NODE_ENV === 'production' ?
'https://jovanka-samudra.vercel.app/api' : 'http://localhost:3000/api';
const resShots = await fetch(`${baseUrlDribble}/user/shots?access_token=${process.env.TOKEN_DRIBBLE}&page=1&per_page=9`);
const shots = await resShots.json();
const resResult = await fetch(`${baseUrl}/projects`);
const result = await resResult.json();
const projects = result.data.projects;
return {
props: {
shots,
projects,
},
revalidate: 1,
}
}
This is the API code to retrieve data from database (pages/api/projects folder)
import ProjectService from "#services/ProjectService";
import connectDB from "#utils/connectDB";
import projectValidator from "#validators/project";
import ClientError from '#exceptions/ClientError';
const handler = async (req, res) => {
const projectService = new ProjectService();
if (req.method === 'GET') {
try {
const projects = await projectService.getProjects();
return res.status(200).json({
success: true,
length: projects.length,
data: {
projects
}
});
} catch (error) {
return res.status(500).json({
success: false,
message: error.message,
});
}
} else if (req.method === 'POST') {
...
}
return res.status(404).json({
success: false,
message: 'Method not alowed'
});
}
export default connectDB(handler);
services/ProjectService folder
import InvariantError from '#exceptions/InvariantError';
import NotFoundError from '#exceptions/NotFoundError';
import Project from '#models/Project';
class ProjectService {
async getProjects() {
const projects = await Project.find().sort({ 'createdAt': -1 });
return projects;
}
...
}
export default ProjectService;
You should not fetch an internal API route from getStaticProps — instead, you can write the fetch code in API route directly in getStaticProps.
https://nextjs.org/docs/basic-features/data-fetching/get-static-props#write-server-side-code-directly
I'm running selenium tests for a react app, and I'm trying to stub my axios (XHR) requests. Ithink I'm close but seems like there's something missing. I'm running polly l - listening on localhost:3000 - and then my test looks like this:
import { Polly } from '#pollyjs/core'
import XHRAdapter from '#pollyjs/adapter-xhr'
import LocalStoragePersister from '#pollyjs/persister-local-storage';
import webdriver from 'selenium-webdriver'
const { By, Key, until } = webdriver
Polly.register(XHRAdapter)
Polly.register(LocalStoragePersister);
describe('Loggin in', () => {
const polly = new Polly('Sign In', {
adapters: ['xhr'],
persister: 'local-storage'
});
const { server } = polly;
polly.configure({
persisterOptions: {
'local-storage': {
key: '__pollyjs__'
}
}
});
server.get("http://localhost:3000/dashboard").passthrough()
server.get('http://localhost:3000/api/users/me').intercept((req, res) => {
res.status(200);
res.json({});
});
server.put('http://localhost:3000/api/users/login').intercept((req, res) => {
res.status(200);
res.json({});
});
it('renders correctly', async() => {
var chromeCapabilities = webdriver.Capabilities.chrome();
var chromeOptions = {
//'args': ['--headless']
'args': ['--auto-open-devtools-for-tabs']
};
chromeCapabilities.set('chromeOptions', chromeOptions);
const driver = new webdriver.Builder().withCapabilities(chromeCapabilities).build();
jasmine.Ajax.stubRequest('/dashboard').andReturn({
"status": 200
});
await driver.get('http://localhost:3000/dashboard')
await driver.getCurrentUrl().then((url) => {
expect(url).toEqual("http://localhost:3000/dashboard")
})
await polly.stop();
driver.quit()
})
})
So the idea here is that "/dashboard" should be passed through and not be intercepted at all, while the api requests (/api/users/meand /api/users/login) should be stubbed by polly. What happens is that when landing on /dashboard I get a 404 back and polly seem to not pass it through at all. Have I got it completely wrong here?
Cannot GET /dashboard