How to get data from an API of the same origin? - cloudflare

I have a route (/user/{id}) that returns user information in json format. I want to display some user info on my index(/) page. So, in my handler for the index(/), I have
const host ="https//www.example.com"
const url = host + "/user/1"
const response = await fetch(url, init)
But, the thing is that it hangs and times out. I guess it is because, it is still serving the request for the index page, which is also making another request to /user/{id}. So, the second request doesn't seem to be served as the handler is occupied by the first request in my opinion.
Is there a way to fix this?
Thank you

Related

Expressjs send content after listen

I want to make a route in express js to send some content after 1000 ms.
Note: I cant use res.sendFile, it has to be a plain route.
This is the code for the route:
app.get('/r', (req,res)=>{
res.send("a")
setTimeout(()=>{
res.send("fter")
}, 1000)
}
app.listen(8080)
But I get the error: ERR_HTTP_HEADERS_SENT, I assume because the page has already been loaded.
I need my node program to send it after it has already been loaded, so I cant like send a html,js,css script to do it. Is it possible? I cant seem to find how.
Well, if that is not possible, what I am really trying to do is after the page has loaded, execute js or send a message that the page can receive from the node program, like if there was res.execute_js('postMessage(1)')
EDIT based on your edit: So as I understand you want a way to send different values from a node app endpoint without using socketio. I've managed to replicate a similar experimental behavior using readable streams. Starting off, instead of returning response to the request with res.send() you should be using res.write() In my case I did something like this:
app.post('/api', (req, res) => {
res.write("First");
setTimeout(() => {
res.write("Second");
res.end();
}, 1000);
});
This will write to a stream "First" then after 1000ms it'll write another "Second" chunk then end the stream, thus completing the POST request.
Now in the client, you'll make the fetch response callback async, get the ReadableStream from the request like so
const reader = response.body.getReader();
now we should be reading this stream, we'll first initialize an array to collect all what we're reading,
const output = [];
now to actually read the stream,
let finished, current;
while (!finished) {
({ current, finished} = await reader.read());
if (finished) break;
output.push(current);
}
if you read current in the loop, it'll contain each value we passed from res.write() and it should read twice, "First" and after 1000ms "Second".
EDIT: This is very experimental however, and I wouldn't recommend this in a production codebase. I'd suggest trying out socketio or a publish/subscribe mechanism instead.
Old answer: You're already sending "a" back, you should remove the first res.send() invocation at the top of the callback.
So, this is for all the people wondering. No you cannot do this with pure express (there is a workaround, so keep reading).
The reason you cant do this is because, when the user requests to the url, it sends them a response, and the browser renders it. You cant then tell it to change the response, as the browser has already received a response. Even if you send multiple, like with res.write, rather then res.send, the browser will just wait until it receives all the data.
Here are two workarounds:
    1. Use socket.io, cscnode, or another library to have events for updating text,
    2. Send hardcoded html, that updates text (1 was probably better)
That is all I think you can do.
More clarification on the socketio one is basically have an event for changing text that you can fire from node, and the browser will understand, and change the text.

multiple axios request in a react-native app: best practices

I have a question concerning a react native app and doing network requests.
I'm creating a react native app and as a backend I'm using NodeJS.
Users can sign up/sign in, and the refresh token is stored. Everytime the app opens, a new refresh token is fetched (if the user is signed in). This is an example of a network request that happens every time the app opens.
When the app opens and the user is signed in, I do a second network request (after the first network request for the access token was successful), to check if the data in redux has to be synchronized with the data in the database. I store some general information like the username locally + in the database. If - for any reason - I have to change the username in the database, I set the field "shouldSync" to true. The app sends a request to /api/sync, the controller sees that shouldSync = true and sends back all the data from the database to the user.
I also have a third network request that runs every time the app opens up: to check if there is a new version. I do a request to /api/version, with a response like "1.0.0". If the local version differs from the version in the response, I show an alert (only one time) saying there is a new version in the app store/play store.
When the app closes/goes in background mode, I also do a network request to the server to store the last active timestamp.
All these requests work, and I don't see any bottlenecks yet, but I have never built a production-graded app, so I have a few question concerning these network requests. I hope somebody can answer them.
Is it ok to do 3 separate network requests, or should I try to combine the three requests into one? I could combine the access token request + sync request (because these run when the user is signed in), but NOT the version request (because this request always has to run).
On some screens, I need dynamic data from the database/server. Sometimes I have 3-5 separate requests running at the same time. I'm using axios and I've made my code like this:
// first request
const requestOne = () => {
return axios({ ... });
};
// second request
const requestTwo = () => {
return axios({ ... });
};
// run these requests when the screen mounts
useEffect(() => {
axios.all([requestOne(), requestTwo()])
.then(axios.spread((requestOneRes, requestTwoRes) => {
// response from request one
console.log(requestOneRes.data);
// response from request two
console.log(requestTwoRes.data);
}));
}, []);
Is this a good example of combining multiple requests?
The most requests don't have a lot of response data. I have tested some requests in Postman and I've checked the response sizes of some requests, I've listed them here:
Everytime the app opens up:
/api/version: 463B request size / 231B response size
When the user signs in or signs up:
/sign-in: 476B request size / 1.16kB response size
/sign-up: 472B request size / 408B response size
When the app opens up + when the user is signed in:
/api/version: 463B request size / 231B response size
/refresh-access-token: 649B request size / 521B response size
/api/sync: 633B request size / 244B response size (NOT SYNCING) or 592B response size (SYNCING)
Total: +/- 1.6kB request size / +/- 1.25kB response size
I'm using express and BodyParser and I've set the limit to 2MB (2,000,000B).
app.use(bodyParser.json({ limit: 2000000 }));
I have installed request-stats in my NodeJS-backend to log all incoming requests. I'll all parts of my app separately and log all (big) requests, but for now I don't see any requests > 10kB, and even these are very rare.
Sorry for the long text. I want to be as clear as possible.
One recommendation, depending on the nature of your auth, is to remove the refreshToken expiry. Technically, the refresh token should be the retainer for the generation of new accessTokens (of which have an expiry). Refresh tokens themselves should not be regenerating without a relog by the end user. So instead of the user getting a new auth token, my way of assessing requests is 1. attempt the desired request, upon a 400 error, assess the response in axios for handling. If it is the result of an invalid/expired access token, request for a refresh with the stored refresh token. 2. Resend the prior request. This system removes the need for unnecessary request handling upon app start. Good luck!

How to distinguish between GET and POST

I'm writing a simple api for training using express. Here's my testing code:
var express = require('express');
var app = express();
app.post("/api/:var_name", function(req, res) {
res.send(req.params.var_name);
});
is simply testing to see if POST is working. When I call http://localhost:3000/api/1 I get Cannot GET /api/1, so the server is obviously interpreting the POST request as GET, what do I need to do to call POST instead?
Anything you call in the address bar of your browser will be sent via get. This is due to the fact that post-messages (and almost all other methods) do have a body-part. But there is no way for your browser to send additional information inside the body of the http packet.
If you want to test your routes for any method other than GET I would suggest you download a tool like postman.
https://www.getpostman.com/
BEWARE: This is my preference. You can of curse also use text based browsers like curl to test it.
The server interprets the request according to the verb you set in the HTTP request. If no method/verb is specified it is interpreted as GET(not sure about this part).
When you call that URL, you need to use the method as well. For example if you use the fetch API, you can call it like:
fetch(url, {method:"POST"})
If you're entering it in your browser and expect it to be interpreted as a post request, it's not. All browser url requests are GET. Use a tool like Postman to call different HTTP verbs. It's really useful when creating such APIs.
You can check out this answer on details of how to add body and headers to a post request: Fetch: POST json data

Intercept Requests With Custom Responses in PhantomJS?

Is there a way to intercept a resource request and give it a response directly from the handler? Something like this:
page.onRequest(function(request){
request.reply({data: 123});
});
My use case is for using PhantomJS to render a page that makes calls to my API. In order to avoid authentication issues, I'd like to intercept all http requests to the API and return the responses manually, without making the actual http request.
onResourceRequest almost does this, but doesn't have any modification capabilities.
Possibilities that I see:
I could store the page as a Handlebars template, and render the data into the page and pass it off as the raw html to PhantomJS (instead of a URL). While this would work, it would make changes difficult since I'd have to write the data layer for each webpage, and the webpages couldn't stand alone.
I could redirect to localhost, and have a server there that listens and responds to the requests. This assumes that it would be ok to have an open, un-authenticated version of the API on localhost.
Add the data via page.evaluate to the page's global window object. This has the same problems as #1: I'd need to know a-priori what data the page needs, and write server side code unique to each page.
I recently needed to do this when generating pdfs with phantom js.
It's slightly hacky, but seems to work.
var page = require('webpage').create(),
server = require('webserver').create(),
totallyRandomPortnumber = 29522,
...
//in my actual code, totallyRandomPortnumber is created by a java application,
//because phantomjs will report the port in use as '0' when listening to a random port
//thereby preventing its reuse in page.onResourceRequested...
server.listen(totallyRandomPortnumber, function(request, response) {
response.statusCode = 200;
response.setHeader('Content-Type', 'application/json;charset=UTF-8');
response.write(JSON.stringify({data: 'somevalue'}));
response.close();
});
page.onResourceRequested = function(requestData, networkRequest) {
if(requestData.url.indexOf('interceptme') != -1) {
networkRequest.changeUrl('http://localhost:' + totallyRandomPortnumber);
}
};
In my actual application I'm sending some data to phantomjs to overwrite request/responses, so I'm doing more checking on urls both in server.listen and page.onResourceRequested.
This feels like a poor-mans-interceptor, but it should get you (or whoever this may concern) going.

What method should I use for a login (authentication) request?

I would like to know which http method I should use when doing a login request, and why? Since this request creates an object (a user session) on the server, I think it should be POST, what do you think? But since the login request should be idempotent, it could be PUT, couldn't it?
Same question for a logout request, should I use the DELETE method?
If your login request is via a user supplying a username and password then a POST is preferable, as details will be sent in the HTTP messages body rather than the URL. Although it will still be sent plain text, unless you're encrypting via https.
The HTTP DELETE method is a request to delete something on the server. I don't think that DELETING an in memory user session is really what it's intended; more it's for deleting the user record itself. So potentially logout can be just a GET e.g. www.yoursite.com/logout.
I believe that you can translate LOGIN & LOGOUT methods into basic CRUD operations CREATE & DELETE. Since you are creating a new resource called SESSION and destroying it when logging out:
POST /login - creates session
DELETE /logout - destroys session
I would never do LOGOUT as GET just because anyone could make an attack just simply by sending an email with IMG tag or link to website where such an IMG tag exists. (<img src="youtsite.com/logout" />)
P.S.
Long time I was wondering how would you create a RESTful login/logout and it turned out it's really simple, you do it just like I described: use /session/ endpoint with CREATE and DELETE methods and you are fine. You could also use UPDATE if you want to update session in one way or another...
Here is my solution based on REST guides and recommendations:
LOGIN - create a resource
Request:
POST => https://example.com/sessions/
BODY => {'login': 'login#example.com', 'password': '123456'}
Response:
http status code 201 (Created)
{'token': '761b69db-ace4-49cd-84cb-4550be231e8f'}
LOGOUT - delete a resource
Request:
DELETE => https://example.com/sessions/761b69db-ace4-49cd-84cb-4550be231e8f/
Response:
http status code 204 (No Content)
For login request we should use POST method. Because our login data is secure which needs security. When use POST method the data is sent to server in a bundle. But in GET method data is sent to the server followed by the url like append with url request which will be seen to everyone.
So For secure authentication and authorization process we should use POST method.
I hope this solution will help you.
Thanks
Regarding the method for logging out:
In the Spring (Java Framework) documentation, they state that a POST request is preferred, since a GET makes you vulnerable to CSRF (Cross-Site Request Forgery) and the user could be logged out.
Adding CSRF will update the LogoutFilter to only use HTTP POST. This ensures that log out requires a CSRF token and that a malicious user cannot forcibly log out your users.
See: https://docs.spring.io/spring-security/site/docs/current/reference/html/web-app-security.html#csrf-logout
Logging in should also use POST (body can be encrypted, see the other answers).
For Login I use POST, below is my code for LOGIN method
I used Nodejs with Express and Mongoose
your router.js
const express = require("express");
const router = express.Router();
router.post("/login", login);
your controller.js
export.login = async(req, res) => {
//find the user based on email
const {email, password} = req.body;
try{
const user = awaitUser.findOne({email});
if(user==null)
return res.status(400).json({err : "User with
email doesnot exists.Please signup"});
}
catch(error){
return res.status(500).json({err :
error.message});
}
//IF EVERYTHING GOES FINE, ASSIGN YOUR TOKEN
make sure you have JWT installed
const token = jwt.sign({_id: user._id}, YOUR_SECRET_KEY);
res.cookie('t');
const {_id, name, email} = user;
return res.json({token, user : {_id, email, name}});
}