I have the following API /api/v1/download/:id
Usage: http://localhost:3000/api/v1/download/client_app.zip
Implementation:
const express = require("express");
const axios = require("axios");
const { InternalServerError } = require("common-lib");
const router = express.Router();
router.get("/api/v1/download/:id",
async (req, res, next) => {
const { id } = req.params;
try {
const response = await axios.get(
`${process.env.DOWNLOAD_URL}/artifacts/client_app/${id}`, {
auth: {
username: process.env.USERNAME,
password: process.env.PASSWORD
},
responseType: "stream"
});
response.data.pipe(res);
} catch (error) {
return next(new InternalServerError(error.message));
}
});
module.exports = {
downloadByIdRouter: router
}
A user will use the /api/v1/download/:id to download the .zip file from another remote server, the actual credentials and remote URL are hidden from the end-user.
The API is working as expected and I am able to download the file into my system.
The question is how to write the test for this particular streaming scenario in Jest.
describe("download by id test", () => {
test("downloads the app, if requested properly", () => {
// to do
}, )
});
I checked this reference https://dev.to/cdanielsen/testing-streams-a-primer-3n6e. However, I am not exactly getting the approach.
I need guidance in writing the test for this particular scenario, comparatively new to Jest.
Route import
const express = require("express");
// Import routes
const { downloadByIdRouter } = require("./routes/download-byid");
const app = express();
// Use routes
app.use(downloadByIdRouter);
module.exports = {
app
}
Then I import app in the test file and using the supertest library I make the API calls
download.test.js
const request = require("supertest");
const { app } = require("../../app");
describe("download by id test", () => {
test.todo("starts the app download, if requested properly")
});
Thanks
Related
I am trying to send a request to DetectIntent API from webhook - Dialog Flow CX . I downloaded service-key in GCP and stored in serviceaccount.json file .I created .env file and stored all the values from serviceaccount file to .env file.I get error when I run "node index.js"
Error:"IAM permission 'dialogflow.sessions.detectIntent' on 'projects/dialogflowcx-340818,/agent' denied.",
I went through related stackoverflow posts where they suggested to set GOOGLE_APPLICATION_CREDENTIALS .I tried that as well.Still I get the same error.
I tried :
process.env.GOOGLE_APPLICATION_CREDENTIALS="/Users/suchitranagarajan/Desktop/nodeproject/detectintent/service-account.json"
Also,I tried to set
export GOOGLE_APPLICATION_CREDENTIALS="/Users/suchitranagarajan/Desktop/nodeproject/detectintent/service-account.json"
Please find the code below:
const dialogflow = require('#google-cloud/dialogflow');
test=require('dotenv').config();
const express = require('express');
const path = require("path");
process.env.GOOGLE_APPLICATION_CREDENTIALS="/Users/suchitranagarajan/Desktop/nodeproject/detectintent/service-account.json"
const PROJECTID = process.env.project_id;
const location=process.env.location
const agentid=process.env.agentid
const CONFIGURATION = {
credentials: {
private_key: process.env.private_key,
client_email: process.env.client_email
}
}
const sessionClient = new dialogflow.SessionsClient();
const detectIntent = async (languageCode, queryText, sessionId) => {
let sessionPath = sessionClient.projectLocationAgentSessionPath(PROJECTID,location,agentid,sessionId);
// The text query request.
let request = {
session: sessionPath,
queryInput: {
text: {
// The query to send to the dialogflow agent
text: queryText,
// The language used by the client (en-US)
languageCode: languageCode,
},
},
};
// Send request and log result
const responses = await sessionClient.detectIntent(request);
console.log(responses);
const result = responses[0].queryResult;
console.log(result);
return {
response: result.fulfillmentText
};
}
detectIntent("en", "hello", "abcd1234");
// Start the webapp
const webApp = express();
// Webapp settings
webApp.use(express.urlencoded({
extended: true
}));
webApp.use(express.json());
// Server Port
const PORT = process.env.PORT || 5000;
// Home route
webApp.get('/', (req, res) => {
res.send(`Hello World.!`);
});
// Dialogflow route
webApp.post('/dialogflow', async (req, res) => {
let languageCode = req.body.languageCode;
let queryText = req.body.queryText;
let sessionId = req.body.sessionId;
let responseData = await detectIntent(languageCode, queryText, sessionId);
res.send(responseData.response);
});
// Start the server
webApp.listen(PORT, () => {
console.log(`Server is up and running at ${PORT}`);
});
Please find .env file below:
type= service_account,
project_id=xxx,
private_key_id=xxx,
private_key=xxx","client_email": "xxx","client_id": "xxx","auth_uri": "xxx,
token_uri=xxx,
auth_provider_x509_cert_url= xxx,
client_x509_cert_url=xxx
location=xxx
agentid=xxx
I'm trying to build a instagram scraper with puppeteer and react that works with putting the username on an input and then I want to show the scraped data on the console, I already built the puppeteer script and It works, it returns the data correctly, But I have some issues trying to get the data from a post with axios, I'm using node js and express for my server, when I try to do the post with axios I keep getting an error.
I want to write the username on the input, then I want the puppeteer script to run, and then I want to console log the data that the puppeteer script returns
Error on console
POST http://localhost:4000/api/getData/username_im_scraping net::ERR_CONNECTION_REFUSED
This is my code
Server > index.js
const path = require("path");
const express = require("express");
const webpack = require("webpack");
const cors= require('cors');
const webpackDevMiddleware = require("webpack-dev-middleware");
const webpackHotMiddleware = require("webpack-hot-middleware");
const config = require(path.join(__dirname, "../webpack.config.js"));
const compiler = webpack(config);
const app = express();
const { script } = require("./script");
app.use(webpackDevMiddleware(compiler, config.devServer));
app.use(webpackHotMiddleware(compiler));
app.use(express.static(path.join(__dirname, '../build')));
app.use(cors());
app.get("/api/getData/:username", async (req, res) => {
console.log(`starting script for user ${req.params.username}`);
const data = await script(req.params.username);
console.log(`stopping script for user ${req.params.username}`);
res.send(data);
});
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, '../build', 'index.html'));
});
app.listen(process.env.PORT || 4000, () => {
console.log('Server is listening on port 4000');
});
Homepage.js
import React, { useState } from "react";
import axios from "axios";
const Homepage = props => {
const [username, setUsername] = useState("");
const onChange = ({ target: { value } }) => setUsername(value);
const onClick = () => {
axios.post('http://localhost:4000/api/getData/' + username, {
header: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8;application/json' },
mode: "cors"
})
.then((response) => {
console.log(response);
})
.catch((error) => {
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
console.log(error.request);
} else {
console.log('Error', error.message);
}
})
};
return (
<div>
Time to start coding!
<input value={username} onChange={onChange} />
<button onClick={onClick}>Get instagram followers!</button>
</div>
);
};
export default Homepage;
The problem here is you defined your route with get like app.get("/api/getData/:username") but you are sending a post request. Either change the router to app.post or your axios method to axios.get.
UPDATE
Besides the changes above, after you shared the repository with me i checked and saw you have another problem, which was that you were not running your server so the ERR_CONNECTION_REFUSED message shown.
I forked your repository and made the following changes and created a PR for it. Please take a look at it, and if you want just merge it to your master branch.
P.S please for the next time create a .gitignore file and add node_modules to there so you don't push and pull your node_modules which takes some more amount of time.
I'm trying to send data to my Nodejs server (hosted on Firebase), from Reactjs to retrieve data from an API call.
It worked when the API url was hard coded, so the issue should be in sending the data from React to Node. I'm currently trying to have it only return one request, but once I'm able to do that, I will be trying to fetch multiple requests.
The result is to populate the stocks state with the response.
My React code looks like this:
class Table extends Component {
constructor (props)
{
super(props);
this.state = {
favorites: ['APPL'],
stocks: []
};
}
componentDidMount() {
// http is adjusted for stackoverflow
fetch('http://localhost:5001/', {
// new part:
method: 'post',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
favorites: this.state.favorites})
// old part - worked before i tried to send data to the backend:
})
.then((response) => response.json())
.then(stockList => {
this.setState({ stocks: stockList });
console.log(stockList);
});
}
Node code:
const functions = require("firebase-functions");
const express = require("express");
const fetch = require("node-fetch");
const cors = require("cors");
const app = express();
app.use(cors({origin: true}));
app.get('/', async (request, response) => {
// new line that was ment to catch the data from frontend.
const favorites = request.body.favorites
// web and key is the rest of the API call.
const url = web+favorites+key;
const fetchResponse = await fetch(url);
const symbol = await fetchResponse.json();
response.json(symbol);
});
In order to get the data from the frontend you will need to make a post endpoint instead in your Node server and send a GET request inside that method.
const functions = require("firebase-functions");
const express = require("express");
const fetch = require("node-fetch");
const cors = require("cors");
const app = express();
app.use(cors({origin: true}));
app.post('/', (req, res) => {
// here is how you get the POST data from the body
console.log(req.body.favorites)
// send the data from the POST request to the API through a GET request here
})
Now you need to make a GET request where I put the comment, you can use the simpler https node.js library for that.
In my question, I'm trying to use Firebase functions to handle the link to an external API and use the data from that API in my frontend.
After some though and help from Stackoverflow, I have found that it might not be an ideal way to do it. I was basically trying to add a layer between the frontend and the API, but that is not necessary, as it is possible to reach the API directly in React. This will remove the function from Firebase, meaning less steps, less code and less fees.
So for every instance in the state.favorites, the correlated data is pulled from the API and stored in the state.stocks.
This piece of code did the trick:
class Table extends Component {
constructor (props)
{
super(props);
this.state = {
favorites: ['aapl', 'arvl'],
stocks: []
};
}
componentDidMount() {
this.state.favorites.map((favorites, index) => {
fetch(`API_website${favorites}/(API_token`)
.then((response) => response.json())
.then(stockList => {
this.setState({ stocks: stockList });
console.log(stockList);
});
})
}
I'm using MicroMQ to communicate between different services, and for main service it is ok, I received requests and then delegating them through RabbitMQ. I can see this message in queue but my microservice don't receive any messages. This is for main service:
controller:
export const create = async (req, res) => {
await res.delegate('trade');
}
gatewayConfig:
const Gateway = require('micromq/gateway');
const config = require('../configServer');
export const gateway = new Gateway({
microservices: ['platform', 'trade'],
name: 'platform',
rabbit: {
url: "amqp://rihtavqi:AhKDUujmeC5hBUPb0zQb7qh7AgqnR5QG#lion.rmq.cloudamqp.com/rihtavqi"
}
});
export const services = {
trade: 'trade'
};
server.js
app.use(gateway.gateway.middleware());
this what I use in my main service. This is only place where I'm calling gateway...
And this is for microservice:
server.js
const express = require("express");
const gateway = require('./gateway/gatewayRoute');
const app = express();
const server = require("http").createServer(app);
gateway.start().then(() => {
server.listen(constant.config.port, constant.config.host, async () => {
loggingHelper.consoleLog("APP", `Server running on port ${constant.config.port} and on host ${constant.config.host}.....`);
process.on("unhandledRejection", (reason, promise) => {
loggingHelper.consoleLog("APP_ERROR", `Uncaught error in ${String(reason)}`, promise);
});
});
route
const MicroService = require('micromq/src/MicroService');
const loggingHelper = require('../app/helper/loggingHelper');
const orderService = require('../app/service/orderService');
const gateway = new MicroService({
name: 'trade',
rabbit: {
url: "amqp://rihtavqi:AhKDUujmeC5hBUPb0zQb7qh7AgqnR5QG#lion.rmq.cloudamqp.com/rihtavqi"
}
}
);
gateway.post('/create', async (req, res) => {
loggingHelper.consoleInfoLog("TRADE", "/create received.");
res.json(await service.create(req));
});
module.exports = gateway;
Last one don't work. BTW my idea told me that .post() function is
Unresolved function or method post()
I think problem is here. I trying different ways(creating Gateway(micromq/gateway) in microservice, tried to destructure MicroService but this all give me nothing)
all of this was creating by examples but it not works... And I cannot understand why? Somebody knows why?
Not sure about MicroMQ, but you could use the SMF framework to prototype microservices that are connected to RabbitMQ automatically:
https://medium.com/#krawa76/bootstrap-node-js-microservice-stack-4a348db38e51
How can one unit test an express router that is dependent on passport authentication to call the helper methods?
I'm new to express unit testing and I've seen a lot of code that actually hits the server to call the method. But would that not make it an integration test? This ultimately comes down to my lack of understanding on the best practices on express unit testing.
I've tried to just mock out the passport but that didn't work because I need to get to the callbacks. I've also tried using rewire and just try to test the helper methods and that didn't seem to work either, I think, because file is wrapped in module.export.
Any help here would be much appreciated.
File I'm trying to unit test:
module.exports = function (inject) {
var router = require('express').Router();
var app = inject.app;
return router.get('/', app.passport.authenticate('bearer', { session: false }), [editContentCheck, getUser]);
function editContentCheck(req,res,next) {
if(req.authInfo.scope.indexOf('readOwnUser') == -1) {
res.statusCode = 403;
return res.end('Forbidden');
}
return next();
}
function getUser(req, res) {
var authHeader = req.headers.authorization.split(' ');
var token = authHeader[1];
var models = require('../models');
models.AccessToken.getAccessToken(token,function(err,tokenObj) {
models.User.getUser(tokenObj.userId, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
res.send(JSON.stringify(user));
});
});
}
};
Check this repository, it has all You want: https://github.com/num8er/alttab-nodejs-challenge
Also a look at example and implement it as You wish:
1)server.js :
var
http = require('http'),
app = require('./app'); // app.js file
http.createServer(app).listen(8080);
2)app.js :
var
express = require('express'),
app = express();
app.use(require('./routes')); // routes.js file
module.exports = app;
3)routes.js :
var router = require('express').Router();
function editContentCheck(req,res,next) {}
function getUser(req, res) {}
router.get('/posts', app.passport.authenticate('bearer', { session: false }), [editContentCheck, getUser]);
module.exports = router;
4)spec/AppSpec.js :
var
request = require('supertest-as-promised'), // npm i --save-dev supertest-as-promised
app = require('./../app');
var token = "some token here";
describe('App', function() {
describe("Posts", function() {
it('should pass auth check and get posts', function() {
return request(app)
.get('/posts')
.set('Authorization', 'Bearer ' + token)
.expect(200);
});
});
});
p.s. I'm using jasmine as testing framework, but even with mocha it's same style. Because of it's using supertest-as-promised that gets app module and calls the route without creating http object.
p.s.2. it's not unit testing, You're testing the feature, so it's more an integration test to check if all chains of code is properly integrated.