Axios request from express app missing arguments - node.js

Im trying to make a POST request to a FacePlusPlus API.
At the moment I'm just running app.js with node, but I keep getting an error .
My axios request inside express app:
axios({
method: "post",
url: "https://api-us.faceplusplus.com/facepp/v3/face/analyze",
headers: {
'Content-Type': "application/json",
},
data: {
'api_key': '<My api key goes here>',
'api_secret': '<My api secret goes here>',
'image_url': 'https://images.pexels.com/photos/220453/pexels-photo-220453.jpeg?w=1260&h=750&auto=compress&cs=tinysrgb'
}
})
.then(res => console.log(res))
.catch(err => console.log(err))
The Response error:
{ Error: Request failed with status code 400
at createError (/Users/Matt/webdev/test/node_modules/axios/lib/core/createError.js:16:15)
at settle (/Users/Matt/webdev/test/node_modules/axios/lib/core/settle.js:18:12)
at IncomingMessage.handleStreamEnd (/Users/Matt/webdev/test/node_modules/axios/lib/adapters/http.js:192:11)
at emitNone (events.js:110:20)
at IncomingMessage.emit (events.js:207:7)
at endReadableNT (_stream_readable.js:1047:12)
at _combinedTickCallback (internal/process/next_tick.js:102:11)
at process._tickCallback (internal/process/next_tick.js:161:9)
config:
{ adapter: [Function: httpAdapter],
transformRequest: { '0': [Function: transformRequest] },
transformResponse: { '0': [Function: transformResponse] },
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
validateStatus: [Function: validateStatus],
headers:
{ Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json',
'User-Agent': 'axios/0.17.1',
'Content-Length': 212 },
method: 'post',
url: 'https://api-us.faceplusplus.com/facepp/v3/face/analyze',
data: '{"api_key":"*** i removed this for question ***","api_secret":"*** i removed this for question ***","image_url":"https://images.pexels.com/photos/220453/pexels-photo-220453.jpeg?w=1260&h=750&auto=compress&cs=tinysrgb"}' }
...
...
data: { error_message: 'MISSING_ARGUMENTS: api_key' } } }
The data is obviously getting, sent, but why does it say missing argument?

Try console logging the api-key through the response and see what you get, since it is telling you it is a missing argument. Your data is a string and not an object should it be like that, just out of curiosity?

Related

Google token endpoint returning unsupported grant type

I'm trying to implement Google Oauth to get information on users who sign in with Google such as their name and profile photo.
I found this react library which seems like it can get me a code when using the flow: 'auth_code' param.
Additionally I've found these Google docs which outline how to exchange a code for an ID token which will have user information.
I can successfully retrieve a code using the react component as shown in this slightly redacted log message from my browser:
{
"code": "4/0AWtgzh4VK3QT85egP0m9Rsau_gND-FPDxpM-cPB7ocxTfNkZSCzFSbE86<redacted suffix>",
"scope": "email profile openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email",
"authuser": "0",
"prompt": "consent"
}
I then send this code to my backend which fires off the following request to the token endpoint as found in the Discovery document, mentioned in the OpenID Google docs:
try {
const resp = await axios.post("https://oauth2.googleapis.com/token", {
code: googleJWT,
client_id: getGoogleClientId(),
client_secret: googleSecret,
redirect_uri: "http://localhost:3000",
grant_type: "authorization_code"
}, {
headers: {
"Content-Type": "application/x-www-form-urlencoded"
}
})
console.log("################## posted", resp)
} catch (e) {
console.log("################## could not post")
console.log(e)
}
However, this results in an error being thrown:
error: 'unsupported_grant_type',
error_description: 'Invalid grant_type: '
even though a grant type of authorization_code is reported as supported by the Discovery document.
For completeness, here's the redacted axios config that gets printed with the above error message:
config: {
transitional: {
silentJSONParsing: true,
forcedJSONParsing: true,
clarifyTimeoutError: false
},
adapter: [Function: httpAdapter],
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
validateStatus: [Function: validateStatus],
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': 'axios/0.26.1',
'Content-Length': 298
},
method: 'post',
url: 'https://oauth2.googleapis.com/token',
data: '{"code":"4/0AWtgzh4VK3QT85egP0m9Rsau_gND-FPDxpM-cPB7ocxTfNkZSCzFSbE86<redacted>","client_id":"221274282648-q9nrm8j61s5cba218qot926vnloua2hb.apps.googleusercontent.com","client_secret":"<redacted>","redirect_uri":"http://localhost:3000","grant_type":"authorization_code"}'
},
Why is google complaining that the provided grant type isn't supported and how can I swap this code for an ID token?

How do I suppress expected Axios error messages when testing error states with react-testing-library?

I'm working on adapting some React code of mine to use #testing-library/react, react-query, and msw to mock network calls that I make using axios.
So far (after some brainbending) I've got it working with this code! (yay!)
The test in question (simplified):
import React from 'react';
import { rest } from 'msw';
import { setupServer } from 'msw/node';
import { screen, waitFor, waitForElementToBeRemoved } from '#testing-library/react';
import { queryCache } from 'react-query';
import userEvent from '#testing-library/user-event';
import Login from '../Login';
import { render, queryClient } from '~/testhelpers/helpers.integration';
// #endregion imports
const server = setupServer(
// ...default setup for successful request; not relevant here
);
beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());
describe('rendering', () => {
describe('error', () => {
it.only('should render error message when request fails', async () => {
server.use(
rest.post(`${API_BASE_URL}api/auth/token`, (req, res, ctx) => {
return res(ctx.status(400), ctx.json('Invalid username or password.'));
})
);
render(<Login />);
const usernameInput = screen.getByLabelText('Username');
const passwordInput = screen.getByLabelText('Password');
const submitInput = screen.getByRole('button', { name: 'Login' });
userEvent.type(usernameInput, 'testUsername');
userEvent.type(passwordInput, 'testPassword');
userEvent.click(submitInput);
await waitFor(() => {
expect(screen.getByText('Invalid username or password.')).toBeInTheDocument();
});
});
});
});
Again, this test works! Hooray! But the issue is that I am making axios think (via msw) that it is receiving a 400 response for this query, and I get this big chunk of error message in my console when I run this test with Jest:
PASS src/display/views/login/__tests__/Login.spec.js
rendering
error
√ should hide loading indicator and render error message when request fails (522 ms)
console.error
Error: Request failed with status code 400
at createError (C:\Users\me\Documents\_Programming\GitHub\my-project\node_modules\axios\lib\core\createError.js:16:15)
at settle (C:\Users\me\Documents\_Programming\GitHub\my-project\node_modules\axios\lib\core\settle.js:18:12)
at XMLHttpRequestOverride.handleLoad [as onreadystatechange] (C:\Users\me\Documents\_Programming\GitHub\my-project\node_modules\axios\lib\adapters\xhr.js:59:7)
at XMLHttpRequestOverride.triggerReadyStateChange (C:\Users\me\Documents\_Programming\GitHub\my-project\node_modules\node-request-interceptor\src\interceptors\XMLHttpRequest\XMLHttpRequestOverride.ts:133:33)
at XMLHttpRequestOverride.trigger (C:\Users\me\Documents\_Programming\GitHub\my-project\node_modules\node-request-interceptor\src\interceptors\XMLHttpRequest\XMLHttpRequestOverride.ts:145:12)
at C:\Users\me\Documents\_Programming\GitHub\my-project\node_modules\node-request-interceptor\src\interceptors\XMLHttpRequest\XMLHttpRequestOverride.ts:306:18
at runNextTicks (internal/process/task_queues.js:62:5)
at processTimers (internal/timers.js:489:9) {
config: {
adapter: [Function: xhrAdapter],
transformRequest: { '0': [Function: transformRequest] },
transformResponse: { '0': [Function: transformResponse] },
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
validateStatus: [Function: validateStatus],
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json;charset=utf-8'
},
method: 'post',
url: 'http://baseurl/api/auth/token',
data: '{"username":"testUsername","password":"testPassword"}'
},
request: XMLHttpRequestOverride {
requestHeaders: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json;charset=utf-8'
},
responseHeaders: { 'x-powered-by': 'msw', 'content-type': 'application/json' },
_events: [],
UNSENT: 0,
OPENED: 1,
HEADERS_RECEIVED: 2,
LOADING: 3,
DONE: 4,
onreadystatechange: [Function: handleLoad],
onabort: null,
onerror: [Function: handleError],
onload: null,
onloadend: null,
onloadstart: null,
onprogress: null,
ontimeout: [Function: handleTimeout],
url: 'http://baseurl/api/auth/token',
method: 'POST',
readyState: 4,
withCredentials: false,
status: 400,
statusText: 'Bad Request',
data: '{"username":"testUsername","password":"testPassword"}',
response: '"Invalid username or password."',
responseType: 'text',
responseText: '"Invalid username or password."',
responseXML: null,
responseURL: '',
upload: null,
timeout: 0,
async: true,
user: undefined,
password: undefined
},
response: {
data: 'Invalid username or password.',
status: 400,
statusText: 'Bad Request',
headers: { 'x-powered-by': 'msw', 'content-type': 'application/json' },
config: {
adapter: [Function: xhrAdapter],
transformRequest: [Object],
transformResponse: [Object],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
validateStatus: [Function: validateStatus],
headers: [Object],
method: 'post',
url: 'http://baseurl/api/auth/token',
data: '{"username":"testUsername","password":"testPassword"}'
},
request: XMLHttpRequestOverride {
requestHeaders: [Object],
responseHeaders: [Object],
_events: [],
UNSENT: 0,
OPENED: 1,
HEADERS_RECEIVED: 2,
LOADING: 3,
DONE: 4,
onreadystatechange: [Function: handleLoad],
onabort: null,
onerror: [Function: handleError],
onload: null,
onloadend: null,
onloadstart: null,
onprogress: null,
ontimeout: [Function: handleTimeout],
url: 'http://baseurl/api/auth/token',
method: 'POST',
readyState: 4,
withCredentials: false,
status: 400,
statusText: 'Bad Request',
data: '{"username":"testUsername","password":"testPassword"}',
response: '"Invalid username or password."',
responseType: 'text',
responseText: '"Invalid username or password."',
responseXML: null,
responseURL: '',
upload: null,
timeout: 0,
async: true,
user: undefined,
password: undefined
}
}
}
at CustomConsole.console.error (node_modules/#testing-library/react/dist/act-compat.js:52:34)
at node_modules/react-query/lib/core/mutation.js:115:32
I think, to a certain extent, this is expected, but it's REALLY unnecessary spam in my tests given that I am expecting and in fact wanting that request to fail. Is there a best practice way to remove this unnecessary log via config for Jest, RTL, msw, or Axios?
react-query logs to the console per default, you can override this with setLogger:
import { setLogger } from 'react-query'
setLogger({
log: printLog,
warn: printWarn,
error: printError,
})
see also: https://react-query.tanstack.com/reference/setLogger

Error: read ECONNRESET Axios in backend Node js

I am using axios in the backend nodejs and wanted to fetch the data of the movie database API.
when is send request from frontend to my nodejs API it gives Error: read ECONNRESET error. But sometimes it works properly. here is my API route :-
app.get("/api/v1/movie/details/:movieId",(req,res) => { const id = req.params.movieId;
let results = {};
axios
.get(
`/movie/${id}?api_key=${process.env.API_KEY}&language=en-US&append_to_response=videos,credits`
)
.then((response) => {
results = { ...response.data };
return res.status(200).json(results);
})
.catch((e) => {
console.log(e);
return res.status(500).json(e.message);
});});
And here is the error I am getting in console
Error: read ECONNRESET
at TLSWrap.onStreamRead (internal/stream_base_commons.js:205:27) {
errno: 'ECONNRESET',
code: 'ECONNRESET',
syscall: 'read',
config: {
url: '/movie/556984?api_key=API_KEY&language=en-US&append_to_response=videos,credits',
method: 'get',
headers: {
Accept: 'application/json, text/plain, */*',
'User-Agent': 'axios/0.20.0'
},
baseURL: 'https://api.themoviedb.org/3',
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
adapter: [Function: httpAdapter],
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
validateStatus: [Function: validateStatus],
data: undefined
},
I don't understand how sometimes it working but sometimes its showing this error.
But whenever I send request to directly to the movie database API from the browser (not sending to my own API) i got response everytime... please help me !!!

Trying to implement NodeJS Gmail API example

I am trying to get the NodeJs Gmail API Quickstart example working. At first, I was able to get the example running and receive an out put that looked like this.
INBOX
SPAM
ETC ...
I made a few changes after so that I could see messages, etc. Once that happened I started getting the following error after the prompt (It was working prior).
Authorize this app by visiting this url: https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.modify&response_type=code&client_id=***&redirect_uri=***
Enter the code from that page here:
I get this error code
Error retrieving access token GaxiosError: invalid_grant
at Gaxios.<anonymous> (C:\***\node_modules\gaxios\build\src\gaxios.js:73:27)
at Generator.next (<anonymous>)
at fulfilled (C:\***\node_modules\gaxios\build\src\gaxios.js:16:58)
at processTicksAndRejections (internal/process/task_queues.js:97:5) {
response: {
config: {
method: 'POST',
url: 'https://oauth2.googleapis.com/token',
data: 'code=***client_id=***&client_secret=***&redirect_uri=http***=authorization_code&code_verifier=',
headers: [Object],
params: [Object: null prototype] {},
paramsSerializer: [Function: paramsSerializer],
body: 'code=***&client_id=***&client_secret=***&redirect_uri=***&grant_type=authorization_code&code_verifier=',
validateStatus: [Function: validateStatus],
responseType: 'json'
},
data: {
error: 'invalid_grant',
error_description: 'Malformed auth code.'
},
headers: {
***,
***
},
status: 400,
statusText: 'Bad Request'
},
config: {
method: 'POST',
url: 'https://oauth2.googleapis.com/token',
data: 'code=***&client_id=***&client_secret=***&redirect_uri=***=authorization_code&code_verifier=',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': 'google-api-nodejs-client/3.1.2',
},
params: [Object: null prototype] {},
paramsSerializer: [Function: paramsSerializer],
body: 'code=***&client_id=***&client_secret=***&redirect_uri=***&grant_type=authorization_code&code_verifier=',
validateStatus: [Function: validateStatus],
responseType: 'json'
},
code: '400'
}
So I reverted the changes back to the original quickstart code, and I am still getting the above error. I have no idea why this is happening and would appreciate some help!
the taken of Gmail api expires really soon after you work with it
try to delete the credentials.json and start the script again .

sending file from server to server using axios

I m trying to post a multi part form data with a file from one api to another. for that I m using axios and a FormData library that handle the data I want to sent
import { ReadStream } from "fs"
import Axios from "axios"
import * as fs from "fs"
const FormData = require('form-data')
let formData: FormData = new FormData()
formData.append('name', name)
formData.append('allowPrint', 'false')
const file: ReadStream = fs.createReadStream(name)
formData.append('content', file, name)
return Axios.post(fileAPIUrl + "/file", formData, {
headers: {
"Origin": origin,
"Authorization": "Bearer " + securityToken,
"Content-Type": "multipart/form-data"
}, responseType: "json"
})
I should receive a json with the id of my file I just upload. I know the other api works because Is working from my frontend , I m able to post a file with more info from the frontend but if I use this url from my backend I receive the following error:
{ Error: write after end
at write_ (_http_outgoing.js:627:15)
at ClientRequest.write (_http_outgoing.js:622:10)
at RedirectableRequest._write node_modules/follow-redirects/index.js:153:23)
at doWrite (_stream_writable.js:406:12)
at clearBuffer (_stream_writable.js:533:7)
at onwrite (_stream_writable.js:458:7)
at onCorkedFinish (_stream_writable.js:657:5)
at afterWrite (_stream_writable.js:473:3)
at onwrite (_stream_writable.js:464:7)
at Socket._writeGeneric (net.js:742:5)
at Socket.connect (net.js:692:12)
at Object.onceWrapper (events.js:272:13)
at Socket.emit (events.js:185:15)
at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1157:10)
config:
{ adapter: [Function: httpAdapter],
transformRequest: { '0': [Function: transformRequest] },
transformResponse: { '0': [Function: transformResponse] },
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
validateStatus: [Function: validateStatus],
headers:
{ Accept: 'application/json, text/plain, */*',
'Content-Type': 'multipart/form-data',
Origin: 'http://localhost',
Authorization: ‘Bearer token',
'User-Agent': 'axios/0.15.3' },
method: 'post',
responseType: 'json',
url: ‘file.url/file',
data:
FormData {
_overheadLength: 538,
_valueLength: 98,
_valuesToMeasure: [],
writable: false,
readable: true,
dataSize: 0,
maxDataSize: 2097152,
pauseStreams: true,
_released: true,
_streams: [],
_currentStream: null,
_boundary: '--------------------------207564514352341640400188',
_events: {},
_eventsCount: 0 } },
response: undefined }
(node:89) [DEP0013] DeprecationWarning: Calling an asynchronous function without callback is deprecated.
You are likely using an old version; this bug has been fixed in https://github.com/follow-redirects/follow-redirects/issues/50/.

Resources