Cannot read property 'pipe' of undefined in node js - node.js

I'm trying to download image using axios and fs
When i run it using node app.js it gives me an error saying pipe
can't be defined
"TypeError: Cannot read property 'pipe' of undefined".
const axios = require('axios');
const fs = require('fs');
const Path = require('path');
async function download()
{
const url ='https://www.google.co.in/imgres'
const path = Path.resolve(__dirname,'files','image1.jpg')
const response = axios
(
{
method : 'GET',
url:url,
responseType:'stream'
}
)
response.data.pipe(fs.createWriteStream(path))
return new Promise((resolve,reject)=>{
response.data.on('end',()=>{
resolve()
})
response.data.on('error',err=>{
reject(err);
})
}).catch();
}
download().then(()=>{
console.log('download finished');
})

Don't you need to wait for axios promise to complete?
See Axios API
...
const response = axios
(
{
method : 'GET',
url:url,
responseType:'stream'
}
).then(function(response) {
response.data.pipe(fs.createWriteStream(path))
return new Promise((resolve,reject)=>{
response.data.on('end',()=>{
resolve()
})
...
Depending on script level you could do this with async/await too I guess, but I'm no Axios expert.

Related

Problem importing module using express Not Using Bundler

Im building a application using express and I dont want to use a bundler. When I import the axios module it gives me the next error: "Uncaught TypeError: Failed to resolve module specifier "axios". Relative references must start with either "/", "./", or "../"."
I also made a repository of the entire project so far here: https://github.com/klaus4323/Natours-Nodejs.git
The code where I want to use axios is in the login.js (I am doing the nodejs online class of Jonas Schemetmann) file:
import axios from 'axios';
import { showAlert } from './alerts.js';
export const login = async (email, password) => {
try {
const res = await axios({
method: 'POST',
url: 'http://127.0.0.1:3000/api/v1/users/login',
data: { email, password },
});
if (res.data.status === 'success') {
showAlert('success', 'Logged in succesfully');
window.setTimeout(() => {
location.assign('/');
5000);
}
catch (err) {
showAlert('error', err.response.data.message);
}
};
export const logout = async () => {
try {
const res = await axios({
method: 'GET',
url: 'http://127.0.0.1:3000/api/v1/users/logout',
});
if ((res.data.status = 'success')) location.reload(true);
catch (err) {
showAlert('error', 'Error logging out. Try Again!');
}
};
Use like this
import * as axios from 'axios'

Steam authentication with API Gateway and lambda

I'm trying to create the authentication of my website using
https://github.com/LeeviHalme/node-steam-openid.
Steam OpenID: https://partner.steamgames.com/doc/features/auth
I have an API Gateway with these two endpoints:
/login
// the steamAuth file is the same module as node-steam-openid but for ts
import { SteamAuth } from "../utils/steamAuth";
export const login = async () => {
const client = new SteamAuth(
'http://localhost:3000',
`${process.env.API_URL}/consume`,
process.env.STEAM_API_KEY,
);
try {
const redirectUrl = await client.getRedirectUrl();
return {
statusCode: 302,
headers: { Location: redirectUrl }
};
} catch (e) {
console.log(e);
return {
statusCode: 500,
message: 'Internal server error'
};
}
}
/consume
import { APIGatewayEvent } from 'aws-lambda';
import { SteamAuth } from "../utils/steamAuth";
export const consume = async (event: APIGatewayEvent) => {
const client = new SteamAuth(
'http://localhost:3000',
`${process.env.API_URL}/consume`,
process.env.STEAM_API_KEY,
);
console.log(event);
try {
const user = await client.authenticate(event);
console.log('success', user);
} catch (e) {
console.log('error', e);
}
return {
statusCode: 302,
headers: { Location: 'http://localhost:3000/' },
};
}
The thing is I get this error in /consume endpoint
error TypeError: Cannot read property 'toUpperCase' of undefined
at Object.openid.verifyAssertion (/var/task/node_modules/openid/openid.js:905:28)
at openid.RelyingParty.verifyAssertion (/var/task/node_modules/openid/openid.js:68:10)
at /var/task/src/utils/steamAuth.js:60:31
at new Promise (<anonymous>)
at SteamAuth.authenticate (/var/task/src/utils/steamAuth.js:59:16)
at Runtime.consume [as handler] (/var/task/src/lambda/consume.js:9:35)
at Runtime.handleOnceNonStreaming (/var/runtime/Runtime.js:73:25)
I believe this error occurs because the verifyAssertion is waiting for an express request while it is provided an API Gateway one.
Link to the code with the mentioned function is here
Should I use another module to do the authentication as I don't really want to modify the source code of the module? I didn't find anything at the moment
Thanks!
I found a workaround using express in lambda. As expected, the openid module used by node-steam-openid is expecting an express request and not a lambda event.
import { SteamAuth } from "../utils/steamAuth";
const express = require('express');
const serverless = require('serverless-http');
const app = express();
app.get('/verify', async (req: any, res: any) => {
const client = new SteamAuth(
process.env.HOSTNAME,
`${process.env.API_URL}/verify`,
process.env.STEAM_API_KEY,
);
try {
const user: any = await client.authenticate(req);
} catch (e) {
throw new Error(e.message);
}
});
module.exports.verify = serverless(app);

Axios is returning undefined

My API is returning proper data when I am requesting from Postman. Even API is getting properly called from React, I checked using console.log inside the controller, but I am always getting undefined response. I am not sure what the mistake is.
const submit = async (e: SyntheticEvent) => {
e.preventDefault();
const response = await axios
.get('certificates', {
params: { sponser },
})
.then((res) => {
console.log(response); //undefined
alert(res.status); //200
alert(res); //[object Object]
});
};
Could you please help me on the same.
You need to return res in the then to have access on response:
const response = await axios
.get('certificates', {
params: { sponser },
})
.then((res) => {
console.log(response); //undefined
alert(res.status); //200
alert(res); //[object Object]
// response is not defined here!
return res;
});
console.log(response);
Shorter way:
const response = await axios
.get('certificates', {
params: { sponser }
});
console.log(response);
It seems that OP is relatively new to js - I can recommend this intro to async js: https://javascript.info/async-await

Send form data to API from nodejs

Earlier I was using rest API to upload my files to the server. I had input type file and I was sending the form data to the server with that API. It was working fine but now I have to use graphql mutation for the same. We have an apollo server running app where I have used the same API to upload our images but it seems that file object was not in the same format as it was expected by rest API. So my question is how can we create same file object like we have in browser from nodejs.
We are using RESTDataSource to make HTTP calls in graphql app
My schema
type Mutation {
uploadFile(file: Upload!): Boolean!
}
Here is my resolver
import { createWriteStream, createReadStream } from 'fs';
import FormData from 'form-data';
async uploadFile(file: any): Promise<any> {
const url = new URL(`https://dev.dummber.com/portal/file/v1/uploadFile`);
const { createReadStream: apolloFileStream, mimetype, filename } = await file;
const tempFilename = `${filename}`;
const stream = apolloFileStream();
const wstream = createWriteStream(tempFilename);
await new Promise((resolve, reject) => {
stream
.pipe(wstream)
.on('finish', () => resolve())
.on('error', () => reject());
});
const rstream = createReadStream(tempFilename);
const formData = new FormData();
formData.append('uploadingFile', rstream);
const response = await this.post(url.toString(),
{
data: formData
}
, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
return true
}

Nock and google maps client

I'm trying to test a service that uses the #google/maps client for getting directions data.
Here is a simplified version of the service:
'use strict'
const dotenv = require('dotenv')
const GoogleMaps = require('#google/maps')
dotenv.config()
const {GOOGLE_API_KEY: key} = process.env
const client = GoogleMaps.createClient({key, Promise})
const getData = exports.getData = async function({origin, destination}) {
try {
const options = {
origin,
destination,
mode: 'transit',
transit_mode: ['bus', 'rail']
}
const res = await client.directions(options).asPromise()
return res
} catch (err) {
throw err
}
}
And here is a test file to show the case:
'use strict'
const dotenv = require('dotenv')
const nock = require('nock')
const gdService = require('./gd.service')
dotenv.config()
const {GOOGLE_API_KEY: key} = process.env
const response = {json: {name: 'custom'}}
const origin = {lat: 51.5187516, lng: -0.0836314}
const destination = {lat: 51.52018, lng: -0.0998361}
const opts = {origin, destination}
nock('https://maps.googleapis.com')
.get('/maps/api/directions/json')
.query({
origin: `${origin.lat},${origin.lng}`,
destination: `${destination.lat},${destination.lng}`,
mode: 'transit',
transit_mode: 'bus|rail',
key
})
.reply(200, response)
gdService.getData(opts)
.then(res => {
console.log(res.json) // it's undefined!
})
.catch(err => {
console.error(err)
})
What I expect is to get the defined response as a response of the service method invocation. But I get undefined. Why is that?
After reading the source of #google/maps client, I figured out that I had to provide nock with the following reply header:
...
nock('https://maps.googleapis.com')
.defaultReplyHeaders({
'Content-Type': 'application/json; charset=UTF-8'
})
.get('/maps/api/directions/json')
...

Resources