Aurelia HttpClient cancel requests - aurelia

I am trying to build an auto complete component and want to make it cancel unresolved requests to the server while they type.
I can find no documentation around this in the documentation for HttpClient. It mentions it IS cancellable (unlike fetch) but not how. https://aurelia.io/docs/plugins/http-services
Currently I have this which I cobbled together quite blindly, unsurprisingly it doesn't even abort the requests:
async searchTermChanged(newValue, oldValue) {
if (newValue.length < 3)
return;
if (this.promises.length) {
this.promises.forEach(x => x.abort());
//should probably remove too
}
var promise = this.httpClient.post(this.endpoint, { SearchTerm: newValue });
this.promises.push(promise);
var data = await promise;
var response = JSON.parse(data.response);
this.results = response;
}
}
Where can I find out more information on how to make cancellable requests? My google-fu is failing me.

Looks like you can do this:
this.client["pendingRequests"].forEach(request => {
request.abort();
});
I am having to do ["pendingRequests"] as I'm using TypeScript and the array does not seem to be within the definition.
Note: I am also using a scoped HttpClient per autocomplete, so that when it cancels all previous requests it will not accidentally cancel something else that the app is requesting.

Related

How to make an HTTP request within router.get method in Express

I'm making a simple API in express js. I've an end point where I'll make a call to GitHub api int turn. My Front-end application will utilize it. Here is my code:
api.js
const express = require('express');
const router = express.Router();
...
var http = require('http');
var https = require("https");
router.get('/github', function (req, res) {
// APPROACH 1: Failed : fetch is not defined
// fetch('https://api.github.com/users/tmtanzeel')
// .then(response => response.json())
// .then(json => console.log(json))
// APPROACH 2: Failed : throw er; // Unhandled 'error' event
/*try {
https.get('https://api.github.com/users/tmtanzeel',function (res) {
console.log(res);
})
} catch (error) {
...
}*/
});
Both my approaches are failing. I've almost no experience with Express. Please picth in
The second method is almost corrent. Add the error handler and send to the caller the data you just received.
https.get('https://api.github.com/users/tmtanzeel',function (apiRes) {
apiRes.pipe(res);
}).on('error', (e) => {
console.error(e);
res.status(500).send('Something went wrong');
});
Handling the response (stream) received from the API call can be done in two ways.
Using pipes which is automatic
Handle read events and manage the data writing manually
I have used the first approach.
However, it is very well recommended that you get sound knowledge in handling Streams if you use Node JS. Streams are the basis of Node JS requests and responses.
https://nodejs.dev/learn/nodejs-streams
You should use Express to handle incoming requests.
(for example if your webapp fetches data from your (express) server).
Read the docs: http://expressjs.com
Your first attempt failed because fetch is an implementation of the web-browser, not one of nodejs.
If you want to use fetch try: https://www.npmjs.com/package/node-fetch
its a well documented, easy to use fetch function.
From your examples, all seems fine except I can't see you sending the returned data to the client.
You can try something similar like adding res.send(data) to send the data and make it available on the /github route

Using vue router BeforeRouteEnter method to wait for http request to complete

Hi I'm trying to make it so that when a user opens a page it won't open until the data from the server is successfully retrieved so that it won't appear after 0.5s or so after the user enters.
To do this I read that I need to use BeforeRouteEnter but I'm having trouble finding information on how to properly use this, especially with waiting for my REST API to complete its request.
Here's the method I want to wait to complete before routing to my new component:
async getThread() {
const response = await postsService.fetchOneThread({
id: this.blockId,
topic: this.topicId,
thread: this.postId
});
this.thread = response.data;
}
so once this.thread = response.data only then do I want the page to display.
An important thing to note is that I am also passing through URL parameters to get the data which is the topic/black/post ID.
Here is my getUrlParam method also
url() {
let x = this.$route.params.topic.split('-');
this.topicId = x[0];
let y = this.$route.params.id.split('-');
this.blockId = y[0];
let post = this.$route.params.thread.split('-');
this.postId = post[1];
this.getThread();
}
Thanks
You need to move getThread inside beforeRouteEnter
beforeRouteEnter: (to, from, next) => {
postsService.fetchOneThread({
id: this.blockId,
topic: this.topicId,
thread: this.postId
}).then( response => {
//store the data somewhere accessible
next()
})
},
A few notes:
I don't think beforeRouteEnter can be async, so I'm using then to get the response
the component is not yet ready, so you can't access it yet, you need to save the information some other place so it can be read by the component. I'd suggest using Vuex for this.
If you decide to use Vuex than you need to add a mutation and call it from the promise's callback.
store.commit('ADD_THREAD', response.data)

In cloud code seems impossible to use Parse.Config.get() with express is it correct?

Is there any way to use Parse.Config.get() inside an expressjs app hosted in cloud code?
Looks very easy to use Parse.Object and Parse.User but with Parse.Config.get() the code is not deployed using "parse deploy"
We manage to use it adding the jssdk in html and using "frontend js" but haven't find any way to use in directly in express controllers.
Thanks
It seem to be related with some kind of permissions issues...
var Parse = require('parse-cloud-express').Parse;
var Util = require('util')
Parse.Cloud.define("currentConfig", function(request, response) {
console.log('Ran currentConfig cloud function.');
// why do I have to do this?
Parse.initialize(xxx, yyy);
Parse.Config.get().then(function(config) {
// never called
// ...
console.log(config.get('xxx'))
}, function(error) {
console.log(Util.inspect(error))
});
});
Output
Ran currentConfig cloud function.
{ code: undefined, message: 'unauthorized' }
Edited code which work for me:
var Parse = require('parse-cloud-express').Parse;
var Util = require('util')
Parse.initialize("appId", "restApiKey", "masterKey");
Parse.Cloud.define("currentConfig", function(request, response) {
console.log('Ran currentConfig cloud function.');
Parse.Cloud.useMasterKey();
Parse.Config.get().then(function(config) {
// never called
// ...
console.log(config.get('xxx'))
}, function(error) {
console.log(Util.inspect(error))
});
});
EDIT: Add solution :)

Prevent expressjs from sending text in bare response

I am using expressjs to implement api calls for my app. Much of the time I don't want to send back extra data in the body however expressjs sends the http status text in the response if you don't specify a body.
For res.send(200); outputs OK in the body, res.send(400); outputs Not Found and so on.
The problem is that my UI is expecting well formatted JSON or an empty body, and the bare strings break this convention. The work around I've found for now is to send res.send(200,{}); to send an empty object, but that's a pain in the butt to do that for every api call.
Is there any way to get around express returning this bare text on an empty response?
Without modifying the express library itself, you can create a middleware function that extends the functionality of res.send.
You can modify res.send so an empty string is added to its arguments when invoked only with a status code. This will prevent the name of the status code from being sent.
app.use(function(req, res, next) {
var send = res.send;
res.send = function() {
if (arguments.length == 1 && typeof arguments[0] == 'number') {
arguments[arguments.length++] = '';
}
return send.apply(res, arguments);
};
next();
});
app.get('/good', function(req, res) {
res.send(200);
});
app.get('/not-found', function(req, res) {
res.send(404);
});

How to test promises in Mongo(ose)/Express app?

I'm using promises to wrap asynchronous (Mongo) DB ops at the end of an (expressJS) route.
I want to try and figure out how to test the following code.
userService
userService.findOne = function (id) {
var deferred = q.defer();
User.findOne({"_id" : id})
.exec(function (error, user) {
if (error) {
deferred.reject(error);
} else {
deferred.resolve(user);
}
});
return deferred.promise;
};
userRoute
var user = function (req, res) {
var userId = req.params.id
, userService = req.load("userService");
// custom middleware that enables me to inject mocks
return userService.findOne(id)
.then(function (user) {
console.log("called then");
res.json({
msg: "foo"
});
}).catch(function (error) {
console.log("called catch");
res.json({
error: error
});
}).done();
};
Here's an attempt to test the above with mocha
userTest
it("when resolved", function (done) {
var jsonSpy = sinon.spy(httpMock.res, "json")
, httpMock = require("/path/to/mock/http/object")
, serviceMock = require("/path/to/mock/service"),
, deferred = q.defer()
, findStub = sinon.stub(serviceMock, "findOne")
.returns(deferred.promise)
, loadStub = sinon.stub(httpMock.req, "load")
.returns(serviceMock),
retPromise;
// trigger route
routes.user(httpMock.req, httpMock.res);
// force promise to resolve?
deferred.resolve();
expect(jsonSpy.called).to.be.true; // fails
// chai as promised
retPromise = findStub.returnValues[0];
expect(retPromise).to.be.fulfilled; // passes
});
the http mock is just an empty object with no-ops where expressJS would normally start rendering stuff. I've added some logging inside those no-ops to get an idea on how this is hanging together.
This isn't really working out. I want to verify how the whole is integrated, to establish some sort of regression suite - but I've effectively mocked it to smithereens and I'm just testing my mocks (not entirely successfully at that).
I'm also noticing that the console logs inside my http mocks triggered by then and catch are firing twice - but the jsonSpy that is invoked inside the actual code (verified by logging out the sinon spy within the userRoute code) is not called in test.
Has anyone got some advice on integration testing strategies for express apps backed by Mongo?
It looks to me like you're not giving your promise an opportunity to fire before you check if the result has been called. You need to wait asynchronously for userService.findOne()'s promise chain to complete before jsonSpy.called will be set. Try this instead:
// start of code as normal
q.when(
routes.user(httpMock.req, httpMock.res),
function() { expect(jsonSpy.called).to.be.true; }
);
deferred.resolve();
// rest of code as normal
That should chain off the routes.user() promise and pass as expected.
One word of caution: I'm not familiar with your framework, so I don't know if it will wait patiently for all async events to go off. If it's giving you problems calling back into your defer chain, you may want to try nodeunit instead, which handles async tests very well (IMO).