feat(docs): Enhance documentation and tests with modern API usage examples and migration guide
This commit is contained in:
parent
96820090d4
commit
b8f545cdd5
@ -1,5 +1,14 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-04-03 - 2.1.0 - feat(docs)
|
||||||
|
Enhance documentation and tests with modern API usage examples and migration guide
|
||||||
|
|
||||||
|
- Updated README to include detailed examples for the modern fluent API, covering GET, POST, headers, query, timeout, retries, and pagination
|
||||||
|
- Added a migration guide comparing the legacy API and modern API usage
|
||||||
|
- Improved installation instructions with npm, pnpm, and yarn examples
|
||||||
|
- Added and updated test files for both legacy and modern API functionalities
|
||||||
|
- Minor formatting improvements in the code and documentation examples
|
||||||
|
|
||||||
## 2024-11-06 - 2.0.23 - fix(core)
|
## 2024-11-06 - 2.0.23 - fix(core)
|
||||||
Enhance type safety for response in binary requests
|
Enhance type safety for response in binary requests
|
||||||
|
|
||||||
|
221
readme.md
221
readme.md
@ -1,17 +1,29 @@
|
|||||||
# @push.rocks/smartrequest
|
# @push.rocks/smartrequest
|
||||||
A module providing a drop-in replacement for the deprecated Request library, focusing on modern HTTP/HTTPS requests with support for form data, file uploads, JSON, binary data, and streams.
|
A module providing a drop-in replacement for the deprecated Request library, focusing on modern HTTP/HTTPS requests with support for form data, file uploads, JSON, binary data, and streams. The library offers both a legacy API and a modern fluent API for maximum flexibility.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
To install `@push.rocks/smartrequest`, use the following npm command:
|
To install `@push.rocks/smartrequest`, use one of the following commands:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Using npm
|
||||||
npm install @push.rocks/smartrequest --save
|
npm install @push.rocks/smartrequest --save
|
||||||
|
|
||||||
|
# Using pnpm
|
||||||
|
pnpm add @push.rocks/smartrequest
|
||||||
|
|
||||||
|
# Using yarn
|
||||||
|
yarn add @push.rocks/smartrequest
|
||||||
```
|
```
|
||||||
|
|
||||||
This command will add `@push.rocks/smartrequest` to your project's dependencies.
|
This will add `@push.rocks/smartrequest` to your project's dependencies.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
`@push.rocks/smartrequest` is designed as a versatile, modern HTTP client library for making HTTP/HTTPS requests. It supports a range of features, including handling form data, file uploads, JSON requests, binary data, streaming, and much more, all within a modern, promise-based API.
|
`@push.rocks/smartrequest` is designed as a versatile, modern HTTP client library for making HTTP/HTTPS requests. It supports a range of features, including handling form data, file uploads, JSON requests, binary data, streaming, pagination, and much more, all within a modern, promise-based API.
|
||||||
|
|
||||||
|
The library provides two distinct APIs:
|
||||||
|
|
||||||
|
1. **Legacy API** - Simple function-based API for quick and straightforward HTTP requests
|
||||||
|
2. **Modern Fluent API** - A chainable, builder-style API for more complex scenarios and better TypeScript integration
|
||||||
|
|
||||||
Below we will cover key usage scenarios of `@push.rocks/smartrequest`, showcasing its capabilities and providing you with a solid starting point to integrate it into your projects.
|
Below we will cover key usage scenarios of `@push.rocks/smartrequest`, showcasing its capabilities and providing you with a solid starting point to integrate it into your projects.
|
||||||
|
|
||||||
@ -117,7 +129,206 @@ customRequestExample();
|
|||||||
|
|
||||||
`request` is the underlying function that powers the simpler `getJson`, `postJson`, etc., and provides you with full control over the HTTP request.
|
`request` is the underlying function that powers the simpler `getJson`, `postJson`, etc., and provides you with full control over the HTTP request.
|
||||||
|
|
||||||
Through its comprehensive set of features tailored for modern web development, `@push.rocks/smartrequest` aims to provide developers with a powerful tool for handling HTTP/HTTPS requests efficiently. Whether it's a simple API call, handling form data, or processing streams, `@push.rocks/smartrequest` delivers a robust, type-safe solution to fit your project's requirements.
|
## Modern Fluent API
|
||||||
|
|
||||||
|
In addition to the legacy API shown above, `@push.rocks/smartrequest` provides a modern, fluent API that offers a more chainable and TypeScript-friendly approach to making HTTP requests.
|
||||||
|
|
||||||
|
### Basic Usage with the Modern API
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { SmartRequestClient } from '@push.rocks/smartrequest';
|
||||||
|
|
||||||
|
// Simple GET request
|
||||||
|
async function fetchUserData(userId: number) {
|
||||||
|
const response = await SmartRequestClient.create()
|
||||||
|
.url(`https://jsonplaceholder.typicode.com/users/${userId}`)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
console.log(response.body); // The JSON response
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST request with JSON body
|
||||||
|
async function createPost(title: string, body: string, userId: number) {
|
||||||
|
const response = await SmartRequestClient.create()
|
||||||
|
.url('https://jsonplaceholder.typicode.com/posts')
|
||||||
|
.json({ title, body, userId })
|
||||||
|
.post();
|
||||||
|
|
||||||
|
console.log(response.body); // The created post
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Setting Headers and Query Parameters
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { SmartRequestClient } from '@push.rocks/smartrequest';
|
||||||
|
|
||||||
|
async function searchRepositories(query: string, perPage: number = 10) {
|
||||||
|
const response = await SmartRequestClient.create()
|
||||||
|
.url('https://api.github.com/search/repositories')
|
||||||
|
.header('Accept', 'application/vnd.github.v3+json')
|
||||||
|
.query({
|
||||||
|
q: query,
|
||||||
|
per_page: perPage.toString()
|
||||||
|
})
|
||||||
|
.get();
|
||||||
|
|
||||||
|
return response.body.items;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Handling Timeouts and Retries
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { SmartRequestClient } from '@push.rocks/smartrequest';
|
||||||
|
|
||||||
|
async function fetchWithRetry(url: string) {
|
||||||
|
const response = await SmartRequestClient.create()
|
||||||
|
.url(url)
|
||||||
|
.timeout(5000) // 5 seconds timeout
|
||||||
|
.retry(3) // Retry up to 3 times on failure
|
||||||
|
.get();
|
||||||
|
|
||||||
|
return response.body;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Working with Different Response Types
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { SmartRequestClient } from '@push.rocks/smartrequest';
|
||||||
|
|
||||||
|
// Binary data
|
||||||
|
async function downloadImage(url: string) {
|
||||||
|
const response = await SmartRequestClient.create()
|
||||||
|
.url(url)
|
||||||
|
.responseType('binary')
|
||||||
|
.get();
|
||||||
|
|
||||||
|
// response.body is a Buffer
|
||||||
|
return response.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Streaming response
|
||||||
|
async function streamLargeFile(url: string) {
|
||||||
|
const response = await SmartRequestClient.create()
|
||||||
|
.url(url)
|
||||||
|
.responseType('stream')
|
||||||
|
.get();
|
||||||
|
|
||||||
|
// response is a stream
|
||||||
|
response.on('data', (chunk) => {
|
||||||
|
console.log(`Received ${chunk.length} bytes of data`);
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
response.on('end', resolve);
|
||||||
|
response.on('error', reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pagination Support
|
||||||
|
|
||||||
|
The modern API includes built-in support for various pagination strategies:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { SmartRequestClient, PaginationStrategy } from '@push.rocks/smartrequest';
|
||||||
|
|
||||||
|
// Offset-based pagination (page & limit)
|
||||||
|
async function fetchAllUsers() {
|
||||||
|
const client = SmartRequestClient.create()
|
||||||
|
.url('https://api.example.com/users')
|
||||||
|
.withOffsetPagination({
|
||||||
|
pageParam: 'page',
|
||||||
|
limitParam: 'limit',
|
||||||
|
startPage: 1,
|
||||||
|
pageSize: 20,
|
||||||
|
totalPath: 'meta.total'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get first page with pagination info
|
||||||
|
const firstPage = await client.getPaginated();
|
||||||
|
console.log(`Found ${firstPage.items.length} users on first page`);
|
||||||
|
console.log(`Has more pages: ${firstPage.hasNextPage}`);
|
||||||
|
|
||||||
|
if (firstPage.hasNextPage) {
|
||||||
|
// Get next page
|
||||||
|
const secondPage = await firstPage.getNextPage();
|
||||||
|
console.log(`Found ${secondPage.items.length} more users`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Or get all pages at once (use with caution for large datasets)
|
||||||
|
const allUsers = await client.getAllPages();
|
||||||
|
console.log(`Retrieved ${allUsers.length} users in total`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cursor-based pagination
|
||||||
|
async function fetchAllPosts() {
|
||||||
|
const allPosts = await SmartRequestClient.create()
|
||||||
|
.url('https://api.example.com/posts')
|
||||||
|
.withCursorPagination({
|
||||||
|
cursorParam: 'cursor',
|
||||||
|
cursorPath: 'meta.nextCursor',
|
||||||
|
hasMorePath: 'meta.hasMore'
|
||||||
|
})
|
||||||
|
.getAllPages();
|
||||||
|
|
||||||
|
console.log(`Retrieved ${allPosts.length} posts in total`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Link header-based pagination (GitHub API style)
|
||||||
|
async function fetchAllIssues(repo: string) {
|
||||||
|
const paginatedResponse = await SmartRequestClient.create()
|
||||||
|
.url(`https://api.github.com/repos/${repo}/issues`)
|
||||||
|
.header('Accept', 'application/vnd.github.v3+json')
|
||||||
|
.withLinkPagination()
|
||||||
|
.getPaginated();
|
||||||
|
|
||||||
|
return paginatedResponse.getAllPages();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Convenience Factory Functions
|
||||||
|
|
||||||
|
The library provides several factory functions for common use cases:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { createJsonClient, createBinaryClient, createStreamClient } from '@push.rocks/smartrequest';
|
||||||
|
|
||||||
|
// Pre-configured for JSON requests
|
||||||
|
const jsonClient = createJsonClient()
|
||||||
|
.url('https://api.example.com/data')
|
||||||
|
.get();
|
||||||
|
|
||||||
|
// Pre-configured for binary data
|
||||||
|
const binaryClient = createBinaryClient()
|
||||||
|
.url('https://example.com/image.jpg')
|
||||||
|
.get();
|
||||||
|
|
||||||
|
// Pre-configured for streaming
|
||||||
|
const streamClient = createStreamClient()
|
||||||
|
.url('https://example.com/large-file')
|
||||||
|
.get();
|
||||||
|
```
|
||||||
|
|
||||||
|
Through its comprehensive set of features tailored for modern web development, `@push.rocks/smartrequest` aims to provide developers with a powerful tool for handling HTTP/HTTPS requests efficiently. Whether it's a simple API call, handling form data, processing streams, or working with paginated APIs, `@push.rocks/smartrequest` delivers a robust, type-safe solution to fit your project's requirements.
|
||||||
|
|
||||||
|
## Migration Guide: Legacy API to Modern API
|
||||||
|
|
||||||
|
If you're currently using the legacy API and want to migrate to the modern fluent API, here's a quick reference guide:
|
||||||
|
|
||||||
|
| Legacy API | Modern API |
|
||||||
|
|------------|------------|
|
||||||
|
| `getJson(url)` | `SmartRequestClient.create().url(url).get()` |
|
||||||
|
| `postJson(url, { requestBody: data })` | `SmartRequestClient.create().url(url).json(data).post()` |
|
||||||
|
| `putJson(url, { requestBody: data })` | `SmartRequestClient.create().url(url).json(data).put()` |
|
||||||
|
| `delJson(url)` | `SmartRequestClient.create().url(url).delete()` |
|
||||||
|
| `postFormData(url, {}, fields)` | `SmartRequestClient.create().url(url).formData(fields).post()` |
|
||||||
|
| `getStream(url)` | `SmartRequestClient.create().url(url).responseType('stream').get()` |
|
||||||
|
| `request(url, options)` | `SmartRequestClient.create().url(url).[...configure options...].get()` |
|
||||||
|
|
||||||
|
The modern API provides more flexibility and better TypeScript integration, making it the recommended approach for new projects.
|
||||||
|
|
||||||
## License and Legal Information
|
## License and Legal Information
|
||||||
|
|
||||||
|
@ -14,10 +14,12 @@ tap.test('should request a JSON document over https', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
tap.test('should post a JSON document over http', async () => {
|
tap.test('should post a JSON document over http', async () => {
|
||||||
await expectAsync(smartrequest.postJson('http://md5.jsontest.com/?text=example_text'))
|
const testData = { text: 'example_text' };
|
||||||
|
await expectAsync(smartrequest.postJson('https://httpbin.org/post', { requestBody: testData }))
|
||||||
.property('body')
|
.property('body')
|
||||||
.property('md5')
|
.property('json')
|
||||||
.toEqual('fa4c6baa0812e5b5c80ed8885e55a8a6');
|
.property('text')
|
||||||
|
.toEqual('example_text');
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('should safe get stuff', async () => {
|
tap.test('should safe get stuff', async () => {
|
86
test/test.modern.ts
Normal file
86
test/test.modern.ts
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import { tap, expect } from '@pushrocks/tapbundle';
|
||||||
|
|
||||||
|
import { SmartRequestClient } from '../ts/modern/index.js';
|
||||||
|
|
||||||
|
tap.test('modern: should request a html document over https', async () => {
|
||||||
|
const response = await SmartRequestClient.create()
|
||||||
|
.url('https://encrypted.google.com/')
|
||||||
|
.get();
|
||||||
|
|
||||||
|
expect(response).toHaveProperty('body');
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('modern: should request a JSON document over https', async () => {
|
||||||
|
const response = await SmartRequestClient.create()
|
||||||
|
.url('https://jsonplaceholder.typicode.com/posts/1')
|
||||||
|
.get();
|
||||||
|
|
||||||
|
expect(response.body).toHaveProperty('id');
|
||||||
|
expect(response.body.id).toEqual(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('modern: should post a JSON document over http', async () => {
|
||||||
|
const testData = { text: 'example_text' };
|
||||||
|
const response = await SmartRequestClient.create()
|
||||||
|
.url('https://httpbin.org/post')
|
||||||
|
.json(testData)
|
||||||
|
.post();
|
||||||
|
|
||||||
|
expect(response.body).toHaveProperty('json');
|
||||||
|
expect(response.body.json).toHaveProperty('text');
|
||||||
|
expect(response.body.json.text).toEqual('example_text');
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('modern: should set headers correctly', async () => {
|
||||||
|
const customHeader = 'X-Custom-Header';
|
||||||
|
const headerValue = 'test-value';
|
||||||
|
|
||||||
|
const response = await SmartRequestClient.create()
|
||||||
|
.url('https://httpbin.org/headers')
|
||||||
|
.header(customHeader, headerValue)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
|
||||||
|
expect(response.body).toHaveProperty('headers');
|
||||||
|
|
||||||
|
// Check if the header exists (case-sensitive)
|
||||||
|
expect(response.body.headers).toHaveProperty(customHeader);
|
||||||
|
expect(response.body.headers[customHeader]).toEqual(headerValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('modern: should handle query parameters', async () => {
|
||||||
|
const params = { param1: 'value1', param2: 'value2' };
|
||||||
|
|
||||||
|
const response = await SmartRequestClient.create()
|
||||||
|
.url('https://httpbin.org/get')
|
||||||
|
.query(params)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
expect(response.body).toHaveProperty('args');
|
||||||
|
expect(response.body.args).toHaveProperty('param1');
|
||||||
|
expect(response.body.args.param1).toEqual('value1');
|
||||||
|
expect(response.body.args).toHaveProperty('param2');
|
||||||
|
expect(response.body.args.param2).toEqual('value2');
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('modern: should handle timeout configuration', async () => {
|
||||||
|
// This test just verifies that the timeout method doesn't throw
|
||||||
|
const client = SmartRequestClient.create()
|
||||||
|
.url('https://httpbin.org/get')
|
||||||
|
.timeout(5000);
|
||||||
|
|
||||||
|
const response = await client.get();
|
||||||
|
expect(response).toHaveProperty('body');
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('modern: should handle retry configuration', async () => {
|
||||||
|
// This test just verifies that the retry method doesn't throw
|
||||||
|
const client = SmartRequestClient.create()
|
||||||
|
.url('https://httpbin.org/get')
|
||||||
|
.retry(1);
|
||||||
|
|
||||||
|
const response = await client.get();
|
||||||
|
expect(response).toHaveProperty('body');
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.start();
|
@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@push.rocks/smartrequest',
|
name: '@push.rocks/smartrequest',
|
||||||
version: '2.0.23',
|
version: '2.1.0',
|
||||||
description: 'A module for modern HTTP/HTTPS requests with support for form data, file uploads, JSON, binary data, streams, and more.'
|
description: 'A module for modern HTTP/HTTPS requests with support for form data, file uploads, JSON, binary data, streams, and more.'
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,9 @@ export function createPaginatedResponse<T>(
|
|||||||
|
|
||||||
case PaginationStrategy.LINK_HEADER: {
|
case PaginationStrategy.LINK_HEADER: {
|
||||||
const linkHeader = response.headers['link'] || '';
|
const linkHeader = response.headers['link'] || '';
|
||||||
const links = parseLinkHeader(linkHeader);
|
// Handle both string and string[] types for the link header
|
||||||
|
const headerValue = Array.isArray(linkHeader) ? linkHeader[0] : linkHeader;
|
||||||
|
const links = parseLinkHeader(headerValue);
|
||||||
|
|
||||||
hasNextPage = !!links.next;
|
hasNextPage = !!links.next;
|
||||||
|
|
||||||
|
@ -2,14 +2,14 @@ import { type ISmartRequestOptions } from '../legacy/smartrequest.interfaces.js'
|
|||||||
import { request, type IExtendedIncomingMessage } from '../legacy/smartrequest.request.js';
|
import { request, type IExtendedIncomingMessage } from '../legacy/smartrequest.request.js';
|
||||||
import * as plugins from '../legacy/smartrequest.plugins.js';
|
import * as plugins from '../legacy/smartrequest.plugins.js';
|
||||||
|
|
||||||
import type { HttpMethod, ResponseType, RetryConfig, TimeoutConfig, FormField } from './types/common.js';
|
import type { HttpMethod, ResponseType, FormField } from './types/common.js';
|
||||||
import type {
|
import {
|
||||||
TPaginationConfig,
|
type TPaginationConfig,
|
||||||
PaginationStrategy,
|
PaginationStrategy,
|
||||||
OffsetPaginationConfig,
|
type OffsetPaginationConfig,
|
||||||
CursorPaginationConfig,
|
type CursorPaginationConfig,
|
||||||
CustomPaginationConfig,
|
type CustomPaginationConfig,
|
||||||
TPaginatedResponse
|
type TPaginatedResponse
|
||||||
} from './types/pagination.js';
|
} from './types/pagination.js';
|
||||||
import { createPaginatedResponse } from './features/pagination.js';
|
import { createPaginatedResponse } from './features/pagination.js';
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user