how to fetch local api in react.js - javascript

I'm a new one, I'm trying to fetch my own api on local,this what I do:
in "src/server.js"
const express = require("express");
const app = express();
app.get("/api", (request, response) => {
response.sendFile("api.js", { root: __dirname });
});
app.listen(8000);
then I use creat-react-app to create a react project, how can I call my api in App.js?
if my situation is not complete, please tell me.
Q1:with server.js, after I run "node server.js", I can can call this file in browser that means I have done an api, right?
Q2:how can I get value from my api.js in App.js without cors problem?

Firstly you should add your request address into package.json file. For example if you want to send http request to https://localhost:5000/, you should add "proxy":"http://localhost:5000" line into your package.json file.
After adding this line, you can send http request without getting CORS error.
Also you can use fetch function to sending request and getting response from server side in your react code(App.js).
fetch('/api')
.then((response) => response.json())
.then((data) => console.log(data));

Related

I'm making a Choropleth Map of the United States and its counties. The first map I used which was the world map worked fine. The new map doesn't work [duplicate]

I'm trying to make a request in a local file, but I don't know when I try to do on my computer show me an error. Is possible make a fetch to a file inside your project?
// Option 1
componentDidMount() {
fetch('./movies.json')
.then(res => res.json())
.then((data) => {
console.log(data)
});
}
error: Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0 at App.js: 10 --> .then(res => res.json())
// Option 2
componentDidMount() {
fetch('./movies.json', {
headers : {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
})
.then( res => res.json())
.then((data) => {
console.log(data);
});
}
error1: GET http://localhost:3000/movies.json 404 (Not Found) at App.js:15 --> fetch('./movies.json', {
error2: Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0 at App.js: 10 --> .then(res => res.json())
// This works
componentDidMount() {
fetch('https://facebook.github.io/react-native/movies.json')
.then( res => res.json() )
.then( (data) => {
console.log(data)
})
}
Try to place your json file in the public folder like so :
public/movies.json
and then fetch using
fetch('./movies.json')
or
fetch('movies.json')
I have experienced the same problem previously. When I place the json file in the public folder, problem is solved.
When using fetch, React normally reads asset/resources files in the public folder.
You are trying to serve a static file with a fetch command, which inherently requires the file to be served by a server. To resolve the issue, you have a few options available to you. I am going to outline the two that are most commonly suggested for such a thing:
Use Node.js and something like expressjs to host your own server that serves the file you want to fetch. While this procedure might require more effort and time, it is certainly more customizable and a good way to learn and understand how fetching from a backend works.
Use something like Chrome Web Server to easily set up a very simple server to serve your file on your local network. Using this method, you have very little control over what you can do with said web server, but you can quickly and easily prototype your web application. However, I doubt there's a way to move this method to production.
Finally, there are other options where you can upload one or more files online and fetch them from an external URL, however this might not be the optimal strategy.
Your JSON file needs to be served by the server so you need the express server (or any other). In this example we are using express.
Note: you can also download git repo
App.js File
import React, { Component } from 'react';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: null
};
}
componentDidMount() {
const myHeaders = new Headers({
"Content-Type": "application/json",
Accept: "application/json"
});
fetch("http://localhost:5000/movie", {
headers: myHeaders,
})
.then(response => {
console.log(response);
return response.json();
})
.then(data => {
console.log(data);
this.setState({ data });
});
}
render() {
return <div className="App">{JSON.stringify(this.state.data)}</div>;
}
}
export default App;
server.js
var express = require("express");
var data = require('./movie.json'); // your json file path
var app = express();
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.get("/movie", function(req, res, next) {
res.send(data);
});
app.listen(5000, () => console.log('Example app listening on port 5000!'))
I was encountering the same error and there are two changes I made in my code to get rid of the error. Firstly, you don't need an express server to serve your files you can read data from a local json file inside your public folder in your create-react-app directory.
const getData=()=>{
fetch('data.json',{
headers : {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}
)
.then(function(response){
console.log(response)
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
}
useEffect(()=>{
getData()
},[])
First, as suggested in some of the answers above ensure that your json file is inside the public folder and the path parameter inside the fetch function is correct as above. Relative paths didn't work for me.
Second, set the headers as shown. Removing the headers part from my fetch call was still giving me this error.
a simple solution to this is to use live server extension (if you use vs code)
Say that i have the following file test.html
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
<script>
var depdata;
depdata = fetch("test1.geojson")
.then((data) => {
return data;
});
depdata.then(function(data) {console.log(data)})
</script>
</body>
</html>
When access the file in the firefox through file://... I get the following error:
Cross-Origin Request Blocked:....
When I followed the error on firefox I got the following explanation
CORS requests may only use the HTTPS URL scheme, but the URL specified by the request is of a different type. This often occurs if the URL specifies a local file, using a file:/// URL.
To fix this problem, simply make sure you use HTTPS URLs when issuing requests involving CORS, such as XMLHttpRequest, Fetch APIs, Web Fonts (#font-face), and WebGL textures, and XSL stylesheets.
So the as far as I understand we just need to access the test.html through HTTP. The most straight forward way around this problem was the python simple http server. In the terminal.
> cd directory of the project.
> python3 -m http.server 8000 --bind 127.0.0.1
Then in the browser:
http://localhost:8000/test.html
My go-to approach is to use express-generator to set up a quick local server, then run ngrok (free tier is fine) and point your app to the url it creates. This has the advantage of letting you easily test your fetching in the iOS simulator or Android emulator, as well as on a device not tethered to your computer. Plus, you can also send the url to people testing your app. Of course, there would need to be a way for them to manually input that url so the app could set it as the fetch endpoint.
I got it working rather very simple way - no express / webserver really needed. Just do :
import data from '../assets/data.json';
and use the json data like this (say if it is a JsonArray) :
data.map(movie ...
Do this in App.js or some other class extending React.Component,
The error
Unexpected token < in JSON at position 0
comes from the HTML file that is returned if the request is unsuccessful. The first element (at position 0) of an HTML file is typically a '<'. Instead of a JSON, an attempt is made to read in an HTML file.
You can find the returned HTML File in the Inspect Tool -> Network -> Erroneous file marked in red -> Reponse. There you can see what the specific error is. Example Error Message
To fix the error for me, it helped to move the file to be imported to the Public folder of my React project and then import it like this from a file in the 'src' folder: fetch('dataTemplate.json')
You can place your json file in the public folder. In your React component you can use userEffect (). You don't need Express.js for this case.
React.useEffect(() => {
fetch("./views/util/cities.json")
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
});
To fetch local files, a good alternative:
npm install file-fetch
to read a file:
const fileFetch = require('file-fetch')
fileFetch('./public/user.json').then((res) => {
res.body.pipe(process.stdout)
})
See doc

How should I use proxy in a web app made with node.js and vanilla javascript?

I have a web app made in node.js and vanilla javascript. I wanna replace "http://localhost:4000/api/word" with "api/word" in the fetch api so that it works when the app's deployed on Heroku. I solved the issue by adding "proxy" : "http://localhost:4000" in package.json file when I used React for other apps but I don't know how to deal with the issue when I'm not using React.
server.js
const express = require("express");
const app = express();
const cors = require("cors");
const fs = require("fs");
const port = process.env.PORT || 4000;
app.use(express.json());
app.use(cors());
app.get("http://localhost:4000/api/word", function (req, res) {
fs.readFile("./wordlist.txt", (err, data) => {
if (err) throw err;
let wordList = data.toString().split("\n");
res.send(wordList);
});
});
main.js
function getWord() {
fetch("/api/word")
.then((res) => res.json())
.then((res) => {
...do something...
})
.catch((err) => console.log(err));
}
I tried the React way but it sends the get request to localhost:5500 which is the client side port.
Since your client and server are listening on different ports, I'm assuming your server isn't serving the client and that it has its own server. If the client doesn't need its own separate server, you can serve it from your express app by putting it in a directory and using express.static. Assuming you put the frontend code in a directory called public next to your server code, that would look like this:
app.use(express.json());
app.use(cors());
app.use(express.static(path.resolve(__dirname, 'public')));
If you do need to have a separate server for the client, there are modules just for this problem. http-proxy is a very popular one. I provided examples of how to use it here that could be easily adapted for any Node server, but there are many more in the docs.
Also just a sidenote, app.get("http://localhost:4000/api/word", function (req, res) should be app.get('/api/word' ...: your routes shouldn't define the scheme, host, and port.

How to route nodejs requests to another nodejs application?

Hi I am trying to build a really simple "API-gateway" to demonstrate a small scale microservice project. I am using Nodejs and Express and I wanted to write a really simple public facing api-gateway server to route requests to my different microservices. For example lets say I have microservice A B and C. I wanted requests to localhost:3000/api/A to go to microservice A and return the result and then all other requests to localhost:3000/api/B go to microservice B and return the result ect. I wanted to write this instead of using NGINX, could someone help me understand how I can achieve this? (Most of my other "microservices" are also nodejs/express apis)
Could I get a quick simple example in code? I would love to see a GET request to google and then the client be able to get the GET request. (use of other libraries or modules would be cool too! :D)
You can run B on port 3001, C on 3002.
Then dispach all request by A on port 3000.
You can use Http client like axios in A to request B or C.
Example
A.js
const express = require('express')
const axios = require('axios')
const app = express()
app.get('/api/B', (req, res) => {
axios.get('http://localhost:3001/dosomething', {
params: {...req.query, name: 'Device A'}, //Fetch datas from params
}).then(result => {
res.send(result)
})
})
app.get('/api/C', (_, res) => {
axios.get('http://localhost:3002/dosomething').then(result => {
res.send(result)
})
})
app.listen(3000, () => console.log('On 3000'))
B.js
const express = require('express')
const app = express()
app.get('/dosomething', (req, res) => {
const data = req.query
//Do something with data fetched here you know...
res.send('No worry, I will do something for ' + data.name)
})
app.listen(3001, () => console.log('On 3001'))
If all micro-services are deployed on the same machine(different machines just need a bit more syncing to know ports/ips but that should not be an issue), you just use a common file to store ops/ports and then just redirect calls from route ip:3000/api/A to ipA:portA

Node only sends html content to the client instead of sending a whole Vue app

I created a new vue project with the CLI and want to deploy it. Based on this documentation
https://router.vuejs.org/guide/essentials/history-mode.html#html5-history-mode
I added the history mode to the router. After running npm run build I took the example code for a static native Node server
https://router.vuejs.org/guide/essentials/history-mode.html#example-server-configurations
const http = require('http')
const fs = require('fs')
const httpPort = 3000
http.createServer((req, res) => {
fs.readFile('../base/index.html', 'utf-8', (err, content) => {
if (err) {
throw err;
}
res.writeHead(200, {
'Content-Type': 'text/html; charset=utf-8'
})
res.end(content)
})
}).listen(httpPort, () => {
console.log('Server listening on: http://localhost:%s', httpPort)
})
So when navigating to localhost:3000 the vue project seems to load correctly
but I have a blank page with two errors
When I click on those js files it shows me the content of the index.html file. Obviously js is not able to understand this html content. How can I fix that problem?
Server will not send the whole vue app at once.
Browser get html file from server, when you browse to that url.
Browser parse the html file.
Browser detects assets (js, images, css).
Browser request those files.
It request those file from server, but you haven't initialized server to find those files.
So, need to add static files.
https://expressjs.com/en/starter/static-files.html
You can take reference from here
as #Sukul answer before, you just need to server the static files because you have now only one handler to server all the request coming with the HTML file (the mount point document) and when its requesting the *.js app it's expecting the valid javascript syntax instead it finds HTML, and that what the error messages are on the network tab
const http = require('http')
const fs = require('fs')
const nStatic = require('node-static');
var fileServer = new nStatic.Server('./public');
const httpPort = 3000
const controllers = (req,res)=>{
if(req.url.includes(".")
return fileServer.serve(req, res);
else
fs.readFile('../base/index.html', 'utf-8', (err, content) => {
if (err) {
throw err;
}
res.writeHead(200, {
'Content-Type': 'text/html; charset=utf-8'
})
res.end(content)
})
}
}
http.createServer(controllers).listen(httpPort, () => {
console.log('Server listening on: http://localhost:%s', httpPort)
})
node-static ref
however, I highly recommend you trying to use express.js

How to utilize Request to integration test async Koa Node API

I'm working on my first real-world Node project using Koa2 and Request for making RESTful API calls to a 3rd party. The Koa service itself is relatively simple, but I'm trying to write an integration test for it using Jest. I've found examples of using Jest with Supertest/Superagent, but I cant find how I'd write the equivalent test using ONLY Jest and Request as the http client. Below is the Jest/Supertest example...
const request = require('supertest');
const app = require('../../src/app')
describe('Test the root path', () => {
test('It should response the GET method', async () => {
const response = await request(app).get('/');
expect(response.statusCode).toBe(200);
});
})
It seems like I should be able to just use Request to do the same thing that supertest/superagent is doing here, but I cant find any example. Thanks for suggestions!
Supertest looks magical because you can pass it your app and somehow that just works.
Under the hood, Supertest justs starts listening and configures the underlying request to use the address as a base url.
I'm using Axios here as an example, I don't use Request but it should be easy enough to adjust.
const axios = require('axios')
const app = require('../../src/app')
const server = app.listen() // random port
const url = `http://127.0.0.1:${server.address().port}`
const request = axios.create({ baseURL: url })
describe('Test the root path', () => {
test('It should response the GET method', async () => {
const response = await request.get('/')
expect(response.statusCode).toBe(200)
});
})

Categories