How to use fetch from Sapper client - javascript

This is my server.js file
import { json } from 'body-parser';
import sirv from 'sirv';
// import polka from 'polka';
import compression from 'compression';
import * as sapper from '#sapper/server';
import express from 'express';
const { PORT, NODE_ENV } = process.env;
const dev = NODE_ENV === 'development';
express() // You can also use Express
.use(
json(),
compression({ threshold: 0 }),
sirv('static', { dev }),
sapper.middleware()
)
.listen(PORT, err => {
if (err) console.log('error', err);
});
This is the endpoint I'm trying to reach
located in src/routes/contact.js
export async function post(req, res, next) {
res.setHeader('Content-Type', 'application/json')
const data = req.body
console.log(data);
return res.end(JSON.stringify({ success: true }))
}
And this is the fetch
fetch('/contact', {
method: 'POST',
body: 'Hola mundo',
headers: {
'Content-Type': 'application/json'
}
}).then(() => {
console.log('Form submitted');
})
But network reports NOT FOUND, What I'm missing here? I thought it was a matter of polka then I switched to Express but the issue remains
PD: This is my reference Post for the structure
fetch post is giving me undefined for the posted data?

Related

getting "unexpected end of file" axios error while making a get request in this small nodejs app

I have been getting this error in this small nodejs app while trying to learn using axios on the backend to make request. "unexpected end of file".
axios request file
import axios from "axios";
export const getData = async () => {
let data;
try {
const response = await axios.get(
"https://jsonplaceholder.typicode.com/users"
);
console.log(response);
data = response;
} catch (error) {
console.log(error.message);
return;
}
return data;
};
server.js
import express from "express";
import cors from 'cors';
import axios from "axios";
import { getData } from "./utils/getData.js";
const app = express();
app.use(cors());
app.use(express.json());
app.get("/", async (req, res) => {
let users;
users = await getData();
res.send(users);
})
app.listen(5000, () => {
console.log("server listening at port 5000");
})
You can add below header encoding to your request.
axios.get("url", {
headers: { "Accept-Encoding": "gzip,deflate,compress" }
});
the Brotli decompression bug was fixed in v1.2.2
Bro, go to Package.json--> in dependencies --> check for axios ---> Add 'axios' : '1.1.3'.
This will solve your issue.

How to run proxy for react/redux application on AWS Amplify

I have recently Implemented Proxy (in Express.js) for my React App to hide API URL's when making a request. It has been working perfectly fine when I run it the proxy and app on localhost. Now that I'm ready to deploy My application to AWS Amplify, I am a little confused as to how I get my proxy to run there since I'm not manually starting the app and proxy from the CLI. Do I need to use an EC2 instance instead or can I achieve this using Amplify?
Any Help would be greatly appreciated!
This is what my Project Directory Looks like :
This is what my Server.js looks like :
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const axios = require('axios');
var cors = require('cors')
app.use(cors())
app.use(bodyParser.urlencoded({
extended: false
}));
const BASE_URL = 'https://my-aws-lambda-base-url/dev'
const port = process.env.PORT || 5000;
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});
app.listen(port, () => console.log(`Listening on port ${port}`));
app.use('/contact', require('body-parser').json(), async (req, res) => {
try {
await axios.post(`${BASE_URL}/contact`, {
Email : req.body.Email,
type : req.body.type,
Message : req.body.Message,
Phone : req.body.Phone
},
{
headers: {
'Content-Type': 'application/json',
}
},
).then(function(response) {
const result = response.data
console.log(result)
if(result && result.Message) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(result))
}
}).catch((e)=> {
console.log(e)
res.send(false)
})
} catch (error) {
console.log(error)
res.send(false)
}
});
And this is how I make the request from In my React App
export async function sendContact(request){
try {
if(!request.Phone)
request.Phone = false
if(request.textMe){
request.type = "BOTH"
}
else{
request.type = "EMAIL"
}
let result ;
await fetch('/contact', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
Email : request.Email,
type : request.type,
Message : request.Message,
Phone : request.Phone
})
}
).then(async response =>
await response.json()
).then(data =>
result = data
).catch((e)=> {
notifyError(e.response.data.Message)
return false
})
console.log(result)
return result
} catch (error) {
console.log(error)
}
}
And Finally, Here's My Build Script from Amplify for my application
version: 1
frontend:
phases:
preBuild:
commands:
- npm i
build:
commands:
- npm run build
artifacts:
baseDirectory: build
files:
- '**/*'
cache:
paths:
- node_modules/**/*
P.S : I do also have "proxy": "http://localhost:5000" added to my Package.json
EDIT :
I tried Using a Background task manager like PM2 to run post build in the build script but that still did not work (although it did locally)
I ended up spinning up a proxy lambda as my API gateway (middle man) between my client and server. I also have the proxy denying any requests not coming from my website.

Express.js Csurf working in postman but not React.js

I'm trying to setup CSRF tokens so that I can do a number of checks before issueing a token to the client to use in future requests.
Taking the guidance from the csurf documentation, I've setup my express route with the following:
const express = require('express');
const router = express.Router({mergeParams: true});
const csurf = require('csurf');
const bodyParser = require('body-parser');
const parseForm = bodyParser.urlencoded({ extended: false });
const ErrorClass = require('../classes/ErrorClass');
const csrfMiddleware = csurf({
cookie: true
});
router.get('/getCsrfToken', csrfMiddleware, async (req, res) => {
try {
// code for origin checks removed for example
return res.json({'csrfToken': req.csrfToken()});
} catch (error) {
console.log(error);
return await ErrorClass.handleAsyncError(req, res, error);
}
});
router.post('/', [csrfMiddleware, parseForm], async (req, res) => {
try {
// this returns err.code === 'EBADCSRFTOKEN' when sending in React.js but not Postman
} catch (error) {
console.log(error);
return await ErrorClass.handleAsyncError(req, res, error);
}
});
For context, the React.js code is as follows, makePostRequest 100% sends the _csrf token back to express in req.body._csrf
try {
const { data } = await makePostRequest(
CONTACT,
{
email: values.email_address,
name: values.full_name,
message: values.message,
_csrf: csrfToken,
},
{ websiteId }
);
} catch (error) {
handleError(error);
actions.setSubmitting(false);
}
Postman endpoint seems to be sending the same data, after loading the /getCsrfToken endpoint and I manually update the _csrf token.
Is there something I'm not doing correctly? I think it may be to do with Node.js's cookie system.
I think your problem is likely to be related to CORS (your dev tools will probably have sent a warning?).
Here's the simplest working back-end and front-end I could make, based on the documentation:
In Back-End (NodeJS with Express) Server:
In app.js:
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var bodyParser = require('body-parser')
var express = require('express')
const cors = require('cors');
var csrfProtection = csrf({ cookie: true })
var parseForm = bodyParser.urlencoded({ extended: false })
var app = express()
const corsOptions = {
origin: "http://localhost:3000",
credentials: true,
}
app.use(cors(corsOptions));
app.use(cookieParser())
app.get('/form', csrfProtection, function (req, res) {
res.json({ csrfToken: req.csrfToken() })
})
app.post('/process', parseForm, csrfProtection, function (req, res) {
res.send('data is being processed')
})
module.exports = app;
(make sure you update the corsOptions origin property to whatever your localhost is in React.
In Index.js:
const app = require('./app')
app.set('port', 5000);
app.listen(app.get('port'), () => {
console.log('App running on port', app.get('port'));
});
In React:
Create file "TestCsurf.js" and populate with this code:
import React from 'react'
export default function TestCsurf() {
let domainUrl = `http://localhost:5000`
const [csrfTokenState, setCsrfTokenState] = React.useState('')
const [haveWeReceivedPostResponseState, setHaveWeReceivedPostResponseState] = React.useState("Not yet. No data has been processed.")
async function getCallToForm() {
const url = `/form`;
let fetchGetResponse = await fetch(`${domainUrl}${url}`, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"xsrf-token": localStorage.getItem('xsrf-token'),
},
credentials: "include",
mode: 'cors'
})
let parsedResponse = await fetchGetResponse.json();
setCsrfTokenState(parsedResponse.csrfToken)
}
React.useEffect(() => {
getCallToForm()
}, [])
async function testCsurfClicked() {
const url = `/process`
let fetchPostResponse = await fetch(`${domainUrl}${url}`, {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"xsrf-token": csrfTokenState,
},
credentials: "include",
mode: 'cors',
})
let parsedResponse = await fetchPostResponse.text()
setHaveWeReceivedPostResponseState(parsedResponse)
}
return (
<div>
<button onClick={testCsurfClicked}>Test Csurf Post Call</button>
<p>csrfTokenState is: {csrfTokenState}</p>
<p>Have we succesfully navigates csurf with token?: {JSON.stringify(haveWeReceivedPostResponseState)}</p>
</div>
)
}
Import this into your app.js
import CsurfTutorial from './CsurfTutorial';
function App() {
return (
<CsurfTutorial></CsurfTutorial>
);
}
export default App;
That's the simplest solution I can make based on the CSURF documentations example. It's taken me several days to figure this out. I wish they'd give us a bit more direction!
I made a tutorial video in case it's of any help to anyone: https://youtu.be/N5U7KtxvVto

fetch post is giving me undefined for the posted data?

Learning how to use Sapper. I have a component with form (the form has one field to enter an email address) and use fetch to post the data to the serverhandle. When I post the data and try to log the data I posted, it logs Undefined. I have no idea why and need help to figure it out.
Here is my component with the form and fetch post code:
<script>
let emailvalue
let url = "posthandle"
async function handleSubmit(event) {
console.log(event);
console.log(event.target);
emailvalue = event.target.email.value;
console.log("this is from the variable--data--:" + content)
// ******** Here is the Fetch() code
fetch(url, {
method: 'POST',
body: JSON.stringify(emailvalue),
headers: {
'Content-Type': 'application/json'
}
})
.then(r => {
//this is gives the error that res stream is locked console.log(r.json())
consolde.log(r)
r.json()
.then(function(result) {
// this logs [object object]
console.log("let us see" + result)
})
})
.catch(err => {
// POST error: do something...
console.log('POST error', err.message)
})
//post code example https://stackoverflow.com/questions/55393685/js-sapper-posting-data-to-server-the-right-way
}
</script>
<p> {emailvalue} </p>
<form on:submit|preventDefault="{handleSubmit}">
<label for="email">Email</label>
<input required type="email" id="email" />
<button type="submit">Create account</button>
</form>
The line that reads: console.log("let us see" + result) is showing [object Object] and I don't understand why?
My handle to manage the post :
export async function post(req, res, next) {
res.setHeader('Content-Type', 'application/json')
/* Retrieve the data */
var data = req.body;
// Do something with the data...
// it logs Undefined. Why?
console.log("Here's the posted data:" + data );
/* Returns the result */
return res.end(JSON.stringify({ success: true }));
}
why data is undefined? Is the code wrong? Should I do something to read "data" and manage the actual data posted in the form?
Here is my server code (after #J) pointed out the body-parser issue:
import express from 'express';
import * as sapper from '#sapper/server';
const sirv = require('sirv');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
const session = require('express-session');
const assets = sirv('static', {
maxAge: 31536000, // 1Y
immutable: true
});
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}))
app.use(assets, sapper.middleware()).listen(process.env.PORT, err => { if (err) console.log('error', err); });
If I console.log (r) from my fetch function which has the reponse. I get this in the console: Response {type: "basic", url: "http://localhost:3000/posthandle", redirected: false, status: 200, ok: true, …}
I had to npm install body-parser --save and add it to the server.js. I had to add bodyParser.urlencoded and bodyParser.json to get it to work.
import sirv from 'sirv';
import polka from 'polka';
import compression from 'compression';
import * as sapper from '#sapper/server';
// const express = require('express')
const app = polka()
const bodyParser = require('body-parser')
const { PORT, NODE_ENV } = process.env;
const dev = NODE_ENV === 'development';
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app
.use(
compression({ threshold: 0 }),
sirv('static', { dev }),
sapper.middleware()
)
.listen(PORT, err => {
if (err) console.log('error', err);
});

Req.body is empty when I POST using axios but when I use 'request' it's working fine

A little background -
I have my NodeJS server running on port 3001 and my React application on port 3000. I've set up a proxy in my React application package.json to proxy all requests to port 3001 -
"proxy": "http://localhost:3001"
Now when I'm using Axios in my React application to make POST request on 'users/authentication' route on my NodeJS server, the request body is being parsed as blank on the Node server
const request = {
method: 'POST',
url: `/users/authenticate`,
headers: {
'Content-Type': 'application/json'
},
body: {
email: email,
password: password
}
};
console.log(request);
axios(request).then((res) => {
//handle success
});
}).catch((err) => //handleError ))
But unfortunately, the NodeJS application crashes because it's parsing req.body as blank. The relevant code on Server side -
//in index.js file
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json())
app.use('/users', users);
//in users.js file
const express = require('express');
const router = express.Router();
const userController = require('../controllers/users');
router.post('/authenticate', userController.authenticate);
module.exports = router;
//in UserController
const userModel = require('../models/user');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
module.exports = {
authenticate: function (req, res, next) {
console.log(req);
userModel.findOne({ email: req.body.email }, function (err, userInfo) {
if (err) {
next(err);
} else {
if (bcrypt.compareSync(req.body.password, userInfo.password)) {
const token = jwt.sign({ id: userInfo._id }, req.app.get('secretKey'), { expiresIn: '1h' });
res.json({ status: "success", message: "user found!!!", data: { user: userInfo, token: token } });
} else {
res.json({ status: "error", message: "Invalid email/password!!!", data: null });
}
}
});
},
}
But when I'm logging the request in the 'authenticate' function, the req.body is being parsed as blank which is making the application crash.
Now when I do this exact thing using 'Request' package on React, it's working completely fine. Below code using 'Request' library -
var options = {
method: 'POST',
url: 'http://localhost:3000/users/authenticate',
headers:
{
'Content-Type': 'application/json'
},
form:
{
email: email,
password: password
}
};
console.log(options);
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
Any idea why it's working fine using Request and not on Axios?
The only problem with 'Request' is that I have to mention the complete URL - 'localhost:3000...' instead of just the route like in Axios.
Any other suggestions on how I could implement this better would be great also.
The property for adding data to the request body in Axios is called data not body.

Categories

Resources