website/frontend/src/api/RESTful.ts

101 lines
3.2 KiB
TypeScript

import { AuthenticationPage, AuthenticationRules } from "../pages/auth/auth";
import { NewsData, NewsFeed } from "../pages/feed/news";
import { NewsItem } from "../pages/feed/news-item";
type EndpointURL = "/api" | `http${'s' | ''}://${string}`;
interface ErrorDetails {
code: string,
message: string,
}
interface APIResponse<T> {
response ?: T;
error ?: ErrorDetails;
}
let newsFeed : NewsFeed | null = null;
let authPage : AuthenticationPage | null = null;
class ErrorAPI extends Error {}
export class ControllerAPI {
protected endpoint: EndpointURL;
constructor(endpoint: EndpointURL = "/api") {
this.endpoint = endpoint;
}
protected async request<T>(path: string, options: RequestInit = {}): Promise<T> {
let url : string;
if (this.endpoint === "/api") {
url = new URL("/api", window.location.origin).href + path;
}
else if (/\/$/i.test(this.endpoint)) {
url = this.endpoint + path.slice(1);
}
else {
url = this.endpoint + path;
}
const response = await fetch(url, options);
const result: APIResponse<T> = await response.json();
if (result.error) throw new ErrorAPI(result.error.message);
if (result.response === undefined) throw new ErrorAPI("Missing response from API");
return result.response;
}
protected checkFirstAuth(): boolean {
// Implement your authentication logic here, e.g., check for a valid token in localStorage
//const token = localStorage.getItem('authToken');
//return !!token; // Returns true if token exists and is not empty
return true;
}
protected throwIfUnauthed(): void {
// Let's redirect to /auth if not authed
if (!this.checkFirstAuth()) {
window.location.href = '/auth';
}
}
async isAuthenticated(): Promise<boolean> {
if (!this.checkFirstAuth()) return false;
const result = await this.request<boolean>('/isAuthenticated', {
method: 'GET',
credentials: 'include' // Include cookies for authentication
});
return result;
}
async getNews(returnPage: boolean = false) : Promise<NewsFeed | NewsData[]> {
this.throwIfUnauthed();
const result = await this.request<NewsData[]>('/news', {
method: 'GET',
credentials: 'include' // Include cookies for authentication
});
if (!returnPage)
return result;
if (!newsFeed)
newsFeed = new NewsFeed(result.map(x => new NewsItem(
x.id,
x.title,
new Date(x.publishedAt),
x.content,
x.source
)));
return newsFeed;
}
async getAuthRules(returnPage: boolean = false) : Promise<AuthenticationRules | AuthenticationPage> {
const result = await this.request<AuthenticationRules>('/authenticationRules', {
method: 'GET',
credentials: 'include' // Include cookies for authentication
});
if (!returnPage) return result;
if (!authPage)
authPage = new AuthenticationPage(result);
return authPage;
}
}