React: Hide API keys - reactjs

Currently, my team and I have a website up and running.
Our current method of storing API keys is placing them in a .env file. However, this method still allows the API keys to be accessed through this method of inspecting a web page.
API key is visible
Any suggestions or fixes that could prevent this key from being visible to the public?

You cannot hide your keys anywhere in the browser, frontend, or client-side. They should always be on your server.
What you need is a server env with an API, here's how you will do it:
Any request made from your client/browser will be sent to your server.
Your server will then extract the original request URL add the keys
(that were previously stored on your browser) and forwards the
request to the original URL.
And lastly, your server will forward the response received from the
request to your browser.

If the data being fetched is static (not reliant on user input) it can be fetched during build time using the Next.js getStaticProps method and thus avoid being detected in the frontend altogether.
Users will never be able to see the actual endpoints which were originally called during build time to be stored for later retrieval in a lib/ directory.
Next is React-based, so it's relatively "easy" to migrate to from React.
As getStaticProps runs only on the server-side, it will never run on
the client-side. It won’t even be included in the JS bundle for the
browser, so you can write direct database queries without them being
sent to browsers.
This means that instead of fetching an API route from getStaticProps
(that itself fetches data from an external source), you can write the
server-side code directly in getStaticProps.
Take the following example. An API route is used to fetch some data
from a CMS. That API route is then called directly from
getStaticProps. This produces an additional call, reducing
performance. Instead, the logic for fetching the data from the CMS can
be shared by using a lib/ directory. Then it can be shared with
getStaticProps.
https://nextjs.org/docs/basic-features/data-fetching/get-static-props

Related

SSR vs CSR explanation

I've been working as a full stack web developer for over a year now. Nextjs/golang is our stack. Today I realized that I have no idea whether we use CSR or SSR. I think we use CSR but I'm not sure. I've gone down rabbitholes on this topic like 100 times but its never stuck.
First question:
When they say server side, do they mean on the backend? i.e. golang? or does that mean on the nextjs server? Whenever someone says server I think backend but I don't think this is correct.
Second question:
How does client side rendering work? Like I know the server sends javascript to the client then the client uses the javascript to build the page. But all of this javascript must make a bunch of requests to the server to grab data and html right? Like how would the javascript build the page otherwise? Is this why react/nextjs is written in jsx? So the server can send all the JSX which is actually just javascript to the client then the client can build the html?
Third Question:
If CSR has the client build the page, how would this ever work? Like what about all of the data that needs to be pulled from our database for specific users / etc etc. That can't be done directly from the frontend.
I tried reading tons of articles online! Hasn't clicked yet
You said the essential thing yourself: in client-side rendering, "the server sends javascript to the client, then the client uses the javascript to build the page." Hold on to that one point – everything else is secondary. The client "renders."
Now that "client-side" rendering capabilities have become so powerful – and, so varied – it has generally become favored. If you "tell the client what to do and then let him do it," you are more likely to get a consistently favorable outcome for most clients. Yes, the client will issue perhaps-many AJAX requests in carrying out your instructions. That is irrelevant.
CSR - server sends HTML that contains links to javascript (script tags). Clients then loads and executes JS (JavaScript typically contains fetching code). That means that each client will perform several round trips to the server to get HTML and then the data.
SSR - server sends HTML and embeds the necessary data in it
The client already has the data and HTML, so it can render it. SSR does fetch on each request, meaning the client still gets the latest data.
Benefits of using SSR compared to CSR is lower load time, it makes the website feel "faster" and also improves the ranking by search engine bots. On the other hand, the server does the rendering, which increases its burden (though fewer requests decreases it).
SSG is the same as SSR but fetching occurs at build time, the result page is computed only once and returned for each request. It is possible to use SSG with or without data.
Use SSG if possible, then mostly SSR. In some occasions it may be better to use CSR instead of SSR, though I'm not experienced enough to give the answer when.
Now answering your questions:
Yes, SSR happens on the server. If you use fetch function then it will work on client. But if you use getServerSideProps or getStatisSideProps then it will work on server. You can read from the file system, fetch public API or query the database, whatever you do in getStatisSideProps, getServerSideProps will run on the server, before returning the response.
Yes, you're correct. Client need the data to render the page, so it has to send requests to server and then render.
The third question is the same as the second. I hope the long answer I gave clarified your confusion.
Sorry for long answer.

What is the best way to solve the problem of sending mutations from multiple browser tabs in RTK Query?

I have a simple React application that allows performing CRUD operations on various entities. It uses RTK Query to interact with the backend, and I want to utilize its built-in caching system - invalidating the cache only when a mutation is performed on an endpoint with the given tag. It works fine as long as I have only one tab open. If there are multiple users interacting with the application and one of them performs a mutation, the cache will be invalidated only in this user's browser tab. The update will not be populated to other browsers or tabs that are currently connected to the app. Each user would have to manually refresh the page after another user performed a mutation. One way to solve that is to invalidate the cache periodically, which isn't ideal, another is to force every query to re-fetch on focus, which is even worse. The best scenario would be to somehow detect that another user had sent a mutation for the given endpoint, and then invalidate the cache of this endpoint (by tags) in every other browser tab that is connected to the application. I'm looking for a solution that is better than what I've already implemented, which is the following:
There's a global component with a single websocket, which immediately connects to the backend
The backend assigns a unique identifier to the socket, saves it in a socket pool and sends back an event with the identifier
The component with the socket saves the identifier in Redux
RTK Query adds the identifier as a custom header to every request sent to the backend
The backend checks the HTTP method of the request. If it is a mutation (POST / PUT / PATCH / DELETE), it extracts the identifier from the custom header, filters the socket pool excluding the socket that has the same identifier as in the request, sends an event with the tag of the service that is being mutated to all the filtered sockets
The component's socket receives the event and uses RTK Query's invalidateTags utility function to invalidate the cache of the mutated service
Thanks to that, the whole app functions as if it was a real-time collaboration tool, where every change made by any user is immediately reflected in all the connected browser tabs. However, I think it is a bit too complicated and I feel like I'm reinventing the wheel. This scenario is surely quite popular, and there must be something that I'm missing, like an npm package that solves this problem, an RTK Query option that I've omitted, or a well-known design pattern. Of course, there are multiple packages that allow synchronizing Redux Store across multiple tabs, but that doesn't solve the problem of having multiple users connecting from different devices.
It works fine as long as I have only one tab open
JS code lives within a single tab / open page by default.
That includes JS variables and logic, and the Redux store is just another JS variable.
RTK Query is not specifically designed to interact across tabs. You'll have to write that part yourself.
If the concern is multiple users interacting with the same backend server, that's what RTK Query's polling options are for. Alternately, yeah, you could have the server send a signal via websocket to let the client know it needs to refetch data. But again, that's something you'll need to write yourself, as it's specific to the needs of your own application.

Request with params, processing and rendering SPA - architectural approach

I was not sure how to name the question but here is what I need to do and I'm looking for some advice how to handle it architecture-wise. I'm Java / Kotlin developer very familiar with Spring Boot and very basic knowledge of front end as a whole - just so you know my origin.
Here is the flow of my new application:
user retrieves a generated link with lots of params that he can click in his browser
when he clicks on that link I want to retrieve those params in backend, run some longish external API calls & calculations (up to 10 seconds) and then return results one by one (some websocket or server sent events) and present them in SPA application (preferably React) with results nicely presented so he can pick one of the options I calculated, fill out some form and pay for it.
Maybe I'm confused - I've worked with many front end developers but I never thought how to actually "start" a SPA when someone clicks on some URL with params and then handle all those passed params via backend.
Is what I just wrote doable with React rendered on client side and Spring Boot as the backend? Or do I have to use React server side rendered because I have this static URL with params?
Could someone clarify how I should approach this?
Generally when a SPA is hosted on a domain, the webserver will be configured to redirect all requests on all paths to the root url. So it doesn't matter what path on your domain the user is trying to access, the SPA will still get loaded.
Then in your React SPA you inspect window.location to find the path and params in the url. You then call the backend (most likely on another domain) sending it the params via a web request. It then sends back a response with a random key, and continues to start the time consuming process in the background. When results come in, they are persisted globally in a dictionary against the random key (could be to a database, could be held in memory if you only are going to need one back-end server). Then on another API endpoint, the React front end can poll with the random key and get the current status of the processing, displaying it to the user.

Which is the best option to fetch data from Mongodb database?

Sorry for a general question. My situation looks so: i have mongodb database and 2 reactjs pages. In each page i want to fetch a different information from database. Depending by your practice, which is the best way to fetch data from mongodb in a reactjs component?
I would recommend reading up on the MERN stack - tons of guides available online via google and youtube. The gist would be that a typical web application will consist of a few key components. In this case:
1 - (React) The client page rendered to the user
2 - (Node + Express) The server which processes data, allows you to use endpoints to make changes to your application. These endpoints make the necessary database queries. You can use a database client to write these queries as JavaScript within your NodeJS endpoints.
3 - (MongoDB) Your database.
So for instance a typical CRUD app allows you to create, read, update, and delete. Let's say you are looking at making a standard TODO list app.
You would need to make requests to these endpoints to perform these operations.
You could have a POST to /todo which would then insert a new document into your database.
You would need a way to read the information from the page... say a GET request to /todos to read all items. Or also a GET request to /todo/:id to get a specific item.
You would need a way to update an existing item... say a PUT request to /todo/:id with the updates you want to take place.
Finally you would need a way to delete an item... a DELETE request to /todo/:id which would delete the item.
Each of these endpoints would make a request to insert / read / update / delete items from the database, and return content to the client React code --> which then displays it to the user.
Frontend side, in react.js call api data using fetch() method. Pass your Mongodb URI string. If you want data in slot based use limit() and Skip() function for pagination.
Follow MVC pattern where your frontend only calla controller api. And controller calls DAO methods for Mongodb. You can Use Mongodb Stitch for serverless app.sor data leak can be avoided forntend side. Mongodb has connecting pool max.100 so that each time client request Mongodb connection cashed object given from pool to further speed up your connection time.

Data Flow with React/Redux and Express

I have a React/Redux front-end with an Express back-end application, and I'm rather new, but I have a question regarding how to deal with the flow of data.
So, on my front end side, I have a search bar. When a user enters a search term, I sent a post request from React which is handled in my Express routes.js file. In this file, I am taking that search term, and I am looking for that term in my Mongo database. After that, all I want to do is send an object back if the term was found in the database.
I have used axios in this application to make an HTTP request to a certain route to pull off some data, but that was within an app.get(...) on the express side, and I used an axios.get(...) on the React side to retrieve the information.
But, this situation is slightly different since the data is flowing in two directions. Initially, from a front end to the backend, and then back-end to front-end. And in this case, I'm using app.post(...).
Now my question is, how would I retrieve the data to the front end? Could I simply just do an axios.get(...) on an app.post(...) or is there some other way to do this?
If you GET from the browser to your back-end's route which is implemented to respond to POST only, you will probably get a 405 error. Implement a POST Axios request and a POST Express reply.
You can use either GET or POST, but you need to be consistent on the server and the client side. If you do an http GET from the client, the server will only respond if you have a app.get(...) as a server route.
As far as the flow of data is concerned, both a get and a post can return data, it just needs to be specified on the express route.
After the business logic of looking if the key exists in mongo do something like res.send({'found': true}) or res.json({'found': false}). This will ensure that the data gets back to the client.
If I were to do this, I would:
1.) Use an Axios get request and pass in as a parameter the identifying attributes, such as a related _id or key phrase.
2.) Use mongoDB's query filter search parameters to index and aggregate the schema data in the DB. I would probably use .findOne or .find.
3.) Use the router callback to pass in the filtered data, then dispatch a function to save it to a state.
This way you can set up specific terms or keywords to search with, and utilize the searched data throughout the app.

Resources