is it possible to provide restful service from react? - javascript

i'm working on a web project that should provide restful post service with react framework.
there are a lot of consuming rest service example on internet.
however, i want to provide restful service.
I tried the following,
1- provide service from react framework. i see it is not possible.
2- provide service from express and binding it with react via proxy
https://www.youtube.com/watch?v=v0t42xBIYIs
for this example, get method works but post method does not.
my express server like below.
const express = require('express');
const app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.post('/api/customers', (req, res) => {
res.json(req.body);
});
const port = 5000;
app.listen(port, () => `Server running on port ${port}`);
after that, , use proxy and react code like this
componentDidMount()
{
fetch('/api/customers')
.then(res => res.json())
.then(customers => this.setState({customers}, () => console.log('Customers fetched...', customers)));
at that point i get the below error
customers.js:18 GET http://localhost:3000/api/vehicles 500 (Internal Server Error)
thank you for all advice.
i'm searching for best practice.

The result of a React application build are script bundles and html files (also can include source maps for debugging) commonly referred to as build artifacts.
The best practice is simple:
When Express is involved the React app should download the build artifacts and API responses from Express (commonly called backend in this scenario).
What happens when this is not followed:
1. React frontend server (typically webpack-dev-server) is used in production. This is not a good idea, webpack-dev-serveris meant to be used in development only.
2. Browser detects that JS code from the bundles downloaded from one server (frontend) attempts to call another server (backend) and triggers a security violation which is meant to improve security. People then use CORS HTTP headers (sent by backend) to make the backend tell browsers: "Don't worry about security and don't trigger security violations, I (the backend) has been hardened to such an extent that I don't care that some code downloaded not from me tries to access me". The browser complies and this results in security needlessly watered down.
When to proxy:
In development only. The webpack-dev-server is excellent for development with its support for Live Reloading, HMR etc. To keep those advantages the backend (Express) can and should serve as a reverse proxy for the frontend. E.g. when Express receives a request for a build artifact, it should download it from the frontend first and then use it to send the response back. This ensures CORS issues do not arise.

Two issues stand out
Post vs Get
You're serving your api from a post endpoint. Change it to get.
app.get('/api/customers', (req, res) => {res.json(vehicleList);});
fetch
In the UI, it shows you are fetching from localhost:3000 when you should be fetching from localhost:5000. I assume your proxy is rerouting 3000 -> 5000 so hopefully this isn't an issue. I would however doublecheck and try hitting the localhost:3000/api/customers url (copy and paste that into the url bar) and see if you see your json.
Also
It is certainly possible to have express serve the static react bundle from a the same base url as your api.
e.g.
app.use('/', express.static('public'));
app.post('/api/customers', (req, res) => {
res.json(vehicleList);
});

Actually, I think you didn't focus that both are running on two different ports
like your server is running on Port:5000 and react project port:3000 so just add
"proxy":http://localhost:5000
//server.js (node file)***
app.get('/api/customers', (req, res) => {
const customers = [
{id: 1, Name: 'Rohan', email: 'r#gmail.com'},
{id: 2, Name: 'Rohan', email: 'r#gmail.com'}
];
res.json(customers);
});
const port = 5000;
app.listen(port, () => `Server running on port ${port}`)
// React Script***
class Customers extends Component {
constructor() {
super();
this.state = {
customers: []
};
}
componentDidMount() {
fetch('/api/customers')
.then(res => res.json())
.then(customers => this.setState({customers}, () => console.log('Customers fetched...', customers)));
}

i think there is no method for pushing data from server to client in a convensional way.
there is a good subject to push data from server to client. you may want to see that.
WebSocket vs ServerSentEvents

Related

How to keep socket.io client in frontend code

I am just learning webdev and want to try to make a multiplayer game using Express and socket.io
I can make a server with socket.io in it which listens. That part works fine.
However when I try to connect a client, this only works if I let the HTML file with the following in it be served by the server like follows:
Server code:
const express = require('express')
const app = express()
const http = require('http')
const server = http.createServer(app)
const { Server } = require('socket.io')
const io = new Server(server)
const port = 3000
io.on('connection', (sock) => {
console.log('client connected')
})
// This seems to be necessary, but I don't want it to be!!!
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html')
})
server.listen(port, () => {
console.log(`Server listening on port ${port}`)
})
This index.html has the following at the bottom:
<script src="/socket.io/socket.io.js"></script>
<script>const socket = io()</script>
However I want to keep all my frontend code seperate from the server. I made a seperate repository for the frontend and backend. I want the frontend to contain all the UI logic and use only data calls (AJAX) to get Json data from the server. So I want to put this index.html file in my frontend code only.
Yet if I do this the connection doesn't work.
I can start the server fine.
I open index.html from WebStorm which also creates a server for this which I configured to also listen to port 3000
Yet it cannot find /socket.io/socket.io.js and I get the following error in the console.
It also doesn't work if WebStorm runs on a different port.
The resource from “http://localhost:3000/socket.io/socket.io.js” was blocked due to MIME type (“text/html”) mismatch (X-Content-Type-Options: nosniff).
How can I keep this html in my client repo only and still work with socket.io, or is this not possible?
You can't have multiple servers listening on the same port. Run the servers on different ports and either:
Have a reverse proxy forwarding requests to your Socket.io server (which needs special handling) and your front end server or
Put an absolute URL in the script src and configure CORS.

Is there anyway that I can get the running port?

I`d like to show in my React application the running port of the local server, is there any way to get it programmatically? The running port may defer if something is already running on the default port of create-react-app.
create-react-app is a React toolchain, which packages some useful tools together to let you dive into development without any initial setup. Local development server is a part of that toolchain, it's only purpose is to serve static files your react app needs.
Sure, create-react-app lets you configure some options with environment variables but it is not meant to serve as backend for your react application.
You can achieve this with your own backend by writing an endpoint to get the server port but for the local server I don't think it is possible.
This functionality is not available since React App and Local server are running independently.
However, your server port will be available when you start the server. So you can have another API that will simply fetch the port of the server and that can be displayed accordingly.
Something like this on the server.
app.get('/server/port', (req, res) => {
return res.json({port: server.address().port})
})
where your server is started at
const server = app.listen(20000)
In the react app, you can have the fetch request like this
fetch('http://localhost:20000/server/port')
.then(response => response.json())
.then(data => console.log(data));
// you will have the port no. in data.port
This will be helpful to you.

Express server routes not being hit. Browser Error 'No Data Received ERR_EMPTY_RESPONSE'

I'm having an issue with my express server with an email service I was attempting to set up. After troubleshooting I decided to boil it down and attempt see if the issue would replicate with a simple 'hello world' example, which it did. No routes will be work correctly each request, whether done by a js frontend, postman, or just in a chrome browser will work. Each request will just 'spin' until it returns a 'No Data Received ERR_EMPTY_RESPONSE' error.
I've tried reinstalling the express dependency, reinstalling node itself, different browsers. The code is attached, any help would be appreciated.
const express = require('express');
const cors = require('cors');
const app = express();
let port = 3000;
app.use(cors);
app.get('/testroute', (req, res) => {
console.log('route hit');
res.send('test success');
});
app.listen(port, () => {
console.log('server started on port: ' + port);
});
Change this:
app.use(cors);
to this:
app.use(cors());
Your server was hanging because you were passing cors as middleware. But, cors by itself is not middleware. When Express called it, it never sent a response or called next() to continue routing, so therefore the client was just left hanging forever waiting for a response. Instead, the cors library is designed to that you call it as in cors() to get back a middleware function that you then pass to Express.
This is fully documented in the cors library documentation.

Heroku custom DNS API route issue in Node.js

I have a custom domain set up in Heroku which works fine.
I can access my site using both my app name and custom domain.
I can access a route using my standard Heroku URL, but not using the custom domain.
For example:
Works:
https://{myappname}.herokuapp.com
https://{myappname}.herokuapp.com/callback
https://{customdomain}.com
Does not work:
https://{customdomain}.com/callback
Server config:
const express = require("express");
const path = require("path");;
const callback = require("./callback");
const app = express();
// Body parser middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Serve static assets if in production
if (process.env.NODE_ENV === "production") {
app.use("/callback", callback);
// Set static folder
app.use(express.static("client/build"));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, "client", "build", "index.html"));
});
}
// Init server/port
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Server running on port ${port}`));
I know its too late but I am writing for those who face this issue in the future.
I was also facing this issue and solved through this.
Was Not Working
https://{customdomain}.com/callback
This Worked for me.
https://www.{customdomain}.com/callback
I figured this out, it was pretty simple and I feel stupid, however I will answer this here in case anyone ever has the same issue.
Problem:
I had a React route/component called Callback. This React component was calling a Node.js route also called Callback, which processes information then redirects to a new React route/component.
Simple fix was to change my React route/component to callbackPage, leaving my Node.js route as Callback.
So in summary, I had a webpage URL with the same name as a server API route. when I visited this page, instead of the page being rendered, the API route was run and basically did nothing and timed out. I'm still confused as to why it worked with my app URL but not my custom domain.

Using a node.js app with HTML

My goal is this: JS but server-side. My solution, the obvious, node.js. I've used node.js quiet a bit. Mainly for an application, not a web server. The only reason I need to do server-side JS is that I need to use a library that connects to the Discord API. So I have a little test .js file with my node.js in it. It just prints text if it works. Basic. What I need it to do is whenever someone goes to https://example.com/something, it runs the node.js script and if the script ends up with printing "hello", then https://example.com/something will say "hello".
I've done some research on this, I've found ways to deploy a node.js app, which I know how to do. I can't really find anything that I'm looking for though.
You can use express to run a webserver on nodejs
Install express by running "npm install express" in your project folder through command prompt
Create a app.js file with the following code
var express = require('express'); // load the express library
var app = express(); // create an instance of express
var child_process = require('child_process'); //load the child_process module
app.get("/something", function(req, res) { // Setup a router which listens to the site http://localhost/something
child_process.fork("./yourCodeFile.js"); // Launch your code file
});
app.listen(80);
Run node app.js to listen to web connections
Then you put your code into the yourCodeFile.js which has to be be in the same folder as the app.js file, even better you could just write all your code in the app.js code as long as you keep it inside the function inside app.get
You should take a look at cloud-based lambda functions and platforms like AWS Lambda, which run a script in response to an HTTP request. They are relatively new and the architecture used to support this is being called "serverless", which is a simple term, albeit a bit of a misnomer. There are various tools out there to help you build these systems, such as the similarly named Serverless framework, though you can typically still use more traditional server frameworks that you are probably more comfortable with. Either way, you are not responsible for managing any server, including starting it or stopping it.
In terms of constructing a response that you are happy with, you can of course respond with any arbitrary string you want. See the AWS example of a Node.js handler.
exports.myHandler = function(event, context, callback) {
callback(null, "Hello, world!");
}
Lambda functions can also return binary data and work well with static storage systems like Amazon S3. For example, the function can be run in response to the creation of static assets.
Your code should look like this:
const http = require('http');
const url = require('url');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
const pathName =url.parse(req.url).pathname;
if (pathName == '/something') {
res.end('Hello World\n');
} else {
res.end('Please visit /something \n');
}
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
You should run your file with node youfile.js And when you do curl http://127.0.0.1:3000 you will see
Please visit /something
But when you do curl http://127.0.0.1:3000/something you will see
Hello World

Categories

Resources