Pass data from reactjs to koajs server(405 method not allowed) - reactjs

I'm a beginner at both ReactJS and KoaJS.
I'm trying to send data from my React js form inputs to the server-side which was written with Koa.
Here is what I wrote to post data to the backend.
app.js
const FormContainer = () => {
const url = "http://localhost:3100/"
const [data,setData] = useState({
email:"",
firstname:"",
lastname:""
})
function submit(e){
e.preventDefault();
Axios.post(url, {
email: data.email,
firstname: data.firstname,
lastname: data.lastname
})
.then(res => {
console.log(res.data)
})
}
function handle(e){
const newData = {...data}
newData[e.target.id] = e.target.value
setData(newData)
console.log(newData);
}
Here is the server-side code
server.js
const Koa = require('koa');
const json = require('koa-json');
const KoaRouter = require('koa-router');
const bodyParser = require('koa-bodyparser');
const { default: App } = require('next/app');
const cors = require('#koa/cors');
const port = 3100
const server = new Koa();
const router = new KoaRouter();
server.use(json());
server.use(cors());
router.get('/', ctx => (ctx.body = {
}));
server.use(router.routes());
server.use(router.allowedMethods());
server.listen(port, () => console.log('Server Running'));
When I run the server, I keep getting this console error but I'm not sure what's wrong. Can someone help me? Thank you.
Error Image

Related

State Not Finished Setting before being used in useEffect

I am hosting a react app in aws amplify using the aws-serverless version of express as the REST API, which sits inside of a lambda function. A big problem that I am facing is that asynchronous jobs in aws-serverless express cause the lambda function to complete before the promises resolve. Leaving me with no data and no error handling. This caused me to bring a lot of the asynchronous work to the front end of the application.
The problem here is that I need to bring a large amount of data into state. Right now, I am using a delay workaround (shown below) but instead need a programatic way to make sure state is finished updating before being used in the second useEffect hook (dependent on odds & failedTries props) instead of using the delay functionality.
Any help would be greatly appreciated.
const App = ({ signOut }) => {
const [odds, setOdds] = useState([]);
const [updateTime,setUpdateTime] = useState(0);
const [failedTries,setFailedTries] = useState(0);
useEffect(() => {
const setNflOdds = async () => {
let response = await updateNflOdds();
let data = response;
setOdds(data);
};
setNflOdds();
setUpdateTime(1);
const interval = setInterval(() => {
setNflOdds();
setUpdateTime(updateTime => updateTime +1);
}, 100000);
return () => clearInterval(interval);
}, []);
useEffect(() => {
const s3Push = (() => {
if(!odds.length) {
setFailedTries(failedTries => failedTries + 1);
} else {
const delay = ms => new Promise(res => setTimeout(res, ms));
const nflOddsRefDelay = async() => {
*//This is the current workaround, wait ten seconds before pushing odds state up to the s3 bucket*
await delay(10000);
oddsS3Helper(odds);
};
nflOddsRefDelay()
}
});
s3Push();
}, [odds, failedTries]);
With the above indicated delay workaround this works for my use case (13k records inside of the array) but the data size is highly variable and I want to figure out a way that no matter the data size it brings the entire call up to the s3 bucket.
below is the content of the functions being called in the useEffect hook
const pushToS3 = async ( file, key ) => {
const creds = await Auth.currentCredentials()
const REGION = {region};
const s3Client = new S3Client({
credentials: Auth.essentialCredentials(creds),
region: REGION
});
const params = {
Bucket: {s3 bucket name}
Key: key,
Body: file,
};
s3Client.send(new PutObjectCommand(params));
console.log("file is sent");
};
const oddsS3Helper = (async (odds) => {
console.log("inside s3 helper: ",odds);
let csv = '';
let headers = Object.keys(odds[0]).join(',');
let values = odds.map(odd => Object.values(odd).join(',')).join('\n');
csv += headers + '\n' + values;
const buffedFile = csv;
const key = 'nflprops.csv'
const delay = ms => new Promise(res => setTimeout(res, ms));
const propRefDelay = async() => {
await delay(5000);
await postNflOdds();
};
pushToS3( buffedFile, key );
await propRefDelay();
});
async function getNflGames() {
const apiName = {name of serverless API inside of lambda};
const path = {path name};
const init = {
headers: {} // OPTIONAL
};
const data = await API.get(apiName, path, init);
return data;
};
async function getNflOdds(gameId) {
const apiName = {name of serverless API inside of lambda};
const path = {path name};
const init = {
headers: {}, // OPTIONAL
body: { gameId }
};
const data = await API.post(apiName, path, init);
return data;
};
async function updateNflOdds() {
const ojNflGames = await getNflGames();
const nflGameProps = [];
const nflOddsPush = ( async () => {
try {
await ojNflGames.data.map( async (game) => {
const ojNflOdds = await getNflOdds(game.id)
await ojNflOdds.data[0].odds.map((line) => {
nflGameProps.push(
{
gameId: game.id,
oddsId: line.id,
sports_book_name: line.sports_book_name,
name: line.name,
price: line.price,
checked_date: line.checked_date,
bet_points: line.bet_points,
is_main: line.is_main,
is_live: line.is_live,
market_name: line.market_name,
home_rotation_number: line.home_rotation_number,
away_rotation_number: line.away_rotation_number,
deep_link_url: line.deep_link_url,
player_id: line.player_id,
}
);
});
});
} catch (err) {
console.log("there was an error", err);
}
});
try {
await nflOddsPush();
} catch(err) {
console.log("odds push errored: ", err);
}
console.log("inside of updateNflOdds function: ",nflGameProps);
return nflGameProps;
};

React Axios - Pass Hook as Parameter for Axios Params

I am new to React & Axios, I'm trying to work my head around how to change the GET instance properties based on user inputs... If I am going about it the wrong way please direct me.
I want the selected dataFormat to pass to the params of the Axios.getData()
At the moment I can only get it to pass the object rather than its value.
Thanks in advance
Here is the code to fetch the data:
function App() {
let [responseData, setResponseData] = React.useState([]);
const [dataFormat, setDataFormat] = React.useState("json");
const fetchData = (e) => {
e.preventDefault();
console.log({dataFormat});
api
.getData(dataFormat)
.then((response) => {
console.log("Hello");
console.log(response);
setResponseData(response.data);
})
.catch((error) => {
console.log(error);
});
};
Here is the Axios instance
enter image description here
Here is the error I am receiving:
enter image description here
First you need to install the express library. Then, import cors and also use express.json() for parsing the json as shown below:
const express = require("express");
const app = express();
const cors = require("cors");
app.use(express.json());
app.use(cors());
function App() {
let [responseData, setResponseData] = React.useState([]);
const [dataFormat, setDataFormat] = React.useState("json");
const fetchData = (e) => {
e.preventDefault();
console.log({dataFormat});
api
.getData(dataFormat)
.then((response) => {
console.log("Hello");
console.log(response);
setResponseData(response.data);
})
.catch((error) => {
console.log(error);
});
};

MS Graph API issue with React

I'm working on a React project.
I'm able to sign in in the graph API, also able to get the user's contacts, but, not able to get his calendar events.
the config file:
export const msalConfig = {
auth: {
clientId: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
authority: "https://login.microsoftonline.com/common",
redirectUri: "http://localhost:4200",
},
cache: {
cacheLocation: "sessionStorage", // This configures where your cache will be stored
storeAuthStateInCookie: true, // Set this to "true" if you are having issues on IE11 or Edge
}
};
// Add scopes here for ID token to be used at Microsoft identity platform endpoints.
export const loginRequest = {
scopes: ["Calendars.ReadWrite", "Contacts.Read"]
};
// Add the endpoints here for Microsoft Graph API services you'd like to use.
export const graphConfig = {
graphMeEndpoint: "https://graph.microsoft.com/v1.0/me",
graphCalendarsEndpoint: "https://graph.microsoft.com/v1.0/me/events",
graphContactsEndpoint: "https://graph.microsoft.com/v1.0/me/contacts",
};
1/ The working part
the importContact.jsx file:
...
import { loginRequest, graphConfig } from '../authConfig.jsx';
import { useMsal } from "#azure/msal-react";
const ImportContacts = (props) => {
const { instance, accounts, inProgress } = useMsal();
const [accessToken, setAccessToken] = useState(null);
const [graphData, setGraphData] = useState(null);
const getMicrosoftContacts = () => {
const request = {
...loginRequest,
account: accounts[0]
};
var contacts= [];
// Silently acquires an access token which is then attached to a request for Microsoft Graph data
instance.acquireTokenSilent(request).then((response) => {
console.log('acquireTokenSilent')
setAccessToken(response.accessToken);
callMsGraph(response.accessToken).then(
response => {
setGraphData(response);
console.log(response)
for (const item of response.value){
contacts.push({
provider: 'Microsoft',
id: item.id,
email: item.emailAddresses[0].address,
firstName: item.givenName,
lastName: item.surname,
name: item.displayName,
label:item.displayName + " (" + item.emailAddresses[0].address + ")" }
)
}
setItems(contacts);
}
);
}).catch((e) => {
instance.acquireTokenPopup(request).then((response) => {
setAccessToken(response.accessToken);
callMsGraph(response.accessToken).then(
response => {
setGraphData(response);
for (const item of response.value){
contacts.push({
provider: 'Microsoft',
id: item.id,
email: item.emailAddresses[0].address,
firstName: item.givenName,
lastName: item.surname,
name: item.displayName,
label:item.displayName }
)
}
setItems(contacts);
}
);
});
});
}
async function callMsGraph(accessToken) {
const headers = new Headers();
const bearer = `Bearer ${accessToken}`;
headers.append("Authorization", bearer);
const options = {
method: "GET",
headers: headers
};
return fetch(graphConfig.graphContactsEndpoint, options)
.then(response => response.json())
.catch(error => console.log(error));
}
...
}
2/ The non working part in events.jsx file:
...
import { loginRequest, graphConfig } from '../authConfig.jsx';
import { useMsal } from "#azure/msal-react";
class Events extends Component {
constructor(props) {
super(props);
this.getMicrosoftEvents = this.getMicrosoftEvents.bind(this);
}
componentDidMount(){
var date = new Date();
var firstDay = new Date(date.getFullYear(), date.getMonth(), 1);
var lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);
this.getMicrosoftEvents(firstDay, lastDay);
}
getMicrosoftEvents(start, end) {
console.log('log displayed in console')
const { instance, accounts, inProgress } = useMsal();
const [accessToken, setAccessToken] = useState(null);
const [graphData, setGraphData] = useState(null);
console.log('log not displayed in console')
const request = {
...loginRequest,
account: accounts[0]
};
// Silently acquires an access token which is then attached to a request for Microsoft Graph data
instance.acquireTokenSilent(request).then((response) => {
console.log('acquireTokenSilent')
setAccessToken(response.accessToken);
callMsGraph(response.accessToken, start, end).then(
response => {
console.log('microsoft response ' + response)
}
);
}).catch((e) => {
console.log('microsoft response error ' + e)
instance.acquireTokenPopup(request).then((response) => {
setAccessToken(response.accessToken);
callMsGraph(response.accessToken, start, end).then(
response => {
console.log('microsoft response ' + response)
}
);
});
});
async function callMsGraph(accessToken, start, end) {
console.log('callMsGraph ')
const headers = new Headers();
const bearer = `Bearer ${accessToken}`;
headers.append("Authorization", bearer);
console.log('Authorization ' + bearer)
const options = {
method: "GET",
headers: headers
};
return fetch(graphConfig.graphCalendarsEndpoint
+ '?startDateTime='
+ start
+ '&endDateTime='
+ end,
options)
.then(response => {
console.log('microsoft response ' + response.json())
response.json();
})
.catch(error => console.log(error));
}
}
I'm not getting any error, the api call is not made, the difference between the two calls is one is made after a button click, and the other on load.
Adding logs showed me that the problem could be in this line as the logs are not displayed after it:
const { instance, accounts, inProgress } = useMsal();
What am I doing wrong?
In events.jsx Events component is a class component and you are calling useMsal() and useState() hooks in getMicrosoftEvents. That will not work because hooks can only be called in function components.
You need to make Events component functional like ImportContacts.
Instead of
class Events extends Component {
...
Do this
const Events= (props) => {
const { instance, accounts, inProgress } = useMsal();
const [accessToken, setAccessToken] = useState(null);
const [graphData, setGraphData] = useState(null);
...

Upload more images from react-native app to firebase

I'm trying to upload multiple images from react-native to firebase. The way I go about this is by using expo image picker multiple - by monstrodev ( see snack.io here )
I've managed to get it to work, and managed to be able to choose multiple photos from the 'improvised' camera roll. They load fine in the add screen, but I cannot find a solution on how to upload them properly.
export default function Add(props) {
const [name, setName] = useState("");
const [photos, setPhotos] = useState(null);
const uploadImage = async () => {
const uri = photos[0].uri; // -> uri is like this because 'media' is an array with objects inside that contain name, type, and uri each, and I only need uri of each oject.
const childPath = `data/${firebase.auth().currentUser.uid}/${Math.random().toString(36)}`;
console.log(childPath);
const response = await fetch(uri);
const blob = await response.blob();
const upload = firebase
.storage()
.ref()
.child(childPath)
.put(blob);
const uploadProgress = snapshot => {
console.log(`transferred: ${snapshot.bytesTransferred}`)
};
const uploadComplete = () => {
upload.snapshot.ref.getDownloadURL().then((snapshot) =>{
addPost(snapshot);
console.log(snapshot);
})
};
const uploadError = snapshot => {
console.log(snapshot);
};
upload.on("state_changed", uploadProgress, uploadError, uploadComplete );
};
const addPost = (downloadURL) => {
firebase.firestore()
.collection("allPosts")
.collection(firebase.auth().currentUser.uid)
.collection('userPosts')
.add({
downloadURL,
name,
}).then((function () {
props.navigation.popToTop()
}))
}
useEffect(() => {
const {params} = props.route;
if(params) {
const {photos} = params;
if(photos) setPhotos(photos)
delete params.photos
}
}, [{photos}]) // This useEffect updates when coming back from the ImageBrowserScreen (can be found in snack.io, it's exactly the same)
The main problem is, let's say, I choose 3 photos. If I console.log(photos) I get this:
Array [
Object {
"name": "name1.JPG",
"type": "image/jpg",
"uri": "file:///name1.jpg",
},
Object {
"name": "name2.JPG",
"type": "image/jpg",
"uri": "file:///name2.jpg",
},
Object {
"name": "name3.JPG",
"type": "image/jpg",
"uri": "file:///name3.jpg",
},
]
The only I could get it to work was this, give exact path to uri (photos[0].uri for example) otherwise get network error. But this only uploads the first object/photo. I also tried to map through the photos state and return all uri's into a single array and use that as const uri, but that obviously didn't work, for uri needs only one string. So I somehow need to run that function for each uri to be able to get a downloadURL and store each of them.
EDIT:
const uploadImage = async (photo) => {
const uri = photo.uri;
const childPath = `data/${
firebase.auth().currentUser.uid
}/${Math.random().toString(36)}`;
console.log(childPath);
const response = await fetch(uri);
const blob = await response.blob();
const snapshot = await firebase.storage().ref().child(childPath).put(blob);
const downloadURL = await snapshot.ref.getDownloadURL();
imgs.push(downloadURL)
};
const uploadPhotos = async () => {
await Promise.all(photos.map(p=>uploadImage(photo)).then(addPost())
};
Can you try it with a loop trough all photos and upload them separately. Idealy using a Promise.all to upload them in parallel:
const addPost = async (downloadURLs) => {
await firebase.firestore()
.collection("allPosts")
.collection(firebase.auth().currentUser.uid)
.collection('userPosts')
.add({
downloadURLs,
name,
})
props.navigation.popToTop()
}
const uploadImage = async (photo) => {
const uri = photo.uri;
const childPath = `data/${
firebase.auth().currentUser.uid
}/${Math.random().toString(36)}`;
console.log(childPath);
const response = await fetch(uri);
const blob = await response.blob();
const snapshot = await firebase.storage().ref().child(childPath).put(blob);
const downloadURL = await snapshot.ref.getDownloadURL();
return downloadURL
};
const uploadPhotos = async () => {
const downloadURLs=await Promise.all(photos.map(p=>uploadImage(photo))
await addPost(downloadURLs);
};

How to pass value to Koa2

I have an react app that I want to pass value down to a koa server.
let data = new FormData()
data.append('json', JSON.stringify(token))
fetch('/charge', { method: 'POST', body: data })
.then((res) => {
return res.json()
})
.then((json) => {
console.log('something wrong')
console.log(json)
})
and below is my server code
const config = require('../config')
const server = require('../server/main')
const router = require('koa-router')()
const parse = require("co-body")
const port = config.server_port
server.use(router.routes())
router
.post('/charge', function (ctx, next) {
console.log(ctx.request.body)
console.log('howyd')
ctx.body = "howdy"
})
Just can't get the value passing down from client. Do you guys know what is going on?
Make sure you're using the body parser. It looks like you're requiring it in, but not actually using it. Something like this (untested):
const config = require('../config')
const server = require('../server/main')
const router = require('koa-router')()
const parse = require("co-body")
const port = config.server_port
server.use(router.routes())
router
.post('/charge', async (ctx, next) => {
let body = await parser.json(ctx.request)
console.log(body)
console.log('howyd')
ctx.body = "howdy"
})

Resources