Remix js localstorage alternative for server side - node.js

I have a remix application to act like frontend.
I load data from my backend and for some data I need to load it only once and reuse it on different pages.
In previous frontend we used localstorage but here is server side which returns me ReferenceError: window is not defined
import {LoaderFunction} from "#remix-run/node";
import authenticator from "~/services/auth.server";
import Layout from "~/src/Layout";
import {fetchData} from "~/services/fetch.service";
export let loader: LoaderFunction = async ({request}) => {
const user = await authenticator.isAuthenticated(request, {failureRedirect: "/login",});
const configs = await fetchData('GET', request, 'api/configs/all')
.then((response) => {
return response;
})
.catch(async error => {
await authenticator.logout(request, {redirectTo: "/login"});
});
try {
localStorage.setItem('parameters', configs);
} catch (e) {
console.log(e);
}
return {
user: user,
request: request
};
};
export default function DashboardPage() {
const data = useLoaderData();
return (
<Layout user={data?.user} request={data.request}>
</Layout>
);
}
I need the config to be accessable at any time, it's not usefull if I need to load it all the time.

You can't use localStorage on the server-side, since it is first set on the client. You could use cookies since they are accessible on the server-side.

Related

How to properly handle errors on subscriptions with Apollo Server?

I have an Express + Apollo Server backend. I enabled subscriptions on it using ws and graphql-ws. Everything is working fine.
Now, I would like to handle resolvers errors properly: hide backend details in production, change message based on error type, add a unique ID, etc. On regular mutations, I'm able to do so using the formatResponse function.
On subscriptions, I can't find where I could do it. All I need is a function called before sending data to the client where I have access to data and errors.
How can I do that?
Here's how the WS Server is created:
// Create Web Socket Server
const wsServer = new WebSocketServer({
server: httpServer,
path: '/graphql'
});
const serverCleanup = graphqlWS.useServer(
{
schema: graphqlApp.schema,
context: async (ctx: any) => {
try {
// ...Some auth checking...
return context;
} catch (e) {
throw new ApolloAuthenticationError('you must be logged in');
}
}
},
wsServer
);
And an example of event sending:
import {PubSub} from 'graphql-subscriptions';
// ...
Subscription: {
tree: {
subscribe: withFilter(
() => pubsub.asyncIterator('some_id'),
(payload, variables) => {
const canReturn = true;
//...Some filtering logic...
return canReturn;
}
)
}
},

What is the best approach to build a NextJS app with a separate NodeJS back-end [duplicate]

I am new in Next.js.
I want to know what is the use of export default function handler because we can directly call the API using fetch.
In my HTML code I put below code. When I click on submit button sendformData() function will be called.
<input type="button" value="Submit" onClick={() => this.sendformData()} ></input>
sendformData = async () => {
const res = await fetch("/api/comments/getTwitFrmUrl?twitUrl=" + this.state.twitUrl, {
headers: {
"Content-Type": "application/json",
},
method: "GET",
});
const result = await res.json();
this.setState({ data: result.data });
};
When sendformData function is called, it calls /api/comments/ file and calls the function.
Here is the /api/comments/[id].js file code.
export default async function handler(req, res) {
if (req.query.id == 'getTwitFrmUrl') {
const resData = await fetch(
"https://dev.. .com/api/getTwitFrmUrl?twitId=" + req.query.twitUrl
).then((response) => response.text()).then(result => JSON.parse(result).data);
res.status(200).json({ data: resData });
}
else if (req.query.id == 'getformdata') {
console.log('getformdata api');
res.status(200).json({ user: 'getuserData' });
}
}
When I put the below code in the sendformData same response will be retrieved. So why we need to call
export default function handler function?
sendformData = async () => {
const res = await fetch(
"https://dev.. .com/api/getTwitFrmUrl?twitId=" + req.query.twitUrl
).then((response) => response.text()).then(result => JSON.parse(result).data);
const result = await res.json();
this.setState({ data: result.data });
};
If you already have an existing API there's no need to proxy requests to that API through an API route. It's completely fine to make a direct call to it.
However, there are some use cases for wanting to do so.
Security concerns
For security reasons, you may want to use API routes to hide an external API URL, or avoid exposing environment variables needed for a request from the browser.
Masking the URL of an external service (e.g. /api/secret instead of https://company.com/secret-url)
Using Environment Variables on the server to securely access external services.
— Next.js, API Routes, Use Cases
Avoid CORS restrictions
You may also want to proxy requests through API routes to circumvent CORS. By making the requests to the external API from the server CORS restrictions will not be applied.

Get the Message notification from Nodejs REST API using Angular8 in background

I am working on an application where I want to implement the message Inbox. I have created the message inbox using Angular8 and NodeJS REST API. Now I want to get the on inbox message in every 30 Second on the background when user login also it doesn't want to affecting the performance of the Angular app.
So I want to Implement the Web-worker with Angular8 to get the Data from NodeJS REST API but I am unable to create.
I have added following code in Angular 8 App
Add this code to app.component.ts
getWorker(token){
if (typeof Worker !== 'undefined') {
// Create a new
const worker = new Worker('../../web-worker/messenger.worker', { type: `module` });
worker.postMessage(token);
worker.onmessage = (e) => {
setTimeout(() => {
worker.postMessage(token)
}, 15000);
};
} else {
// Web Workers are not supported in this environment.
// You should add a fallback so that your program still executes correctly.
}
}
Created worker file with fetch
/// <reference lib="webworker" />
addEventListener('message', ({ data }) => {
const response = `worker response to ${data}`;
postMessage(response);
});
import { environment } from "src/environments/environment";
onmessage = (message:any) => {
fetch(environment.apiUrl +'messages/notification/1/1',
{ method:'GET',
headers:new Headers({
Authorization: `Bearer ${message.data}`
})
}
)
.then(response => {
return response.json()
})
.then(commits => {
// self.onmessage(message)
return commits
});
};
but it shows the type as fetch is should be show web worker Right?
Can anyone help me with this?

How to deal with backend dynamically allocated ports on react.js side using axios?

This morning I deployed a MERN stack login app in heroku successfully. But, when I tried to login
GET http://localhost:5000/user/login/email/password net::ERR_CONNECTION_REFUSED
in the console.
I understood that that the error is because I am making get request in axios using
axios.get("http://localhost:5000/user/login/" + this.state.email + "/" + this.state.password).then((res) => {
if (res.status === 200) {
this.setState({ status: res.status, name: res.data.name });
console.log(res.data);
}
else
throw new Error(res.status);
}).catch((err) => {
this.setState({ isInvalid: true });
})
But, the port is being dynamically allocated on the server side.
const port = process.env.PORT||5000;
app.listen(port, () => {
console.log("Server started on port:" + port);
});
Tried allocating only hardcoded value to the port. Still no luck
There are lots of mistakes in your code. You have deployed your app but your URL is still localhost which is not Heroku URL. First of all you need to setup env variables for your application like this.
You can put this in some constant file from where you get your end point. Don't write END POINTS directly in the ajax calls. Use constant and create a single file for from where you do all the ajax calls of the application.
You can set the env for both frontend and backend and this is how you should work. The development env should be separate from production one.
if (process.env.NODE_ENV === "development") {
API = "http://localhost:8000";
} else if (process.env.NODE_ENV === "production") {
API = "https://be-prepared-app-bk.herokuapp.com";
}
Don't use GET for the login and sending email and password in parameters. You should use POST and send all the data in body.
Here's how you single ajax file should look alike:
import { API_HOST } from "./constants";
import * as auth from "../services/Session";
const GlobalAPISvc = (endPoint, method, data) => {
const token = auth.getItem("token");
const uuid = auth.getItem("uuid");
return new Promise((resolve, reject) => {
fetch(`${API_HOST}${endPoint}`, {
method: method,
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json",
"x-authentication": token,
uuid: uuid
}
})
.then(res => {
return res.json();
})
.then(json => {
resolve(json);
})
.catch(error => {
reject(error);
});
}).catch(error => {
return error;
});
};
export default GlobalAPISvc;
I have created an application in MERN which I made public on GitHub. Feel free to take help from that. Repository Link
Firstly, I would suggest you, not to use get request method for login.
Secondly, if you've deployed your backend code then use dynamic url provided by heroku for login request.
e.g. if your url is xyz.heroku.com then axios.get('xyz.heroku.com/user/login/'+email+'/'+password);
as now you don't need to hard-code the port or use localhost.

NodeJS + Axios instance + Cached between requests

Current setup is VueJS + SSR, but any React JS solutions probably work too.
I have a file called axios.js in which I create a new axios instance and set the apropiate Authorization headers.
import axios from 'axios'
axios.interceptors.request.use((config) => {
config.foo = 123;
});
const instance = axios.create();
instance.verylongunexistingattribute = new Date().toUTCString()
instance.interceptors.request.use((config) => {
config.foo = 456;
});
axios.get('/foo'); // config.foo === 123 -> true
instance.get('/foo'); // config.foo === 456 -> true
export { instance, createInstance, initializeApiV2 }
Seems fine to me, then in my file where I do the AJAX requests I simply do:
import axios from '#/src/api/axios'
let fetchUserProperties = () => {
console.log("axios:instance", axios.verylongunexistingattribute)
console.log("axios:instance.request", new Date().toUTCString())
return new Promise((resolve, reject) => {
axios.get(`/profile/properties`)
.then((result) => {
resolve(result.data)
})
.catch((error) => {
reject(error)
})
});
}
Just to remember, this works perfect in the browser, but fails miserably on node.
Why does it fail: enter link description here
Basically, the instance created in axios.js is being cached by node, so that following request made by diferent users end up using the same instance. And if a requestInterceptor with the token has already been defined then it might show other users data :(
I can't get my head around it, as I can't just return a function which creates a new instance of axios everytime it is called.
How can I create an axios instance which will only live for 1 request?
I tried to explain it as best as I could, if you need more info just ask.

Resources