angular 4 / res.download from nodejs back-end - node.js

I'm calling an Angular component which calls an api service I created to call a nodejs back-end. The back-end download a zip file, using res.download. I believe that the response is not correctly handled, because when I call the back-end directly from the url (localhost:3000/api/download/file), it works perfectly. Here's the code below :
1) Angular component
downloadZipFile(index) {
this._apiService.downloadZip(index).subscribe(data => {
});
}
2) Angular apiService
downloadZip(index) {
return this._http.get('http://localhost:3000' + appConfig.__apiUrl + 'download/' + index);
}
3) NodeJS API
router.get('/download/:index', (req, res) => {
res.download(path.join(__dirname, 'downloads/' + req.params.index + '.zip'));
});

You are attaching multiple time API url in your angular service HTTP request. Please remove one of them. and check again.
downloadZip(index) {
return this._http.get('http://localhost:3000/download/' + index);
}
Add above code in your service.

Related

How to process JS file returned from Express response.sendFile()

I have an API which uses Node.js + Express on the backend.
For one of the API endpoints, I'd like to use the Express response object method of "sendFile", documented here:
https://expressjs.com/en/api.html#res.sendFile
The API should return a Javascript file through the sendFile method.
What I can't figure out is how to read in the .js file on the front end so that I can use the JavaScript functions defined in the file. The sendFile portion appears to be working -- it's just the use of the file which I can't figure out.
Here's what I'm doing on the backend:
app.get("/api/member", async (req, res) => {
options = {
root: path.join(__dirname, '/static'),
dotfiles: 'deny'
}
res.sendFile("member.js", options, (err) => {
if (err) {
console.log(err)
next(err)
} else {
console.log('Sent file')
}
})
});
This seems to be working fine, as I can navigate to the endpoint on my localhost and it loads the JS file. The file member.js simply contains some javascript function definitions.
But, I can't figure out how to consume/use the file once it arrives to the front end.
Here's what I have currently on the frontend:
async function refreshJS() {
const url = `${baseUrl}/member`;
const response = await fetch(url, { credentials: "include" });
const script = document.createElement("script")
script.type = "text/javascript"
script.src = response.body
document.head.appendChild(script)
eval(script)
}
I've spent a lot of time looking through the console/debugger to find the text associated with the JS functions -- but they're nowhere to be found.
I've tested this general framework by loading JS files locally through the console and it worked, so I think it's wrapped up in a misunderstanding of where the JS functions live in the API response. For example, if I replace the command above of:
script.src = response.body
with
script.src = "member.js"
then everything works fine provided I have the file locally.
The examples that I've reviewed seem to deal exclusively with sending an HTML file which is loaded on the frontend. But, I can't find supporting documentation from the fetch API to understand how to use the JS file contents.

How to get updates from backend automatically in client side

I have 3 apps, mobile app (react native), web app (react js) and a Nodejs app.
the mobile app is an e-commerce mobile app, and the web app is the admin page (client side). The admin page get all data from NodeJs app (api) that use firebase admin sdk.
The problem is that i want everytime a user place an order using the mobile app, the admin page automatically fetch data from NodeJs app.
api code :
router.post("/orders", function(req, res, next) {
const {filterBy} = req.body;
let orders = [];
if(filterBy === "all"){
db.ref("orders").on('value',function(snap){
if(snap.val){
snap.forEach(function(child){
let items = child.val();
orders.push(items);
})
}
})
}else{
db.ref("orders").orderByChild("generalStatus").equalTo(filterBy)
.on('value',function(snap){
if(snap.val){
snap.forEach(function(child){
let items = child.val();
orders.push(items);
})
}
})
}
res.json(orders.reverse());
});
You can create a socket connection between your web-app and backend. Whenever someone places an order on the mobile app, you can fire an event in backend api which the client can listen too.
You can use socket.io https://socket.io/get-started/chat
You can also add listener on firebase document and use the method on to check for any changes in DB eg if you want to get updates from chat db you can use this code e.g.
const chatRef = database().ref(firebaseMessages.CHAT);
let listener = chatRef.on('value', snapshot => {
console.log('User data: ', snapshot.val());
});
//...
// Later when you no longer need the listener
chatRef.off('value', listener);

Generating rss.xml for Angular 8 app locally works fine, but not on prod

I am trying to generate a rss.xml file for my angular 8 app with ssr + firebase + gcp inside the domain.
I've created a RssComponent which can be reached at /rss route. There i call getNews() method and receive an array of objects. Then I make a http request to /api/rss and in server.ts i handle that request:
app.post('/api/rss', (req, res) => {
const data = req.body.data;
const feedOptions = // defining options here
const feed = new RSS(feedOptions);
data.forEach((item) => {
feed.item({
title: item.headingUa,
description: item.data[0].dataUa,
url: item.rssLink,
guid: item.id,
date: item.utcDate,
enclosure: {url: item.mainImg.url.toString().replace('&', '&'), type: 'image/jpeg'}
});
});
const xml = feed.xml({indent: true});
fs.chmod('dist/browser/rss.xml', 0o600, () => {
fs.writeFile('dist/browser/rss.xml', xml, 'utf8', function() {
res.status(200).end();
});
});
});
And finally on response i'm opening the recently generated rss.xml file in RssComponent. Locally everything is working fine but on Google Cloud Platform it's not generating a file.
As explained in the Cloud Functions docs:
The only writeable part of the filesystem is the /tmp directory
Try changing the path to the file to the /tmp directory.
Nevertheless, using local files in a serverless environment is a really bad idea. You should assume the instance handling the following request will not be the same as the previous one.
The best way to handle this would be to avoid writing local files and instead storing the generated file in GCP Storage or Firebase Storage, and then retrieving it from there when needed.
This will ensure your functions are idempotent, and also will comply with the best practices.

Nodejs REST API to rewrite url or work as middleware for accessing distant photos

I am making a rest api with node/express for exposing data with assests urls from another servers , like this :
Client ------> RestAPI with nodeJs/express (API Y) --------> API for Images (API X)
The API for Images (API X): provide json or links for images with url like "http://APIX.com/link1/X.jpg"
The assets / images are located in (API X) server .
What am trying to do is when the client calls the (API Y) and want to get data with image urls like "http://APIY.com/api/X.jpg" ,the (API Y) fetch the images from (API X) and return it to client with links from (API Y), so the client will not know the correct source of images and think that the images are hosted in (API Y) server.
Any idea on how can i implement this in NODE js/express ? thx.
Thanks #jfriend00 , i manage to find a solution with your "proxy" suggestion, i used the http-proxy-middlware npm package , like follow :
I am using express and http-proxy-middleware with Typescript
import express from "express";
import proxy from "http-proxy-middleware";
export default class APIYServer {
constructor(private port: number) {}
public start(): void {
const app = express();
app.use(
//the Url exposed with APIY
"/APIY/assets",
proxy({
//the Url of the APIX server
target: "https://www.APIX.com/",
changeOrigin: true,
pathRewrite: {
//"/APIX-assets-path/" is the path where images are located
"^/APIY/assets": "/APIX-assets-path/"
},
onProxyRes
})
);
//function for handling proxy response
function onProxyRes(proxyResponse: any, request: any, response: any) {
if (proxyResponse.statusCode != 200) {
console.log("---FAIL ---");
}
// DELLETING COOKIES INFOS so the client can't find source of images
Object.keys(proxyResponse.headers).forEach(function(key) {
delete proxyResponse.headers[key];
});
delete proxyResponse.headers['Set-Cookie'];
}
//run APIY server on port 8888
app.listen(this.port, () => {
console.log("Server Started on 8888");
});
}
}
When calling "localhost:8888/APIY/assets/01.png" its give me the images located in "https://www.APIX.com/APIX-assets-path/01.png"...and that's what i m looking for :D

Can't access NodeJS api from Angular app

I have trouble trying to get to my NodeJs server from my angular app. Here's my router:
app.get('/new12345',function(req,res){
console.log("Http Get Recently Gone from /new12345");
var results = userData;
res.send(results);
});
Here where I try getting to my api.
this.http.get('/new12345').subscribe(data => {
this.resultInArray = data['results'];
}
I am getting this error though:
Error: Cannot match any routes. URL Segment: 'new12345'
Thanks!
You did not specify your api base url. You are currently getting to your angular app (hence the angular router error you are getting).
For example, that might look like this:
this.http.get('http://localhost:3000/new12345').subscribe(data => {
this.resultInArray = data['results'];
}

Resources