Skip to content

Commit

Permalink
Merge pull request #71 from MattCCC/fetchf-custom-fetcher
Browse files Browse the repository at this point in the history
Add custom fetcher to fetchf()
  • Loading branch information
MattCCC authored Oct 2, 2024
2 parents 0d58aa3 + 96168b3 commit 5cb99d8
Show file tree
Hide file tree
Showing 8 changed files with 245 additions and 186 deletions.
1 change: 0 additions & 1 deletion .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ node_modules
package
docs

CODE_OF_CONDUCT.md
SECURITY.md

*.tgz
Expand Down
36 changes: 36 additions & 0 deletions FUNDING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Funding for fetchff

fetchff is an open-source project aimed at simplifying and enhancing HTTP requests in JavaScript applications. As an open-source project, it thrives on community support and contributions. Your support helps ensure that fetchff remains sustainable and continues to grow. If you find fetchff useful and would like to support its ongoing development, here are a few ways you can help:

## Ways to Support

### 1. **GitHub Sponsorship**

You can sponsor the fetchff project directly on GitHub. Your contributions help cover development costs and allow us to invest more time into improving the library.

<i>[This option is currently unavailable]</i>

<!-- [Become a Sponsor on GitHub](https://github.com/sponsors) -->

### 2. **Patreon**

Consider supporting fetchff through Patreon. Your monthly contributions will provide us with the resources needed to maintain and enhance the project.

[Support Us on Patreon](https://www.patreon.com/mattccc)

### 3. **Contributions**

If financial support isn't feasible for you at the moment, there are other ways to contribute:

- **Report Issues**: Help us identify bugs or areas for improvement by reporting issues on GitHub.
- **Feature Requests**: Share your ideas for new features or enhancements.
- **Documentation**: Contribute to our documentation to help others understand and use fetchff more effectively.
- **Spread the Word**: Share fetchff with your colleagues and on social media. The more users we have, the more vibrant our community becomes!

## Thank You!

Your support, whether financial or in the form of contributions, helps ensure the longevity and success of fetchff. Together, we can make this project sustainable and even better!

---

For more information on how to contribute to fetchff, please refer to our [CONTRIBUTING.md](./CONTRIBUTING.md) file.
61 changes: 30 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,11 @@ const { data, error } = await api.getUser({
<summary><span style="cursor:pointer">Click to expand</span></summary>
<br>

All the Request Settings can be used directly in the function or in the `endpoints` property (on per-endpoint basis). There are also two extra global settings for `createApiFetcher()`:
All the Request Settings can be directly used in the function as global settings for all endpoints. They can be also used within the `endpoints` property (on per-endpoint basis). The exposed `endpoints` property is as follows:

| Name | Type | Default | Description |
| --------- | ----------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| endpoints | `object` | | List of your endpoints. Each endpoint accepts all the settings below. They can be set globally, per-endpoint or per-request. |
| fetcher | `FetcherInstance` | | A custom adapter (an instance / object) that exposes `create()` function so to create instance of API Fetcher. The `create()` should return `request()` function that would be used when making the requests. The native `fetch()` is used if the fetcher is not provided. |
- **`endpoints`**:
Type: `EndpointsConfig<EndpointsMethods>`
List of your endpoints. Each endpoint is an object that accepts all the Request Settings (see the Basic Settings below). The endpoints are required to be specified.

#### How It Works

Expand All @@ -206,7 +205,7 @@ import { createApiFetcher } from 'fetchff';
const api = createApiFetcher({
apiUrl: 'https://example.com/api',
endpoints: {
updateUserData: {
updateUser: {
url: '/update-user/:id',
method: 'POST',
},
Expand All @@ -215,7 +214,7 @@ const api = createApiFetcher({
});

// Using api.request to make a POST request
const { data, error } = await api.request('updateUserData', {
const { data, error } = await api.request('updateUser', {
body: {
name: 'John Doe', // Data Payload
},
Expand Down Expand Up @@ -279,7 +278,8 @@ You can also use all native `fetch()` settings.
| withCredentials | `boolean` | `false` | Indicates whether credentials (such as cookies) should be included with the request. |
| timeout | `number` | `30000` | You can set a request timeout for all requests or particular in milliseconds. |
| dedupeTime | `number` | `1000` | Time window, in milliseconds, during which identical requests are deduplicated (treated as single request). |
| logger | `object` | `null` | You can additionally specify logger object with your custom logger to automatically log the errors to the console. It should contain at least `error` and `warn` functions. |
| logger | `Logger` | `null` | You can additionally specify logger object with your custom logger to automatically log the errors to the console. It should contain at least `error` and `warn` functions. |
| fetcher | `FetcherInstance` | | A custom adapter (an instance / object) that exposes `create()` function so to create instance of API Fetcher. The `create()` should return `request()` function that would be used when making the requests. The native `fetch()` is used if the fetcher is not provided. |

## 🏷️ Headers

Expand All @@ -291,25 +291,6 @@ You can also use all native `fetch()` settings.

**Note:** Header keys are case-sensitive when specified in request objects. Ensure that the keys are provided in the correct case to avoid issues with header handling.

### How to Set Per-Request Headers

To set headers for a specific request, include the `headers` option in the request configuration. This option accepts an `object` where the keys are the header names and the values are the corresponding header values.

### Default Headers

The `fetchff` plugin automatically injects a set of default headers into every request. These default headers help ensure that requests are consistent and include necessary information for the server to process them correctly.

#### Default Headers Injected

- **`Content-Type`**: `application/json;charset=utf-8`
Specifies that the request body contains JSON data and sets the character encoding to UTF-8.

- **`Accept`**: `application/json, text/plain, */*`
Indicates the media types that the client is willing to receive from the server. This includes JSON, plain text, and any other types.

- **`Accept-Encoding`**: `gzip, deflate, br`
Specifies the content encoding that the client can understand, including gzip, deflate, and Brotli compression.

### Setting Headers Globally

You can set default headers that will be included in all requests made with a specific `createApiFetcher` instance. This is useful for setting common headers like authentication tokens or content types.
Expand Down Expand Up @@ -347,6 +328,19 @@ const { data } = await fetchf('https://api.example.com/endpoint', {
});
```

### Default Headers

The `fetchff` plugin automatically injects a set of default headers into every request. These default headers help ensure that requests are consistent and include necessary information for the server to process them correctly.

- **`Content-Type`**: `application/json;charset=utf-8`
Specifies that the request body contains JSON data and sets the character encoding to UTF-8.

- **`Accept`**: `application/json, text/plain, */*`
Indicates the media types that the client is willing to receive from the server. This includes JSON, plain text, and any other types.

- **`Accept-Encoding`**: `gzip, deflate, br`
Specifies the content encoding that the client can understand, including gzip, deflate, and Brotli compression.

</details>

## 🌀 Interceptors
Expand Down Expand Up @@ -852,6 +846,7 @@ For a complete list of types and their definitions, refer to the [request-handle
| **Unified API Client** | ✅ | -- | -- | -- | -- |
| **Smart Request Cache** | ✅ | -- | -- | -- | -- |
| **Automatic Request Deduplication** | ✅ | -- | -- | -- | -- |
| **Custom Fetching Adapter** | ✅ | -- | -- | -- | -- |
| **Built-in Error Handling** | ✅ | -- | ✅ | -- | -- |
| **Customizable Error Handling** | ✅ | -- | ✅ | ✅ | -- |
| **Retries with exponential backoff** | ✅ | -- | -- | -- | -- |
Expand Down Expand Up @@ -911,6 +906,10 @@ const api = createApiFetcher({
method: 'get', // Default request method.
params: {}, // Default params added to all requests.
data: {}, // Alias for 'body'. Default data passed to POST, PUT, DELETE and PATCH requests.
cacheTime: 300, // Cache is valid for 5 minutes
cacheKey: (config) => `${config.url}-${config.method}`, // Custom cache key based on URL and method
cacheBuster: (config) => config.method === 'POST', // Bust cache for POST requests
skipCache: (response, config) => response.status !== 200, // Skip caching on non-200 responses
onError(error) {
// Interceptor on error
console.error('Request failed', error);
Expand Down Expand Up @@ -1449,7 +1448,7 @@ fetchUserAndCreatePost(1, { title: 'New Post', content: 'This is a new post.' })
<details>
<summary><span style="cursor:pointer">Click to expand</span></summary>
<br>
You can implement a `useApi()` hook to handle the data fetching. Since this package has everything included, you don't really need anything more than a simple hook to utilize.<br><br>
You can implement a `useFetcher()` hook to handle the data fetching. Since this package has everything included, you don't really need anything more than a simple hook to utilize.<br><br>
Create `api.ts` file:
Expand All @@ -1467,10 +1466,10 @@ export const api = createApiFetcher({
});
```
Create `useApi.ts` file:
Create `useFetcher.ts` file:
```tsx
export const useApi = (apiFunction) => {
export const useFetcher = (apiFunction) => {
const [data, setData] = useState(null);
const [error] = useState(null);
const [isLoading, setLoading] = useState(true);
Expand Down Expand Up @@ -1505,7 +1504,7 @@ export const ProfileComponent = ({ id }) => {
data: profile,
error,
isLoading,
} = useApi(() => api.getProfile({ urlPathParams: { id } }));
} = useFetcher(() => api.getProfile({ urlPathParams: { id } }));
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
Expand Down
18 changes: 0 additions & 18 deletions src/.npmignore

This file was deleted.

Loading

0 comments on commit 5cb99d8

Please sign in to comment.