Node async axios - async-await

Help with Node and async problem.
In the first function, I am getting token from external api -
const Token = function getToken(data)
return axios(config)
.then((response) =>
this.response = response.data;
return this.response.access_token;)
.catch(function (error)
console.log(error);
);
Then, in the following function, I can output this token to the screen -
const myToken = Token(data);
myToken.then(function (result)
console.log(result); //here I see a real token
);
how then could I use this token?
Trying to do so -
const test = myToken;
console.log(test);
gives - Promise pending

Assign token value to variable in the outer scope inside then
let token = '';
myToken.then(function (result)
token = result;
);

You can use await -
const token = await myToken
await will unpack the value of promise, similar to .then() but let's you use a more synchronous code style.
Note you'll also need to decorate the function that the above code lives within with the async keyword.
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await

Related

Is it possible to return or await for return of cypress intercept?

I would like to get the response of an intercept cypress call while running an e2e test:
const registerUser = async (username, password)=>{
cy.visit('<user_registration_url');
cy.intercept('/registration').as('registration');
cy.get('input#username').type(username);
cy.get('input#password').type(password);
cy.get('button#submit').click()
// Expected response:
//{statusCode: 200, body: {userId: <string>}}
const result = await cy.wait('#registration');
const userId = result.response.body.userId;
return userId
it('should test something with a newly registered user', ()=>{
const userId = registerUser('foobar', 'password');
// ... keep testing using the userId which was generated on the backend.
});
No, this won't work.
Cypress is asynchronous, so the commands won't return any data that you can assign to variables. You can read more on then in Cypress docs.
You can get to the response like so:
cy
.wait('#registration')
.then(response => {
// some other code
});
or you can check e.g. a status code like so:
cy
.wait('#registration')
.its('response.statusCode')
.should('eq', 201);
You can see many examples on the page for cy.intercept command.
So indeed as #pavelsman mentioned there is no async/await syntax for cypress. In order to make utility functions one can return a chainable as in this example:
const registerUser = (username, password)=>{
cy.visit('<user_registration_url');
cy.intercept('/registration').as('registration');
cy.get('input#username').type(username);
cy.get('input#password').type(password);
cy.get('button#submit').click()
// Expected response:
//{statusCode: 200, body: {userId: <string>}}
return cy.wait('#registration');
it('should test something with a newly registered user', ()=>{
registerUser('foobar', 'password').then(result=>{
const userId = result.response.body.userId;
// ... keep testing using the userId which was generated on the backend.
});
});

I can't get header from backend in vuejs

I have a a spring boot backend that validates user login credentials. After validating the user it sends a login token in its response header. This part definitly works because I have seen it work in postman:
Now I am trying to get the token into my vuejs front end by doing the following:
import axios from 'axios'
const databaseUrl = 'http://localhost:9090/api'
const datbaseUrlBase = 'http://localhost:9090'
async function getSubjects(){
const result = await axios.get(`${databaseUrl}/subject`)
return result.data
}
async function updateSubject(subject){
let body = {
"name": subject.name,
"first_name": subject.first_name,
"date_of_birth": subject.date_of_birth
}
let result = await axios.put(`${databaseUrl}/subject/${subject.subjectid}`, body)
return result.data
}
async function getSubject(id){
let result = await axios.get(`${databaseUrl}/subject/${id}`)
return result.data
}
async function getSimulationsForSubject(id){
let result = await axios.get(`${databaseUrl}/subject/${id}/simulation`)
return result.data
}
async function deleteSubject(id){
await axios.delete(`${databaseUrl}/subject/${id}`)
}
async function makeSubject(subject){
await axios.post(`${databaseUrl}/subject`, subject)
}
async function updateDiagnose(diagnose, id){
await axios.put(`${databaseUrl}/subject/${id}/diagnose/${diagnose.diagnoseid}`, diagnose)
}
async function addSymptomToDiagnose(symptom, diagnoseid, subjectid){
await axios.post(`${databaseUrl}/subject/${subjectid}/diagnose/${diagnoseid}/symptom`, symptom)
}
async function updateSymptom(symptom_id, symptom, subjectid, diagnoseid){
await axios.put(`${databaseUrl}/subject/${subjectid}/diagnose/${diagnoseid}/symptom/${symptom_id}`, symptom)
}
async function getDiagnoseForSubject(diagnoseid, subjectid){
let result = await axios.get(`${databaseUrl}/subject/${subjectid}/diagnose/${diagnoseid}`)
return result.data
}
async function deleteSymptomForDiagnose(subjectid, diagnoseid, symptomid){
await axios.delete(`${databaseUrl}/subject/${subjectid}/diagnose/${diagnoseid}/symptom/${symptomid}`)
}
async function getStatisticsForSimulation(subjectid, simulationid){
let result = await axios.get(`${databaseUrl}/subject/${subjectid}/simulation/${simulationid}/statistics`)
return result.data
}
async function login(login){
let result = await axios.post(`${datbaseUrlBase}/login`, login)
return result.headers
}
export default{
getSubjects,
updateSubject,
getSubject,
getSimulationsForSubject,
deleteSubject,
makeSubject,
updateDiagnose,
addSymptomToDiagnose,
getDiagnoseForSubject,
deleteSymptomForDiagnose,
updateSymptom,
getStatisticsForSimulation,
login
}
Notice the login function above. Whenever I run this code the console.log gives undefined in the browser.
And the console.log(result.headers) gives this:
Is there anyway of accessing this token in my vuejs frontend?
If the server is cross-origin then browser CORS dictates that only a handful of default headers are accessible in a response.
You need to either have a matching origin, or enable the Access-Control-Expose-Headers header by setting it in your response like this:
Access-Control-Expose-Headers: token
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers

How can I pass values between koa-router routes

I wanted to move the authentication procedure from all routes into one route (koa-router provides the all() middleware for all methods on a router for this). However, in the process, I decode a token whose decoding I need for further execution. How can I access this decoded token from another route?
const Router = require('koa-router');
const router = new Router({ prefix: '/test' });
router.all('/', async (ctx, next) => {
//decode
await next();
})
router.get('/', async ctx=> {
// Here I need to access decoded, too
});
the Koa Context object encapsulates the request, response and a state object, along with much more. This state object is the recommended namespace where you can pass data between middleware.
Modifiying the provided example gets:
const http = require('http')
const Koa = require('koa')
const Router = require('koa-router')
const app = new Koa()
const router = new Router({ prefix: '/test' })
router.all('/', async (ctx, next) => {
// decode token
const x = 'foo'
// assign decoded token to ctx.state
ctx.state.token = x
await next()
})
router.get('/', async ctx=> {
// access ctx.state
console.log(ctx.state.token)
})
app.use(router.routes())
http.createServer(app.callback()).listen(3000)
Navigate to http://localhost:3000/test and see the decoded token logged to the console.

How do I blend a promise with an observable?

I'm having trouble promises and observables. I have a handful of http requests which are defined in a package using promises. In the rest of my code I am using observables for various things, including other http calls. In one particular section I am checking to see if the user's bearer token is expired and if so then I get a new token and then proceed with the rest of the call.
if (!token || token.exp < Math.round((new Date()).getTime() / 1000)) {
from(this._store.refreshBearerToken())
.pipe(flatMap(resp => {
let newToken = resp.data;
newToken.exp = (new Date()).getTime() / 1000 + newToken.expires_in;
localStorage.setItem('token', JSON.stringify(newToken))
options = options || {};
options.headers = new HttpHeaders({
"Authorization": `${newToken.token_type} ${newToken.access_token}`,
"Content-Type": "application/json"
});
return this._http$.request<T>(method, url, options as Object).pipe(share());
}));
}
Bearer Token method:
async refreshBearerToken() {
const response = await this._q2.sources.requestExtensionData({
route: "refreshBearerToken"
});
console.log(response);
return response;
}
Since this._store.refreshBearerToken returns a promise I wrapped the call in a from to convert it to an observable. This compiles but when it runs I get "Cannot read property 'pipe' of undefined".
How can I convert this promise to an observable so that I can refresh the token and then continue with the rest of the call?
Edit:
I am importing from via import { Observable, from } from "rxjs";.
So, I thought the error was coming from the line .pipe(flatMap(resp =>... but I was wrong. The error is coming from the method which is calling this.
GetInitialLinkList(): Observable<Institution[]>
{
let base = { 'MemberId': localStorage.getItem('memberId') };
let ins = localStorage.getItem("initialInstitutionList");
if (ins)
{
return of(JSON.parse(ins));
}
return this._settingsService.get().pipe(
flatMap(settings =>
{
this._settings = settings;
return this._api.request<Institution[]>("Post", `${this._settings.mea}/GetInitialLinkList`, { body: base })
.pipe(
retry(1),
catchError(this.handleError)
)
.pipe(flatMap(instList =>
{
localStorage.setItem("initialInstitutionList", JSON.stringify(instList));
return of(instList);
}))
}));
}
and that is being subscribed to inside my component:
private GetLinkList()
{
this.showWaiting.emit(true);
this._data.GetInitialLinkList().subscribe((result) =>
{
this.initialList = result;
this.showWaiting.emit(false);
});
}
From what Brandon said (I forgot to return /facepalm...) I added the return so I have return from(this._store.refreshBearerToken()) which changed my error to
ERROR Error Code: undefined
Message: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
defaultErrorLogger # core.js:6014
Can you show the actual error and the line in the code that the error occurs on? Also show where and how you import from.
I notice your code snippet does not return the observable it builds up via from(...).pipe(...) nor does it subscribe to it. It might help to show how your code actually uses this observable.

redux test Actions must be plain objects. Use custom middleware for async actions

I am not using redux-thunk. this keeps error-ing and I am not sure how to fix it. The examples I see online use redux-thunk which I am not using
my repo is here and the file I am trying to test is in tests\actions\...
My action that is being called in the test
import axios from "axios";
var CancelToken = axios.CancelToken;
let fetch_cancel;
export const FETCH_CATEGORIES = "fetch_categories";
export async function fetchCategories() {
fetch_cancel && fetch_cancel();
const request = await axios.get(
`https://d1i9eedhsgvpdh.cloudfront.net/production-plentific-static/api-cache/find-a-pro/api/v1/categories/all.json`,
{
cancelToken: new CancelToken(function executor(c) {
// An executor function receives a cancel function as a parameter
fetch_cancel = c;
})
}
);
return {
type: FETCH_CATEGORIES,
payload: request
};
}
The error message means that your actions must be plain objects. For example:
store.dispatch({
type: 'ADD_TODO',
text: 'Understand the middleware'
})
If you make an async request, you can't just return an object, because you need to wait for the request to finish. If you return too early, you return a Promise.
However, I cannot reproduce your error in your sandbox.

Resources