What is the best way to structure REST backend API calls with React? - reactjs

Currently me and some colleagues are building a full stack web application, using React as our frontend framework. In this application, we need to perform CRUD operations on multiple resources, therefore multiple pages.
In my previous experience, I found tutorials/courses that put API calls in a services folder. Here's a simple example.
However, I realized this approach doesn't address loading/error states. So, I tried to come up with a solution using hooks, following another example I found: code.
This worked well for a feature I implemented, but I don't know how extensible it can be.
My question is, what is the better approach? Is there another one I didn't mention?

Reactjs is a library not a framework like Angular, there no one single approach how to handle your project structure. There are many alternatives, try to follow the good practices; if you are developing a big project that needs to scale use Redux as state management library, for me for a simple React project, we make folder called services and in an index file we prepare all our services :
/* root services ⚓️ .. */
import axios from 'axios';
const API_URL = 'http://yourapi.com/api/';
const headers = { 'Content-Type': 'application/json' };
const add = (data) => axios.post(`${API_URL}/form`, data, { headers });
const getData = () => axios.get(`${API_URL}/hotels`, { headers });
etc ...
export {
add,
getData
};
And for the call into Components
import { serviceName } from '../services/index';
serviceName({/*params if it's necessary */ })
.then(data => {
//---Get your Data
})
.catch(err => {
//---Handle your Api call error
});

Related

How to improve SEO with getServerSideProps() in NextJS?

I have a website that will show dynamic data (Articles), i.e data that changes hourly.
I therefore have opted to use getServerSideProps() from NextJS.
export async function getServerSideProps() {
const url = process.env.NEXT_PUBLIC_API_URL
const articles = await fetch(url + 'article').then(res => res.json()).catch(err => console.error(err))
console.log("articles", articles);
return {
props: {
articles,
}
}
}
I could not use getStaticPaths() because the data changes so frequently, an hour after building the site and all the static paths would point to out-of-date articles, and all the new articles would not have any paths pointing to them. I also looked at ISR however this also wouldn't work as it relies on knowing the paths in advance.
My issue arises that because getServerSideProps() is completely dynamic, search engines do not see any of the dynamic pages (which is pretty much the entire site), and therefore I do not rank well.
Is there a way to use getServerSideProps() with some kind of caching, that will allow search engines to see the pages? If not, is there an alternative framework I can use that allows dynamic pages while retaining some SEO performance?
First of all, reduce the number of dynamic pages. too many dynamic pages will put your app at risk of cloaking and google hates it.
Generate sitemap. sitemap will improve the SEO but it is very hard for getServerSideProps because those functions are not available during build time. Use this npm package: next-sitemap. it helps for dynamic pages too.
Server side index-sitemaps (getServerSideSitemapIndex)
Here's a sample script to generate index-sitemap on server side.Create pages/server-sitemap-index.xml/index.tsx page and add the following content.
// pages/server-sitemap-index.xml/index.tsx
import { getServerSideSitemapIndex } from 'next-sitemap'
import { GetServerSideProps } from 'next'
export const getServerSideProps: GetServerSideProps = async (ctx) => {
// Method to source urls from cms
// const urls = await fetch('https//example.com/api')
return getServerSideSitemapIndex(ctx, [
'https://example.com/path-1.xml',
'https://example.com/path-2.xml',
])
}
// Default export to prevent next.js errors
export default function SitemapIndex() {}

How to call multiple memoized functions in a React Repo - Service - Context Architecture?

I'm working on a Ionic Capacitor React app with a Repo/Service/Context architecture:
All the functions that do API calls as well as for local storage are in the Repo files.
The Service files have functions that pass in the dependencies that call functions from the Repo files and the process that data.
The Context memoizes the Service functions and makes them available in the context.
So if I have need to create a function that calls multiple memoized service functions, is there an established best practice for how to do this with this architecture? The three options I can think of are (these are of course simplified examples):
Create a function in the Context file that uses the multiple memoized functions.
// in example.context.jsx
export const getAndStoreExamples = (exampleIds) =>
{
const examples = await connectedGetExamples(exampleIds);
await connectedStoreExamples(exampleIds);
};
Create a function in the Service file that has the memoized functions passed in as dependencies and then calls them:
// in example.service.js
export const getAndStoreExamples = (connectedGetExamples, connectedStoreExamples) => async (exampleIds) =>
{
const examples = await connectedGetExamples(exampleIds);
await connectedStoreExamples(exampleIds);
};
Create a function in the Service file that directly calls the functions that are defined in the Service file:
// in example.service.js
export const getAndStoreExamples = (exampleIds) =>
{
const examples = await getExamples(dep1,dep2)(exampleIds);
await storeExamples(dep1,dep2)(exampleIds);
};
EDIT: I noticed a vote to close because this is opinion based. Part of the question about established best practice is also the inverse: will any of these options not work properly?

How to test custom React-query hook that is based on Firebase methods?

I came across react-query-firebase which are hooks that are built on React-query for firebase.
I also found library called mock service worker https://mswjs.io/ however it is based on REST and GraphQL.
Here is an example code how I would use these hooks:
import React from "react";
import { useFirestoreDocument } from "#react-query-firebase/firestore";
import {
doc
} from "firebase/firestore";
import { firestore } from "../firebase";
function GetUser() {
const id = "pW5CizOJOpXezr5lGGshDmKdVpP3";
const ref = doc(firestore, "users", id);
const user = useFirestoreDocument(["users", id], ref);
return (
<div>
{user.isLoading && <div>Loading...</div>}
{user.data && <div>{user.data.data()?.name}</div>}
</div>
);
}
export default GetUser;
I am new to testing and I have no idea how would I have to execute this test, since I am mocking requests can I use random url anyways or does it have to be firebase related methods?
react-query-firebase library is an abstraction over Firebase that encapsulates resource paths (it's an SDK, I believe). Since the paths (URLs) are abstracted from, you have at least two options for how to mock requests issued by such libraries.
Option 1: Use explicit paths
Although the exact resource paths are hidden away, requests still reference existing absolute paths. You can observe those in the "Network" tab of your browser or by enabling a simple request introspection with msw:
// my.test.js
import { setupServer } from 'msw/node'
const server = setupServer(/* no handlers */)
beforeAll(() => server.listen())
afterAll(() => server.close())
Since we're using setupServer with no handlers, all requests that happen in my.test.js will be printed as warnings to stderr. You can observe those warnings to see what resource paths your SDK requests.
The benefit of using an SDK is that it guarantees you a certain resource path structure. Most likely, you will be able to replicate that structure in your mocks:
// src/mocks.js
import { rest } from 'msw'
export const handlers = [
rest.get('https://some-resource.:checksum.firebase.app/path', (req, res, ctx) => res(ctx.text('hello)))
]
Utilize dynamic path segments like :checksum to match a broader range of paths.
The downside of this approach is that your mock definition becomes dependent on the SDK internal details (resource paths). Any updates to the SDK may break your mocks, since they may update the path structure internally without denoting it as a breaking change (abstracted paths are not public API).
Option 2: Spy on the SDK
Alternatively, you can spy on the SDK you're using. An example of such a spy would be using jest.spyOn on the react-query-firebase directly:
// my.test.js
import * as reactQueryFirebase from 'react-query-firebase'
it('creates a user', () => {
jest.spyOn(reactQueryFirebase, 'SOME_METHOD_NAME')
.mockReturnValue(/* mock */)
})
The downside of this method is that you're stubbing the functions from a third-party library, which means your code under test never calls those functions. This decreases the reliability of such a test, and you should, generally, avoid resorting to this approach.
I do recommend you research Firebase, since major SDK providers often have guidelines on mocking their API. Often such a guidance would include using a dedicated third-party package authored by the SDK provider that allows mocking their internal resources.

How to create and update a text file using React.js?

I am trying to save a variable's data into a text file and update the file every time the variable changes. I found solutions in Node.js and vanilla JavaScript but I cannot find a particular solution in React.js.
Actually I am trying to store Facebook Long Live Access Token in to a text file and would like to use it in the future and when I try importing 'fs' and implementing createFile and appendFile methods I get an error saying Method doesn't exist.
Please help me out. Here is the code below
window.FB.getLoginStatus((resp) => {
if (resp.status === 'connected') {
const accessToken = resp.authResponse.accessToken;
try {
axios.get(`https://graph.facebook.com/oauth/access_token?client_id=CLIENT_id&client_secret=CLIENT_SECRET&grant_type=fb_exchange_token&fb_exchange_token=${accessToken}`)
.then((response) => {
console.log("Long Live Access Token " + response.data.access_token + " expires in " + response.data.expires_in);
let longLiveAccessToken = response.data.access_token;
let expiresIn = response.data.expires_in;
})
.catch((error) => {
console.log(error);
});
}
catch (e) {
console.log(e.description);
}
}
});
React is a frontend library. It's supposed to be executed in the browser, which for security reasons does not have access to the file system. You can make React render in the server, but the example code you're showing is clearly frontend code, it uses the window object. It doesn't even include anything React-related at first sight: it mainly consists of an Ajax call to Facebook made via Axios library.
So your remaining options are basically these:
Create a text file and let the user download it.
Save the file content in local storage for later access from the same browser.
Save the contents in online storage (which could also be localhost).
Can you precise if any of these methods would fit your needs, so I can explain it further with sample code if needed?

How to access elements of FirebaseListObservable from scripts

I am working with Angular 2 (more precisely Ionic 2) and Firebase. I use angularfire2 to make them communicate.
While I can very easily go through all the elements of a FirebaseListObservable in a view (using the pipe async syntax), I cannot find a way of doing this from within my scripts.
I've been looking for a while and there are no examples which show this way of accessing the data; they all access it from the view part of the application.
How can I access the elements of FirebaseListObservable from within scripts?
Not 100% sure what you are asking but i use
getData(fbPath:string) {
return new Promise(resolve => {
this.af.database.list(fbPath).subscribe(res => resolve(res));
})
}
In my firebase service. I can then use it in the component like so
this.api.getData('organisations').then(data => {
console.log(data);
}

Resources