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 editLink = async (id: number, data: Partial<CreateLinkRequest>) => {
62 const response = await api.patch<Link>(`/links/${id}`, data);
63 return response.data;
64};
65
66
67export const deleteLink = async (id: number) => {
68 await api.delete(`/links/${id}`);
69};
70
71export const getLinkClickStats = async (id: number) => {
72 try {
73 const response = await api.get<ClickStats[]>(`/links/${id}/clicks`);
74 return response.data;
75 } catch (error) {
76 console.error('Error fetching click stats:', error);
77 throw error;
78 }
79};
80
81export const getLinkSourceStats = async (id: number) => {
82 try {
83 const response = await api.get<SourceStats[]>(`/links/${id}/sources`);
84 return response.data;
85 } catch (error) {
86 console.error('Error fetching source stats:', error);
87 throw error;
88 }
89};
90
91
92export const checkFirstUser = async () => {
93 const response = await api.get<{ isFirstUser: boolean }>('/auth/check-first-user');
94 return response.data.isFirstUser;
95};
96
97export { api };