Access application wide client when using Redux? - redux

I'm using Redux to manage state and Apollo to execute graphQL queries.
I create an Apollo client that should be accessible from various React components.
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
const link = new HttpLink({
uri: getGraphqlEndpointUrl,
headers: {
'x-api-key': getApiKey(),
'Authorization': jwtToken,
},
});
const client = new ApolloClient({
link: link,
cache: new InMemoryCache(),
});
How do I do this with Redux? Do I store the client in a variable in the Redux store? That seems a bit strange to me, but not unreasonable. Is there a better way though?

Only serializable objects should be stored through redux -- functions or objects that have functions as properties do not belong in a redux store. If you need to reference the Apollo client outside of the component hierarchy of your React app, just create a module that exports the client object itself (not a function that creates a client). Then you can just import the client whereever (including the code that includes your ApolloProvider) and all your code will point at the same instance of the client (and the same cache).
It's important that the module for your client export the instantiated client itself -- if you export a function that creates the client, you'll be recreating it each time you import it.

Related

NextJS: How can I create a server side request context

I need to forward a header from the browser to an external API I call from the server side.
The external API is called from getServerSideProps and API routes.
I was thinking about implementing some sort of a request context (using AsyncLocalStorage for example) that I can access from anywhere in the server side code.
That way I could create a middleware that will save the header to the context, and in the external API client I'll fetch it from the context and add it to the requests.
For example:
// context.ts
export const context = new AsyncLocalStorage<string>();
// middleware.ts
export function middleware(request: NextRequest) {
const store = request.headers[SOME_HEADER];
return context.run(store, () => NextResponse.next());
}
// client.ts
axios.post(EXTERNAL_API, DATA, {
headers: {
SOME_HEADER: context.getStore()
}
}).then(...)
Currently I simply send it as a parameter which is pretty tedious.
Is there a way of achieving it?
I tried adding async_hooks to my project but it got really messy when I tried to build the project.

ReferenceError: localStorage is not defined on Deno Deploy

I'm using localStorage on the server and it works fine locally. But when I deployed my code to Deno deploy is not defined
Do I need to import the localStorage? I Deno.com I couldn't find any docs talking about localStorage so maybe that feature is not supported yet. In that case, where can I deploy my code to use it? Thanks
import {Handlers, PageProps} from "$fresh/server.ts";
interface Data {
email: string[]
}
export const handler: Handlers<Data> = {
GET(_req, ctx) {
const emailsStorage = localStorage.getItem("email");
const email = emailsStorage ? JSON.parse(emailsStorage) : [];
console.log(email);
return ctx.render({ email });
},
};
export default function EmailPage({ data }: PageProps<Data>) {
const { email } = data;
return (
<main>
<h1>Emails</h1>
<ul>
{email.map((email) => (
<li>{email}</li>
))}
</ul>
</main>
);
}
The full list of available APIs is here (note that localStorage is not listed).
Deploy does not offer any persistent data storage mechanism. After your deployed code finishes executing in response to a request, all of the JS memory is destroyed, so if you want to work with mutable data that persists between requests, then you'll have to store that data yourself elsewhere — e.g. by sending the data in a network request to another server / hosted database / etc. and then requesting it when you need it.
The docs include several "persist data" tutorials that you can use as a guide/reference in order to learn.
You can persist data in local storage by creating a virtual local Storage by using this code.
import { installGlobals } from "https://deno.land/x/virtualstorage#0.1.0/mod.ts";
installGlobals();
localStorage.getItem("email") will work on Deno Deploy also.

How to verify the request is coming from my application clientside?

I have an app where users can create posts. There is no login or user account needed! They submit content with a form as post request. The post request refers to my api endpoint. I also have some other api points which are fetching data.
My goal is to protect the api endpoints completely except some specific sites who are allowed to request the api ( I want to accomplish this by having domain name and a secure string in my database which will be asked for if its valid or not if you call the api). This seems good for me. But I also need to make sure that my own application is still able to call the api endpoints. And there is my big problem. I have no idea how to implement this and I didn't find anything good.
So the api endpoints should only be accessible for:
Next.js Application itself if somebody does the posting for example
some other selected domains which are getting credentials which are saved in my database.
Hopefully somebody has an idea.
I thought to maybe accomplish it by using env vars, read them in getinitalprops and reuse it in my post request (on the client side it can't be read) and on my api endpoint its readable again. Sadly it doesn't work as expected so I hope you have a smart idea/code example how to get this working without using any account/login strategy because in my case its not needed.
index.js
import Head from 'next/head'
import Image from 'next/image'
import styles from '../styles/Home.module.css'
export default function Home(props) {
async function post() {
console.log(process.env.MYSECRET)
const response = await fetch('/api/hello', {
method: 'POST',
body: JSON.stringify(process.env.MYSECRET),
})
if (!response.ok) {
console.log(response.statusText)
}
console.log(JSON.stringify(response))
return await response.json().then(s => {
console.log(s)
})
}
return (
<div className={styles.container}>
<button onClick={post}>Press me</button>
</div>
)
}
export async function getStaticProps(context) {
const myvar = process.env.MYSECRET
return {
props: { myvar },
}
}
api
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
export default function handler(req, res) {
const mysecret = req.body
res.status(200).json({ name: mysecret })
}
From what I understand, you want to create an API without user authentication and protect it from requests that are not coming from your client application.
First of all, I prefer to warn you, unless you only authorize requests coming from certain IPs (be careful with IP Spoofing methods which could bypass this protection), this will not be possible. If you set up an API key that is shared by all clients, reverse engineering or sniffing HTTP requests will retrieve that key and impersonate your application.
To my knowledge, there is no way to counter this apart from setting up a user authentication system.

Using NodeJS EventEmitter on Meteor server

I’m implementing an app that makes uses of EventEmitter. My aim is to use it on both client and server. But strangely, emitting an event on the server does not work:
Emitter.emit('SomeEvent', {
user,
document,
}
);
The above will work on the client, but not on the server.
I’ve tried importing the event like Emitter = new (require('events').EventEmitter);
I’ve also tried to import a file with
import EventEmitter from 'events';
class ClassEmitter extends EventEmitter {}
const Emitter = new ClassEmitter();
export default Emitter;
My aim is to emit such an event after each database query on the server. I am using apollo and graphql.
Any idea on this would be very thankful.

Login app with Redux & ReactRouter

I would be thankful if someone could point me into a right direction in understanding the Redux architecture.
I should implement "reducer" functions that will handle my actions.
Reducer functions should be combined and create a store.
Lets say I have a LoginForm (React) component, that makes a XHR request to backend API, and receives a JWT token in response.
When I get the response from the API I should dispatch an action like:
store.dispatch({type: "USER_LOGGED_IN",
payload: {username: "john", JWT: "..."});
This updates the state of my application.
What next?
How do I route to to next page? How do I rerender my components (like navbar, etc.) with the logged in username?
Do I use listeners for that?
Let's say you've a method to authorize user:
import { browserHistory } from 'react-router';
// ...
function promisedApiCall(inputData) {
// ...
// api request to backend with input data
// return a promise
}
/*
* on form submit we call this with input data
*/
function authorizeUser(inputData) {
return promisedApiCall(inputData)
.then((response) => store.dispatch({
type: "USER_LOGGED_IN",
payload: {
username: response.userName,
JWT: response.JWT
}
}))
.then(() => browserHistory.push('/success/path/url'))
.catch(() => browserHistory.push('/failure/path/url'));
}
Assuming you have the following prerequisites:
Created redux store and store object is available in the scope where authorizeUser() is executed.
The method promisedApiCall is the function which makes the request to backend with input data from LoginForm.
promisedApiCall should return a promise. [this is really important]
Configured react-router with redux
Once this is complete, app state is updated with user info and also user will be redirected to a new page. This post explains more about programmatically redirecting using react-router.
Access you app state in you component using Redux connect.
Now you have the user info in your component as props.
react-router has a component browserHistory.You can import that like this,
import {browserHistory} from 'react-router';
And to change your route,
browserHistory.push(<route_where_you want_to_go>);
This will let you change the route.

Resources