Services in Remix
creating light service clients for server->server requests w/ Remix.
/*********
Folder Structure
app
|--- models (where prisma models go)
|--- services (where I place my server-side encapsulated logic)
|--- service_folder
|--- service.server.ts
|--- service.types.ts
|--- service.config.ts
***********/
// app/services/notes/notes.types.ts
export type NotesServiceConfig = {
BASE_URL: string;
API_ID?: string;
API_SECRET?: string;
}
expor type Note = {
id: string;
userId: string;
title: string;
body: string;
createdAt: string; // will convert when needed
}
// app/services/notes/notesService.config.ts
import {NotesServiceConfig} from "./notes.types.ts"
export const NotesConfig: NotesServiceConfig = {
BASE_URL: "https://link.to.site/base/api/path",
API_ID: process.env.SOME_API_APP_ID,
API_SECRET: process.env.SOME_API_SECRET
}
// app/services/notes/notesService.server.ts
import {axios} from "axios" // NOTE: maybe use fetch if there on server?
import {NotesConfig as config} from "./notes.config.ts"
import {Note} from "notes.types.ts"
const setHeaders = (config: NotesServiceConfig) => {
return {
headers: {
"api-id-header": config.API_ID,
"api-secret-header": config.API_SECRET
}
}
}
export const getNotes = async (userId: string): Note[] => {
const { data } = await axios.get(`${BASE_URL}/notes/${userId}`,
{...setHeaders(config)}
)
return data
}
// app/routes/notes/index.tsx
...
// loader function
export const loader: LoaderFunction = async({params}) = {
// get userId from session
const userId = await requireUserId(request);
const notes = await getNotes(userId)
// handle error if notes don't exist or throws an error
return notes
}
export default function Component() {
const notes = useLoaderData<Note[]>();
...
}