Is there any way to make AWS SSM getparameters sync?
Requirement :
The secret key, id stored in the SSM store should be accessible on the server up.
Using Node and express in the backend as a reverse proxy, so we have a constant.js file, it stores all the API URLs, paths, etc.
constats.js file
const api1url = 'http://example.com/path1'
const api1_secretkey = 'secret_key'
..................
module.export = {api1url,api1_secretkey}
So we wanted to call the ssm stuff in here before setting the const variables
const SSM = require('aws-sdk/clients/ssm');
const ssm = new SSM();
const params = {
Names: ['/secret_key_api_1', '/secret_key_api_2'],
WithDecryption: true,
};
const parameterList = await ssm.getParameters(params).promise();
I understand that await cant be without async, I just wanted to convey what I am expecting, without it being an async call or whether it be in the callback of getparameters.
const api1url = 'http://example.com/path1'
const api1_secretkey = parameterList.Parameter[1].Value
But since it is an async call we are not able to wait for it,tried doing it in a separate async function and then returning the data but since the function is still async having difficulties.
Not exactly issue wrt to an async function, the async function works as expected, but I want it to be synced, the AWS get parameter function is async. because of this I am not able to do something like const api1_secretkey = process.env.secret_key , this value will be obtained when js file is executed line by line. but since i am waiting for the secret key to come from async func by the time the line by line occurs const api1_secretkey = parameterList.Parameter[1].Value , the promise is still not resolved so undefined will sit. Even if i make a .then on the get params i can make this const api1_secretkey = parameterList.Parameter[1].Value after promise resolved. but since the export module is already done the other file carries undefined in the secret key even after it is changed on promise resolve.
Related
I'm building an api with NextJS and MongoDB. I do a basic setup on the top of the API file:
const { db } = await connectToDatabase();
const scheduled = db.collection('scheduled');
and I continue the code with my handler function:
export default async function handler(req, res) {
otherFunctionCalls()
...
}
const otherFunctionCalls = async () => {
...
}
I know await will work only within an async function, but I would like to use the scheduled constant in other functions what the handler calls, that's why I need to call it on the top.
If I put the constant to every single function, then it's code duplication.
What's the best practice to access to scheduled constant? Should I add the otherFunctionCalls declaration into the handler function?
The complete error what I got:
Module parse failed: The top-level-await experiment is not enabled (set experiments.topLevelAwait: true to enabled it)
File was processed with these loaders:
* ./node_modules/next/dist/build/babel/loader/index.js
You may need an additional loader to handle the result of these loaders.
Error: The top-level-await experiment is not enabled (set experiments.topLevelAwait: true to enabled it)
In the comments you've said you want to find another solution rather than enabling the top-level await experiment in the tool you're using.
To do that, you'll have to adjust the module code to handle the fact that you don't have the scheduled collection yet, you just have a promise of it. If the only exported function is handler and all of the other functions are going to be called from handler, they it makes sense to handle that (no pun!) in handler, along these lines:
// A promise for the `scheduled` collection
const pScheduled = connectToDatabase().then(db => db.collection("scheduled"));
export default async function handler(req, res) {
const scheduled = await pScheduled;
await otherFunctionCalls(scheduled);
// ...
}
const otherFunctionCalls = async (scheduled) => {
// ...use `scheduled` here...
};
There are lots of ways you might tweak that, but fundamentally you'll want to get the promise (just once is fine) and await it to get its fulfillment value anywhere you need its fulfillment value. (For the avoidance of double: await doesn't re-run anything; if the promise is already fulfilled, it just gives you back the fulfillment value the promise already has.)
I'm writing a NodeJS based backend (cloud-function), and I got trouble in the situation as follow:
const context = createContext()
async main(event){
// I need to cache something here
context.set("I need this")
await someDeepFunction()
}
async function someDeepFunction() {
// ...... and got it in a very-very-deep logic
const val = context.get()
}
The main problem is that it's an async function, and when the NodeJS is handling the next request whiling waiting for the last, the context should switch automatically to ensure never lack the cache data of the first request.
I found a javascript project https://github.com/ealush/context, but it's not able to create context when use async.
Is it possible to implement and how?
I need to fetch json data from my realtime db in firebase and set a variable to it. I tried doing that in the code below
useEffect(() => {
let database = firebase.database();
database.ref().on('value', async (snapshot) => {
await setQuestions(snapshot.val());
console.log('questions here ', questions)
})
},[]);
The console.log outputs questions here null, instead of logging the actual data. I know this is a issue involving the order the lines are being executed because I've proven that I am actually pulling the data from the database. It's just not finishing pulling it where I need it to.
From my understanding, await would stop execution within the async block until the line of code with await on it finished. However, that's not happening. So either I misunderstood how async functions work or I'm not putting the async or await keyword where I need to be. Any help is appreciated.
EDIT: questiona is defined. In my code it appears as below
const [questiona, setQuestions] = useState(null);
await has no effect unless the value on the RHS is a promise.
setQuestions is, I assume, the set part of a useState hook. It does not return a promise.
(If it did then the questiona variable (which I assume is the data part of that hook) would not update in the current scope anyway.)
If you want to see what questiona is, then log it on the next render of the React component you are working in.
const [questiona, setQuestions] = useState(someDefaultValue);
console.log(questiona);
useEffect(() => {
let database = firebase.database();
database.ref().on(
'value',
(snapshot) => setQuestions(snapshot.val())
);
},[]);
The issue in the above code is that, when we declare any function as async, it returns a promise.
You need to create a separate async function outside useEffect and call it from the useEffect.
There seems to be so many different ways to do this, but I am trying to use just sinon, sinon-test, chai/mocha, axios, httpmock modules. I am not able to successfully mock a GET call made using axios. I want to be able to mock the response from that axios call so the unit test won't actually have to make the external API request.
I've tried setting up a basic unit test by creating a sandbox, and using sinon stub to set up a GET call and specify the expected response. I'm unfamiliar with JavaScript and NodeJS.
// Main class (filename: info.js)
function GetInfo(req, res) {
axios.get(<url>).then(z => res.send(z.data));
}
// Test class (filename: info.test.js)
it ("should return info", () => {
const expectedResponse = "hello!";
const res = sinon.spy();
const aStub = sinon.stub(axios, "get").resolves(Promise.resolve(expectedResponse));
const req = httpMock.createRequest({method:"get", url:"/GetInfo"});
info.GetInfo(req, res);
// At this point, I need to evaluate the response received (which should be expectedResponse)
assert(res.data, expectedResponse); // data is undefined, res.status is also undefined
// How do I read the response received?
});
I need to know how to read the response that is supposed to be sent back (if it is being captured in the first place by sinon).
I'm assuming the response you're wanting to check is the z.data being passed to res.send(z.data)
I don't think your Sinon Spy is being set up correctly.
In your example, res is a function created by sinon. This function won't have a property data.
You probably want to create a spy like this:
const res = {
send: sinon.spy()
}
This gives you a res object which has a spy with the key send. You can then make assertions about the parameters used to call res.send
it ("should return info", () => {
const expectedResponse = "hello!";
const res = {
send: sinon.spy()
};
const aStub = sinon.stub(axios, "get").resolves(Promise.resolve(expectedResponse));
const req = httpMock.createRequest({method:"get", url:"/GetInfo"});
info.GetInfo(req, res);
// At this point, I need to evaluate the response received (which should be expectedResponse)
assert(res.send.calledWith(expectedResponse)); // data is undefined, res.status is also undefined
});
Dont know if this helps but you may not be getting the correct response because resolves is a return with a promise wrap over it.
So by using resolves and inside it a Promise.resolve you are actually returning Promise wrap in a Promise.
Maybe you can try changing the code to the one below.
const aStub = sinon.stub(axios, "get").resolves(Promise.resolve(expectedResponse));
to
const aStub = sinon.stub(axios, "get").resolves(expectedResponse);
I will appreciate if you help me with the following case:
Given function:
async function getAllProductsData() {
try {
allProductsInfo = await getDataFromUri(cpCampaignsLink);
allProductsInfo = await getCpCampaignsIdsAndNamesData(allProductsInfo);
await Promise.all(allProductsInfo.map(async (item) => {
item.images = await getProductsOfCampaign(item.id);
}));
allProductsInfo = JSON.stringify(allProductsInfo);
console.log(allProductsInfo);
return allProductsInfo;
} catch(err) {
handleErr(err);
}
}
That function is fired when server is started and it gathers campaigns information from other site: gets data(getDataFromUri()), then extracts from data name and id(getCpCampaignsIdsAndNamesData()), then gets products images for each campaign (getProductsOfCampaign());
I have also express.app with following piece of code:
app.get('/products', async (req, res) => {
if (allProductsInfo.length === undefined) {
console.log('Pending...');
allProductsInfo = await getAllProductsData();
}
res.status(200).send(allProductsInfo);
});
Problem description:
Launch server, wait few seconds until getAllProductsData() gets executed, do '/products' GET request, all works great!
Launch server and IMMEDIATELY fire '/products' GET request' (for that purpose I added IF with console.log('Pending...') expression), I get corrupted result back: it contains all campaigns names, ids, but NO images arrays.
[{"id":"1111","name":"Some name"},{"id":"2222","name":"Some other name"}],
while I was expecting
[{"id":"1111","name":"Some name","images":["URI","URI"...]}...]
I will highly appreciate your help about:
Explaining the flow of what is happening with async execution, and why the result is being sent without waiting for images arrays to be added to object?
If you know some useful articles/specs part covering my topic, I will be thankful for.
Thanks.
There's a huge issue with using a global variable allProductsInfo, and then firing multiple concurrent functions that use it asynchronously. This creates race conditions of all kinds, and you have to consider yourself lucky that you got only not images data.
You can easily solve this by making allProductsInfo a local variable, or at least not use it to store the intermediate results from getDataFromUri and getCpCampaignsIdsAndNamesData - use different (local!) variables for those.
However, even if you do that, you're potentially firing getAllProductsData multiple times, which should not lead to errors but is still inefficient. It's much easier to store a promise in the global variable, initialise this once with a single call to the info gathering procedure, and just to await it every time - which won't be noticeable when it's already fulfilled.
async function getAllProductsData() {
const data = await getDataFromUri(cpCampaignsLink);
const allProductsInfo = await getCpCampaignsIdsAndNamesData(allProductsInfo);
await Promise.all(allProductsInfo.map(async (item) => {
item.images = await getProductsOfCampaign(item.id);
}));
console.log(allProductsInfo);
return JSON.stringify(allProductsInfo);
}
const productDataPromise = getAllProductsData();
productDataPromise.catch(handleErr);
app.get('/products', async (req, res) => {
res.status(200).send(await productDataPromise);
});
Of course you might also want to start your server (or add the /products route to it) only after the data is loaded, and simply serve status 500 until then. Also you should consider what happens when the route is hit after the promise is rejected - not sure what handleErr does.