Data Access Layer #13
@@ -7,3 +7,4 @@ albums/
|
|||||||
wallpapers/
|
wallpapers/
|
||||||
frontend/node_modules/
|
frontend/node_modules/
|
||||||
frontend/.next/
|
frontend/.next/
|
||||||
|
frontend/src/data/types.ts
|
||||||
|
|||||||
Executable
+16
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
set -- "BACKEND_HOST"
|
||||||
|
fi
|
||||||
|
|
||||||
|
HOST=$(grep "$1" .env 2>/dev/null | cut -d '=' -f 2 | tr -d '"')
|
||||||
|
echo $1
|
||||||
|
echo $HOST
|
||||||
|
cmd="npx openapi-typescript $HOST/api/schema/ -o src/data/types.tmp.ts"
|
||||||
|
if eval $cmd
|
||||||
|
then
|
||||||
|
echo $cmd
|
||||||
|
mv src/data/types.tmp.ts src/data/types.ts
|
||||||
|
fi
|
||||||
|
chmod go+rw src/data/types.ts
|
||||||
@@ -9,10 +9,11 @@
|
|||||||
"react-oidc-context": "^3.3.0"
|
"react-oidc-context": "^3.3.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "npm run generate:types && next dev",
|
||||||
"build": "next build",
|
"build": "npm run generate:types && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint"
|
"lint": "next lint",
|
||||||
|
"generate:types": "bash generate_types.sh DOCKER_BACKEND"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/postcss": "^4.1.10",
|
"@tailwindcss/postcss": "^4.1.10",
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { getUser } from "muzak/data/fetch";
|
import { getUser } from "muzak/data/fetch";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import api from "muzak/data/fetcher";
|
import { api, User } from "muzak/data/fetcher";
|
||||||
|
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
const [userData, setUserData] = useState([]);
|
const [userData, setUserData] = useState<User[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function getUsers() {
|
async function getUsers() {
|
||||||
@@ -17,7 +17,7 @@ export default function Page() {
|
|||||||
return (
|
return (
|
||||||
<div className="flex min-h-screen flex-col items-center justify-around">
|
<div className="flex min-h-screen flex-col items-center justify-around">
|
||||||
{userData.length > 0 ? (
|
{userData.length > 0 ? (
|
||||||
userData.map((user) => <div key={user.id}>{user.email}</div>)
|
userData.map((user: User) => <div key={user.id}>{user.email}</div>)
|
||||||
) : (
|
) : (
|
||||||
<div>Loading users...</div>
|
<div>Loading users...</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { Fetcher } from "openapi-typescript-fetch";
|
import { Fetcher } from "openapi-typescript-fetch";
|
||||||
import { getUser } from "./fetch";
|
import { getUser } from "./fetch";
|
||||||
|
import { paths, components } from "muzak/data/types";
|
||||||
|
|
||||||
interface GenericPaths {
|
const fetcher = Fetcher.for<paths>();
|
||||||
[path: string]: {
|
|
||||||
[method: string]: any;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const fetcher = Fetcher.for<GenericPaths>();
|
|
||||||
const BASE_URL = process.env.BACKEND_HOST || "http://127.0.0.1:8001";
|
const BASE_URL = process.env.BACKEND_HOST || "http://127.0.0.1:8001";
|
||||||
|
|
||||||
// Configure the fetcher
|
// Configure the fetcher
|
||||||
@@ -19,7 +15,7 @@ fetcher.configure({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
use: [
|
use: [
|
||||||
// Authentication middleware
|
// Add authentication token to request
|
||||||
async (url, init, next) => {
|
async (url, init, next) => {
|
||||||
const user = getUser();
|
const user = getUser();
|
||||||
if (user?.access_token) {
|
if (user?.access_token) {
|
||||||
@@ -30,18 +26,14 @@ fetcher.configure({
|
|||||||
}
|
}
|
||||||
return next(url, init);
|
return next(url, init);
|
||||||
},
|
},
|
||||||
// Error handling middleware
|
// Handle errors
|
||||||
async (url, init, next) => {
|
async (url, init, next) => {
|
||||||
const response = await next(url, init);
|
const response = await next(url, init);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
// Handle authentication errors
|
|
||||||
if (response.status === 401) {
|
if (response.status === 401) {
|
||||||
console.warn("Authentication failed - token may be expired");
|
console.warn("Authentication failed - token may be expired");
|
||||||
// You might want to trigger a redirect to login or token refresh here
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log other errors
|
|
||||||
console.error(`API Error: ${response.status} ${response.statusText}`, {
|
console.error(`API Error: ${response.status} ${response.statusText}`, {
|
||||||
url,
|
url,
|
||||||
method: init.method,
|
method: init.method,
|
||||||
@@ -53,7 +45,6 @@ fetcher.configure({
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create your API methods
|
|
||||||
export const api = {
|
export const api = {
|
||||||
tracks: {
|
tracks: {
|
||||||
list: fetcher.path("/api/track/").method("get").create(),
|
list: fetcher.path("/api/track/").method("get").create(),
|
||||||
@@ -88,4 +79,9 @@ export const api = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type User = components["schemas"]["User"];
|
||||||
|
export type Track = components["schemas"]["Track"];
|
||||||
|
export type Album = components["schemas"]["Album"];
|
||||||
|
export type Vote = components["schemas"]["Vote"];
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
|
|||||||
Reference in New Issue
Block a user