Appearance
React Frontend
Setup
Add
<script src="https://apis.google.com/js/api.js"></script>tofrontend/index.html:tsx... <div id="root"></div> <script src="https://apis.google.com/js/api.js"></script> <script type="module" src="/src/main.tsx"></script> ...Install typescript dependencies:
Each google service has a separate package with the typescript declarations:
- drive: @types/gapi.client.drive-v3
- calendar: @types/gapi.client.calendar-v3
- sheets: @types/gapi.client.sheets-v4
- gmail: @types/gapi.client.gmail-v1
- docs: @types/gapi.client.docs-v1
For example, for drive use
shnpm install --save-dev @types/gapi @types/gapi.client @types/gapi.client.drive-v3Add
"gapi", "gapi.client"and the service specific packages to the types infrontend/tsconfig.app.json:json{ "compilerOptions": { "types": [... "gapi", "gapi.client", "@types/gapi.client.drive-v3", ...], } }
Gapi Integration
- Create a
WithGapicomponent:
tsx
import { fetchWithAuth } from "@lib/fetch/fetchWithAuth";
import { buildQueryString } from "@lib/utils";
import { type ReactNode, useEffect, useState } from "react";
export function WithGapi(props: { children: ReactNode }) {
const [loaded, setLoaded] = useState<
{ status: "loading" | "loaded" } | { status: "error"; error: string }
>({
status: "loading",
});
useEffect(() => {
(async () => {
try {
const scopes = [
"https://www.googleapis.com/auth/calendar.events",
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/gmail.send",
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/documents",
].join(" ");
const apis = [
{ name: "drive", version: "v3" },
{ name: "calendar", version: "v3" },
{ name: "sheets", version: "v4" },
{ name: "gmail", version: "v1" },
{ name: "docs", version: "v1" },
];
const tokenUrl =
"/api/gw/platform/token/" +
buildQueryString({
name: "google",
scopes: scopes,
});
const token = await fetchWithAuth<string>(tokenUrl);
gapi.load("client", async () => {
await gapi.client.init({});
gapi.client.setToken({ access_token: token });
await Promise.all(
apis.map((api) => gapi.client.load(api.name, api.version)),
);
setLoaded({ status: "loaded" });
});
} catch (e) {
setLoaded({ status: "error", error: "" + e });
}
})();
}, []);
if (loaded.status === "loaded") return <>{props.children}</>;
else if (loaded.status === "error")
return <div> Error loading GAPI: {loaded.error} </div>;
else return <div> Loading GAPI... </div>;
}This example can access the Google Drive, Calendar, Sheets, Mail and Docs APIs. The WithGapi component can also be parameterized by modifying the useEffect() function. That way, scopes and clients can be created dynamically.
- Wrap your base google component with the
WithGapicomponent inApp.tsx.
tsx
return (
<WithGapi>
<Container>...</Container>
</WithGapi>
);Usage
Now React components can call Google APIs directly. For example:
tsx
const response = await gapi.client.calendar.events.list({
calendarId,
timeMin: now.toISOString(),
timeMax: max.toISOString(),
singleEvents: true,
orderBy: "startTime",
});