Meteor newbie here, I want to do a meteor call to a meteor method which does a get request to an 3rd party API and forwards the returned JSON response to my initial meteor call.
I want to use the returned JSON response to render my html code
here is my js file with meteor method
Meteor.methods({
'jira.get'(projectName, maxResult) {
if (!this.userId) {
throw new Meteor.Error('Not authorized.');
}
check(projectName, String);
check(maxResult, String);
const base64Auth = Meteor.users.findOne({ _id: this.userId }).Authorization;
const options = {
method: 'GET',
url: `https://myCompany.com/.../search?jql=project=${projectName}&maxResults=${maxResult}`,
headers: {
Authorization: base64Auth,
},
};
const future = new Future();
request(options, function(error, response) {
if (error) throw new Error(error);
const jiraResponse = JSON.parse(response.body);
future.return(jiraResponse);
});
return future.wait();
},
});
and my JSX file that calls above Meteor method is as below
export const App = () => {
Meteor.call('jira.get', project='test', maxResult = '10', (error, jiraResponse) => {
console.log("this is working fine: "jiraResponse)
});
console.log('this is undefined', jiraResponse)
}
If i use useState as below, initially the last console log console.log(jiraResp) prints {} as expected but it goes into infinite loop with the correct data after that
const [ jiraResp, setjiraResp ] = useState({})
Meteor.call('jira.get', project='test', maxResult = '10', (error, jiraResponse) => {
if (jiraResponse){
console.log("got the resp ")
setjiraResp(jiraResponse);
}
else{
console.log("not recieved")
}
});
console.log(jiraResp)
How do i get the response of meteor call and update my jiraResponse just once ?
Setting jiraResp in the method callback will trigger a re-render and since you are making the method call in the render method itself, it will repeat the call, hence the loop.
You need to use useEffect:
const [ jiraResp, setjiraResp ] = useState({});
useEffect(() =>
Meteor.call('jira.get', project = 'test', maxResult = '10', (error, jiraResponse) => {
if (jiraResponse) {
console.log("got the resp ");
setjiraResp(jiraResponse);
} else {
console.log("not recieved");
}
}), []);
console.log(jiraResp);
Related
I make a crud with products
I send an http request to the /api/deleteProduct route with the product id to retrieve it on the server side and delete the product by its id
To create a product it works only the delete does not work
pages/newProduct.js :
useEffect(() => {
async function fetchData() {
const res = await axios.get('/api/products');
setProducts(res.data);
}
fetchData();
}, []);
const handleSubmit = async (event) => {
event.preventDefault();
const formData = new FormData();
formData.append('picture', picture);
formData.append('name', name);
formData.append('price', price);
formData.append('category', category);
formData.append('description', description);
try {
const res = await axios.post('/api/createProduct', formData);
console.log(res.data);
} catch (error) {
console.log(error);
}
};
const handleDelete = async (id) => {
try {
await axios.delete(`/api/deleteProduct?id=${id}`);
setProducts(products.filter(product => product._id !== id));
} catch (error) {
console.log(error);
}
};
api/deleteProduct.js :
import Product from '../../models/Products';
import { initMongoose } from '../../lib/mongoose';
initMongoose();
export const handleDelete = async (req, res) => {
if (req.method === 'DELETE'){
try {
const { id } = req.params
const product = await Product.findByIdAndRemove(id);
if (!product) {
return res.status(404).json({ message: 'Product not found' });
}
return res.status(200).json({ message: 'Product deleted successfully' });
} catch (error) {
console.log(error);
return res.status(500).json({ message: 'Database error' });
}
}};
I have a 500 error but no error in the server side console and the console.log is not showing like the file was not read
Based on the code you've shared, it seems that the problem may be with the way that the delete request is being handled on the frontend. Specifically, in this line:
await axios.delete("/api/deleteProduct", { params: { id } });
The delete request is supposed to receive the id of the product that should be deleted as a query parameter, but it is being passed as a request body.
Instead of passing it as a parameter, you should pass it as a query parameter by changing it to
await axios.delete(`/api/deleteProduct?id=${id}`);
Also, in your api/deleteProduct.js, you should change the following line:
const { id } = req.query;
to
const { id } = req.params;
Also, you should make sure that the server is running and that the api endpoint '/api/deleteProduct' is accessible and handling the request correctly.
For the last, make sure that the product model is imported and initialized correctly and the database connection is established.
Hope that it solves your problem or, at least, helps :))
I succeeded, I put this (server side):
const { id } = req. query;
and (client side):
await axios.delete(/api/deleteProduct?id=${id});
and I exported my function like this:
export default async function handleDelete(req, res) {
I need your help to mock a twilio service which sends a message, using jest to mock the service
I have the next code:
import { SQSEvent } from "aws-lambda";
import { GetSecretValueResponse } from "aws-sdk/clients/secretsmanager";
export async function sendSms(event: SQSEvent, data: GetSecretValueResponse) {
const secrets = JSON.parse(data.SecretString);
const accountSid = secrets.TWILIO_ACCOUNT_SID;
const authToken = secrets.TWILIO_AUTH_TOKEN;
const twilioNumber = secrets.TWILIO_PHONE_NUMBER;
if (accountSid && authToken && twilioNumber) {
//Create a Twilio Client
const client = new Twilio(accountSid, authToken);
//Loop into al records of the event, every record is every message sent from Sqs
for (const record of event.Records) {
const body = JSON.parse(record.body);
const userNumber = "+" + body.number;
//SendMessage function
try {
const message = client.messages.create({
from: twilioNumber,
to: userNumber,
body: body.message,
});
return message;
} catch (error) {
return `Failed to send sms message. Error Code: ${error.errorCode} / Error Message: ${error.errorMessage}`;
}
}
} else {
return "You are missing one of the variables you need to send a message";
}
}
The I call this function from my index:
import { SQSEvent } from "aws-lambda";
import { sendSms } from "./services/sendSms/sendSms";
import { getSecret } from "./services/obtainSecrets/getSecret";
import { SecretsManager } from "aws-sdk";
export const lambdaHandler = async (event: SQSEvent) => {
try {
const obtainedSecret = await getSecret()
.then((credentials: SecretsManager.GetSecretValueResponse) => {
return credentials;
})
.catch(error => {
return error;
});
const response = sendSms(event, obtainedSecret)
.then(response => {
return response;
})
.catch(error => {
return error;
});
return {
message: "OK " + obtainedSecret + response,
code: 200,
};
} catch (error) {
throw new Error(error);
}
};
I have already make some tests, but them always makes a connection with Twilio api(requiring the real token, sid,etc), and I need to mock the Twilio service, so the function I call in my test.ts doesn't connects to internet.
import { Twilio } from "twilio";
import { MessageInstance } from "twilio/lib/rest/api/v2010/account/message";
import { sendSms } from "../../services/sendSms/sendSms";
//mock Twilio library and sendSms service
jest.mock("twilio");
jest.mock("../../services/sendSms/sendSms");
const smsMessageResultMock: Partial<MessageInstance> = {
status: "sent",
sid: "AC-lorem-ipsum",
errorCode: undefined,
errorMessage: undefined,
};
describe("SMS Service", () => {
describe("Send Message", () => {
it("Should fail", async () => {
// update smsMessageResultMock to simulate a faled response
const smsMessageMock = {
...smsMessageResultMock,
status: "failed",
errorCode: 123,
errorMessage: "lorem-ipsum",
};
// simulated response of secret management
let data = {
ARN: "arn:aws:secretsmanager:us-west-2:123456789012:secret:MyTestDatabaseSecret-a1b2c3",
Name: "MyTestDatabaseSecret",
SecretString:
'{"TWILIO_ACCOUNT_SID": "ACTWILIO_ACCOUNT_SID","TWILIO_AUTH_TOKEN": "TWILIO_AUTH_TOKEN","TWILIO_PHONE_NUMBER": "TWILIO_PHONE_NUMBER"}',
VersionId: "EXAMPLE1-90ab-cdef-fedc-ba987SECRET1",
VersionStages: ["AWSPREVIOUS"],
};
// simulated response of SqsEvent
let event = {
Records: [
{
messageId: "19dd0b57-b21e-4ac1-bd88-01bbb068cb78",
receiptHandle: "MessageReceiptHandle",
body: '{"message": "Hello world","number": "(506)88888888"}',
attributes: {
ApproximateReceiveCount: "1",
SentTimestamp: "1523232000000",
SenderId: "123456789012",
ApproximateFirstReceiveTimestamp: "1523232000001",
},
messageAttributes: {},
md5OfBody: "{{{md5_of_body}}}",
eventSource: "aws:sqs",
eventSourceARN: "arn:aws:sqs:us-east-1:123456789012:MyQueue",
awsRegion: "us-east-1",
},
],
};
// simulate tokens for Twilio
const accountSid = "ACfjhdskjfhdsiuy876hfijhfiudsh";
const authToken = "fjfuewfiuewfbodfiudfgifasdsad";
//create client with mocked Twilio
const client = new Twilio(accountSid, authToken);
//call messages.create of Twilio client, and give it the expected result created
client.messages.create = jest
.fn()
.mockResolvedValue({ ...smsMessageMock });
console.log(await sendSms(event, data));
//expectes the function sendSms(event, data) to throw an error
await expect(sendSms(event, data)).rejects.toThrowError(
`Failed to send sms message. Error Code: ${smsMessageMock.errorCode} / Error Message: ${smsMessageMock.errorMessage}`
);
});
});
});
(event and data are simulated responses of SqsEvent and GetSecretValueResponse)
The problem is that when I run the npm test it throws me an error of Twilio's authentication, an it is because I'm passing self created tokens.
Expected substring: "Failed to send sms message. Error Code: 123 / Error Message: lorem-ipsum"
Received message: "Authentication Error - invalid username"
at success (node_modules/twilio/lib/base/Version.js:135:15)
at Promise_then_fulfilled (node_modules/q/q.js:766:44)
at Promise_done_fulfilled (node_modules/q/q.js:835:31)
at Fulfilled_dispatch [as dispatch] (node_modules/q/q.js:1229:9)
at Pending_become_eachMessage_task (node_modules/q/q.js:1369:30)
at RawTask.Object.<anonymous>.RawTask.call (node_modules/asap/asap.js:40:19)
at flush (node_modules/asap/raw.js:50:29)
So what I suppose is that the test is connecting to internet and calling Twilio's api.
I appreciate if you could help me.
I think what you want to do is mock the class returned by the module, using jest.mock('twilio', mockImplementation) and in mockImplementation return a function to act as a constructor that will take your account SID and auth token arguments and then return a mockClient implementation, which in this case needs to return an object which has a messages property, which in turn is an object with a create property that is a mock function.
It's probably easier to just show the code.
const mockClient = {
messages: {
create: jest.fn().mockResolvedValue({ ...smsMessageMock });
}
};
jest.mock("twilio", () => {
return function(accountSid, authToken) {
return mockClient;
}
});
I'm new to Next Js and functional comoponents. I'm trying to retrieve data from /api/retrieve2
//this is retrieve page
export default function Retrieve() {
const onSubmit = async data => {
const { user } = await axios.post("/api/retrieve2", data);
console.log(user) // user here is undefined
};
return (...);
}
//this is retrieve2, inside the API folder
export default async (req, res) => {
try {
const { data } = await axios.post(myBackendUrl, req.body);
console.log(data) //this is printing the right data - { email: 'casas#gmail.com', code: '123123' }
res.json(data);
} catch (e) {
res.json({ err: e.message || e });
}
};
What am I missing, is this something about Next? About functional components?
You should read about ES6 destructuring
You try to destructure user but the axios respons witch is a object doesnt contain the key user
For data it works because there is a data property in the response
Here are all properties that you can destructure:
{ data, status, statusText, headers, config, request }
You need to get the full URL to make http request to using getInitialProps, here Home is the name of your component
const Home = ({ENDPOINT}) => {
const onSubmit = async data => {
const { data } = await axios.post(`${ENDPOINT}/api/retrieve2`, data);
// consider changing `user` here to `data` since Axios stores response in data object
console.log(data) // should be defined
};
return (...);
}
Home.getInitialProps = ctx => {
const ENDPOINT = getEndpoint(ctx.req);
return { ENDPOINT };
};
// You should store this somewhere you can reuse it
export function getEndpoint(req) {
return !!req
? `${req.headers['x-forwarded-proto']}://${req.headers['x-forwarded-host']}`
: window.location.origin;
}
I am calling 2 API request 1 after another so I decided to use the waterfall model but I am facing the issue in it
I have tried so much but not able to solve the issue.
Below is my code:
var unirest = require("unirest");
var async = require("async")
exports.user = (req, res, next) => {
const qry = req.params.id
async.waterfall([
(nextCall) => {
var req = unirest("GET", API_URL1);
req.query({
// some query
});
req.headers({
// some headers
});
req.end(function(subCount) {
// if (resp.error) throw new Error(resp.error);
var channelSubCount = subCount.body
nextCall(null, data)
});
},
(data, nextCall => {
console.log(channelSubCount, 'data')
var reqs = unirest("GET", API_URL2);
reqs.query({
// some query
});
reqs.headers({
// some headers
});
reqs.end(function(res) {
// if (res.error) throw new Error(res.error);
console.log(res.body);
return nextCall(null, {
name: 'abc',
photo: 'src',
count: data
})
});
})
], function(finalData) {
// if (error) { alert('Something is wrong!'); }
console.log('final')
res.status(200).json(
finalData
);
});
};
ERROR:
Reference Error: data is not defined
I don't understand why this is happening.
Also some please show me the right way to implement the above things with optimizations.
Any help appreciated...
Looks like you forgot to close parentheses here in your second arrow function definition:
(data, nextCall => {
It's still a valid JavaScript, but the interpreter now treats data not as a function incoming parameter (as you need), but as a variable. But it's not defined anywhere, therefore you have that error.
Make it like this and it will work:
(data, nextCall) => {
I am working on an Express.js app. The current feature is creating an appointment with a post request and getting and saving data from third party API, then sending updated API data in the subsequent request. The feature is fully working but in the test, the function to get API data is not getting called.
Route to create appointment:
app.post('/schedule', requestHandler.postSchedule);
The request handler for creating appointment:
requestHandler.postSchedule = function (req, res) {
let appointment = {
// posted data
};
new Appointment(appointment)
.save()
.then(newAppointment => {
if(req.body.cityName && req.body.cityName !== '') {
console.log('req.body.cityName', req.body.cityName);
weatherHelper.addNewCityWeatherData(req.body.cityName);
}
return newAppointment;
})
.then(newAppointment => {
// do some other stuff
res.send(newAppointment);
})
.catch(err => {
error(err);
});
};
Function to add weather data:
exports.addNewCityWeatherData = (city) => {
console.log('City in addNewCityWeatherData', city);
getCurrentTrackingCities(cities => {
if(cities.indexOf(city) < 0) {
console.log(city + ' data not in weather');
getWeatherData(city, data => {
console.log('Got weather data');
addWeatherDataToDB(city, data);
});
} else {
console.log('City exists');
}
});
};
Function to get weather data from API:
getWeatherData = (city, callback) => {
console.log('getWeatherData called', city);
let url = `http://api.apixu.com/v1/forecast.json?key=${weatherApiKey}&q=${city}&days=${10}`
request(url, (err, res, body) => {
console.log('Weather data received body');
callback(body);
});
};
When testing, this feature fails and all console logs are printed except the 'Weather data received body' and the logs in consequent functions.
Here is my test:
describe.only('Weather data', function() {
let requestWithSession = request.defaults({jar: true});
let hashedPass = bcrypt.hashSync('testpass', null);
beforeEach((done) => {
new User({
'name': 'Test User',
'email': 'testuser#test.com',
'password': hashedPass
})
.save()
.then(() => {
let options = {
'method': 'POST',
'uri': testHost + '/login',
'form': {
'email': 'testuser#test.com',
'password': 'testpass'
}
};
requestWithSession(options, (err, res, body) => {
done();
});
});
}); // beforeEach
afterEach((done) => {
// remove test stuff from db
}); // afterEach
it('Adds weather data when an appointment with new city is posted', (done) => {
let options = {
'method': 'POST',
'uri': testHost + '/schedule',
'form': {
'title': 'Test title',
'description': 'Test description',
'start_date_time': '2017-07-19 01:00',
'end_date_time': '2017-07-19 02:00',
'cityName': 'New York',
'isTrackingWeather': 'true'
}
};
// post request to add appointment data
requestWithSession(options, (err, res, body) => {
if(err) {
console.log('DatabaseError in Weather Data');
throw {
type: 'DatabaseError',
message: 'Failed to create test setup data'
};
}
let options = {
'method': 'GET',
'uri': testHost + '/allweather'
};
// subsequesnt request to get updated weather data
requestWithSession(options, (err, res, body) => {
let found = false;
weatherData = JSON.parse(body);
// console.log('weatherData in test', weatherData);
weatherData.forEach(weather => {
if(weather.location && weather.location.name === 'New York') {
found = true;
}
});
expect(found).to.be.true;
done();
});
});
});
}); // Weather Data
Here is the terminal output:
Can anyone please tell me what am I doing wrong?
When you run your test is that the test suite make a request to your test server, and the code that handles the request in your test server makes another request to another host.
You do not get to see 'Weather data received body' because the request handled by your test server is not waiting for the request that the test server itself makes. addNewCityWeatherData has no callback and does not return a promise, so the code that calls it goes on its merry way without waiting for it to complete. You should modify it to allow for the calling code to wait for a result.
Also, I'm not seeing how the data from the request initiated by your test server is folded back into the request that comes from your test suite. You may have to add some code for that too, unless addWeatherDataToDB(city, data); is taking care of it automatically somehow.