A very performant and light (2mb in memory) link shortener and tracker. Written in Rust and React and uses Postgres/SQLite.
1import axios from 'axios';
2import { CreateLinkRequest, Link, AuthResponse, ClickStats, SourceStats } from '../types/api';
3
4// Create axios instance with default config
5const api = axios.create({
6 baseURL: '/api',
7});
8
9// Add a request interceptor to add the auth token to all requests
10api.interceptors.request.use((config) => {
11 const token = localStorage.getItem('token');
12 if (token) {
13 config.headers.Authorization = `Bearer ${token}`;
14 }
15 return config;
16});
17
18api.interceptors.response.use(
19 (response) => response,
20 (error) => {
21 if (error.response?.status === 401) {
22 localStorage.removeItem('token');
23 localStorage.removeItem('user');
24
25 window.dispatchEvent(new Event('unauthorized'));
26 }
27 return Promise.reject(error);
28 }
29);
30
31
32// Auth endpoints
33export const login = async (email: string, password: string) => {
34 const response = await api.post<AuthResponse>('/auth/login', {
35 email,
36 password,
37 });
38 return response.data;
39};
40
41export const register = async (email: string, password: string, adminToken: string) => {
42 const response = await api.post<AuthResponse>('/auth/register', {
43 email,
44 password,
45 admin_token: adminToken,
46 });
47 return response.data;
48};
49
50// Protected endpoints
51export const createShortLink = async (data: CreateLinkRequest) => {
52 const response = await api.post<Link>('/shorten', data);
53 return response.data;
54};
55
56export const getAllLinks = async () => {
57 const response = await api.get<Link[]>('/links');
58 return response.data;
59};
60
61export const deleteLink = async (id: number) => {
62 await api.delete(`/links/${id}`);
63};
64
65export const getLinkClickStats = async (id: number) => {
66 try {
67 const response = await api.get<ClickStats[]>(`/links/${id}/clicks`);
68 return response.data;
69 } catch (error) {
70 console.error('Error fetching click stats:', error);
71 throw error;
72 }
73};
74
75export const getLinkSourceStats = async (id: number) => {
76 try {
77 const response = await api.get<SourceStats[]>(`/links/${id}/sources`);
78 return response.data;
79 } catch (error) {
80 console.error('Error fetching source stats:', error);
81 throw error;
82 }
83};
84
85
86export const checkFirstUser = async () => {
87 const response = await api.get<{ isFirstUser: boolean }>('/auth/check-first-user');
88 return response.data.isFirstUser;
89};
90
91export { api };