Skip to content

Commit

Permalink
Merge pull request #7 from romeopeter/feature/config
Browse files Browse the repository at this point in the history
Feature/config
  • Loading branch information
romeopeter authored Jan 6, 2025
2 parents e00760a + c61c29a commit a2be270
Show file tree
Hide file tree
Showing 26 changed files with 539 additions and 284 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
TODO.txt
node_modules
dist
dist
.vscode
222 changes: 152 additions & 70 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@

<br />

**Fetchfully** is an object-first and promise-based HTTP client for the browser . It wraps the JavaScript Fetch API with additional functionalities for efficiency and readability. Just supply the objects and that's it!
Javascript Fetch API with Power Pack ⚡️ <br/> **Fetchfully** wraps the JavaScript Fetch API with additional functionalities for ease and efficiency.

---

## Features

- **Object-First Data Fetching**: Pass data directly as objects, improving code clarity.
- **Object-First Data Fetching**: Supply all init config as object, improving code clarity.
- **In-Built Base Request Logic**: Automatically handles responses based on content type.
- **Parses Payload**: Automatically parses mutation request payload as JSON
- **Simple headers**: Simplifies working with request headers.
- **Simple Path and Query Parameters**: Automatically constructs and encode URL. Just supply the path and query values.
- **Customizable Settings**: Set timeouts and parameter delimiters for your specific needs.
- **Parses Payload**: Automatically parses mutation request payload as JSON.
- **Simple Path and Query Parameters**: Pass path and query parameter as properties to Fetchfully init config.
- **Global config and Instances**: Create different instances that use a global config or override it with instance-specific config.
- **Consumable request method**: Use consumable methods for ergonomic common HTTP requests.

---

Expand All @@ -24,121 +23,124 @@
Install the package using npm or yarn:

```bash
npm install fetch-plus
npm install fetchfully

# or

yarn add fetch-plus
yarn add fetchfully
```

## How To Use

### Basic request
### Basic request with default instance

##### 1. Normal request

```javascript
import fetcher from "fetch-plus";

// 1. Original
await fetcher({ url: "https://api.example.com/posts" });
```

/** 2. With path strings
*
* URL results in: https://api.example.com/posts/1/commments
*/
##### 2. With path string

```javascript
await fetcher({
url: "https://api.example.com",
path: "/posts1/comments",
});

/** 3. With array of path segments
*
* URL results in: https://api.example.com/posts/1/commments
*/
// URL results in: https://api.example.com/posts/1/commments
```

##### 3. With array of path segments

```javascript
await fetcher({
url: "https://api.example.com",
path: ["posts", "1", "comments"],
});

/**
* 4. With query parameters
*
* URL results in: https://api.example.com/comments?page=1&limit=10&colors=red,blue&size=large
*/
// URL results in: https://api.example.com/posts/1/commments
```

##### 4. With query parameters

```javascript
const query = {
page: 1,
limit: 10,
colors: ["red", "blue"],
size: "large",
};
const queryArrayFormat = "comma";

await fetcher({
url: "https://api.example.com",
query,
customOption: { queryArrayFormat },
queryArrayFormat = "comma",
});

// URL results in: https://api.example.com/comments?page=1&limit=10&colors=red,blue&size=large
```

### Mutation request (POST, PUT, PATCH and DELETE)

##### 1. POST request

```javascript
/**
* 1. POST request
*
*/
await fetcher({
url: "https://api.example.com/post",
method: "POST",
headers: {
contentType: "json",
"Content-Type": "application/json",
},
body: {
title: "foo",
body: "bar",
userId: 1,
},
});
```

/**
* 2. PUT request
*
*/
##### 2. PUT request

```javascript
await fetcher({
url: "https://api.example.com/post",
method: "PUT",
headers: {
contentType: "json",
"Authorization": "Bearer token",
"Content-Type": "application/json",
},
body: {
id: 1,
title: "foo",
body: "bar",
userId: 1,
},
}
});
```

##### 3. PATCH request

/**
* 3. PATCH request
*
*/
```javascript
await fetcher({
url: "https://api.example.com/post/1",
method: "PATCH",
headers: {
contentType: "json",
},
body: {
title: "bar",
"Content-Type": "application/json",
},
body: {title: "bar"}
});
```

/**
* 4. Delete request
*
*/
##### 4. Delete request

```javascript
await fetcher({ url: "https://api.example.com/post/1", method: "DELETE" });
```

## Configuration
## Fetchfully Configuration

When initializing `Fetchfully`, you can pass the following options:

Expand All @@ -155,34 +157,114 @@ When initializing `Fetchfully`, you can pass the following options:
| `keepalive` | `boolean` | Persist requests request connection. |
| `mode` | `"same-origin" \| "cors" \| "no-cors"` | Request CORS mode. |
| `customOptions` | `CustomOptionsType` | Request options not explicitly available in the Fetch API. |
| `timeout` | `number` | Time as milliseconds before terminating request. |
| `queryArrayFormat` | `"brackets" \| "comma" \| "repeat" \| "none"` | Indicates how parameter array should be formatted. |

### Custom options

| Option | Type | Description |
| --------------------------- | --------------------------------------------------------------------- | -------------------------------------------------- |
| `responseType` | `"text" \| "json" \| "formData" \| "blob" \| "arrayBuffer" \| "body"` | Request response type. Default is `json`. |
| `timeout` | `number` | Time as milliseconds before terminating request. |
| `queryParamsArrayFormatter` | `"brackets" \| "comma" \| "repeat" \| "none"` | Indicates how parameter array should be formatted. |
## Fetchfully Instance

Example:
Create new instance of Fetchfully with independent custom configurations with the `fetcher.create()` factory method.

```javascript
import fetcher from "fetchfully";

// api/auth
const authAPI = fetchfully.create({
baseUrl: "https://api.example.com/auth",
timeout: 5000,
});

// api/users
const userAPI = fetcher.create({
baseURL: "https://api.example.com/user",
headers: {
"Cache-Control": "no-cache",
},
});

// api/analytics
const analyticsAPI = fetcher.create({
baseURL: "https://api.example.com/analytics",
timeout: 5000
});
```

// Set request timeout and response type
const options = {
responseType: 'text',
timeout: 5000, // 5 seconds
queryArrayFormat: "brackets"
}
## Fetchfully Default Config

const fetch await fetcher({
url: "https://jsonplaceholder.typicode.com/posts",
...,
...,
customOptions: options
})
Create a global config that will persist across all requests

##### Global default

```javascript
import fetcher from "fetchfully";

fetcher.defaults.baseUrl = "https://api.example.com";
fetcher.defaults.timeout = 5000;
```

##### Custom Instance Default

```javascript
const customAPI = fetcher.create({
headers: {
"Authorization": "Bearer token", // Instance-specific authorization header
},
timeout: 2500, // Instance-specific base URL overridden by global config base URL.
});

// Use custom instance
// URL results in: 'https://api.example.com/users?active=true
await customAPI({
path: "/users",
query: { active: true },
});
```
Configs made in a created instance take precedence over those in global default config. For instance, the `2500` (2.5 seconds) set above is specific to that instance and overrides the global default timeout (if/when set).

## Consumable methods for ergonomic requests.
Use these ergonomic methods for common HTTP request.

##### Set base URL
```javascript
import fetcher from "fetchfully";

fetcher.defaults.baseUrl = "https://api.example.com";
```

##### GET request
```javascript
// Using convenience methods
await fetcher.get('users'); // GET request to /users
await fetcher.get('users', { active: true }); // GET with query params
```

##### POST request
```javascript
await fetcher.post('users', {
name: 'John',
email: 'john@example.com'
});
```

##### PUT request
```javascript
await fetcher.put('users/123', {
name: 'John Updated'
});
```

##### PATCH request
```javascript
await fetcher.patch('users/123', {
status: 'active'
});
```

##### PATCH request
```javascript
await fetcher.delete('users/123');
```

## License

This project is licensed under the MIT License.
This project is licensed under the MIT.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "fetchfully",
"version": "1.0.0",
"description": "Object-first and promise based Fetch API wrapper for convenient HTTP requests. Only specify what you need!",
"version": "1.1.0",
"description": "JavaScript Fetch API with power pack ⚡️ It wraps the JavaScript Fetch API with additional functionalities for efficiency.",
"main": "./dist/fetchfully.cjs",
"module": "./dist/fetchfully.mjs",
"types": "./dist/index.d.ts",
Expand Down
16 changes: 16 additions & 0 deletions src/consumable-methods/delete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { FetchfullyInstance } from "../types/config";

/* ------------------------------------------------- */

export function createDeleteMethod(instance: FetchfullyInstance) {
return async function del<T = any>(
path: string,
query?: Record<string, any>
): Promise<T> {
return instance({
path,
method: "DELETE",
query,
});
};
}
16 changes: 16 additions & 0 deletions src/consumable-methods/get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { FetchfullyInstance } from "../types/config";

/* ------------------------------------------------- */

export function createGetMethod(instance: FetchfullyInstance) {
return async function get<T = any>(
path: string,
query?: Record<string, any>
): Promise<T> {
return instance({
path,
method: "GET",
query,
});
};
}
Loading

0 comments on commit a2be270

Please sign in to comment.