# Fetch Requests (reuseable layer for API client services)


> Service/apiClient.js (at the same level as src folder)
```js
class ApiClient {
  constructor() {
    this.baseURL = 'http://localhost:3000/api/v1';
    this.defaultHeaders = {
      'Content-Type': 'application/json',
      Accept: 'application/json',
    };
  }

  async customFetch(endpoint, options = {}) {
    try {
      const url = `${this.baseURL}${endpoint}`;
      const response = await fetch(url, {
        ...options,
        headers: { ...this.defaultHeaders, ...options.headers },
        credentials: 'include',  // Send Cookies
        // 'include' on Same-origin + cross-origin 
        // default 'same-origin' and 
        // use 'omit' for public apis
      });
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      return await response.json();
    } catch (e) {
      console.log('API Error:', e);
    }
  }

  signup(name, email, password) {
    return this.customFetch('/user/signup', {
      method: 'POST',
      body: JSON.stringify({ name, email, password }),
    });
  }
}
const apiClient = new ApiClient();
export default apiClient;

```

## uses of apiClient
```js
// Import at the top
import apiClient from './apiClient';

// GET req
try {
  const users = await apiClient.get('/users');
  console.log(users);
} catch (err) {
  console.error(err);
}

// POST req
const data = {
  email: 'test@test.com',
  password: '123456',
};
await apiClient.post('/login', data);

//PUT Req
await apiClient.put('/users/1', {
  name: 'John',
});

//Delete req
await apiClient.delete('/users/1');

// Cutom header
await apiClient.get('/users', {
  headers: {
    'x-custom-header': 'hello',
  },
});

// Query Params
const role = 'admin';
await apiClient.get(`/users?role=${role}`);

```
```JS
// React Example
import { useEffect, useState } from 'react';
import apiClient from './apiClient';

function Users() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    const fetchUsers = async () => {
      try {
        const data = await apiClient.get('/users');
        setUsers(data);
      } catch (err) {
        console.error(err);
      }
    };

    fetchUsers();
  }, []);

  return (
    <div>
      {users.map(u => (
        <p key={u.id}>{u.name}</p>
      ))}
    </div>
  );
}
```


## Steps on Form Submission  
- Prevent default behavior of form.  
- Show loading state.  
- Call apiClient.signup(...) and wait for response.  
- Handle the response (e.g., redirect on success).  
- Catch and log any errors.  
```js
const handleSubmit = async (e) => {
  e.preventDefault();
  if (!name || !email || !password) return setError('All fields required');

  setLoading(true);
  setError('');
  try {
    const data = await apiClient.signup(name, email, password);
    if (data?.success) navigate('/login');
    else setError(data?.message || 'Signup failed');
  } catch (e) {
    setError('Error occurred');
  } finally {
    setLoading(false);
  }
};
```
```html
{error && <p>{error}</p>}
<form onSubmit={handleSubmit}>
  <input value={name} onChange={(e) => setName(e.target.value)} />
  <input value={email} onChange={(e) => setEmail(e.target.value)} />
  <input value={password} onChange={(e) => setPassword(e.target.value)} />
  <button type="submit">{loading ? 'Signing up...' : 'Signup'}</button>
</form>
```


