Files
sigpro/docs/api/req.md
natxocc f4654a938a
All checks were successful
Deploy Docs to Synology / deploy (push) Successful in 3s
Update docs
2026-04-25 20:28:38 +02:00

183 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# HTTP Requests: `req( )`
The `req` function creates a **reactive HTTP request controller**. It returns signals for `loading`, `error`, and `data`, plus a `run` method to execute the request and an `abort` method to cancel it. All signals update automatically as the request progresses.
## Function Signature
```typescript
req(config: {
url: string;
method?: string; // default: 'GET'
headers?: Record<string, string>;
}): {
run: (body?: any) => Promise<any>;
abort: () => void;
loading: Signal<boolean>;
error: Signal<string | null>;
data: Signal<any | null>;
}
```
| Parameter | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **`url`** | `string` | Yes | The endpoint to call. |
| **`method`** | `string` | No | HTTP method (`'GET'`, `'POST'`, etc.). Default `'GET'`. |
| **`headers`** | `object` | No | Custom headers (will be merged with defaults). |
**Returns:** A controller object with reactive signals and methods.
---
## Usage Patterns
### 1. Basic GET Request
```javascript
const users = req({ url: '/api/users' });
// Start the request
users.run().catch(console.error);
// React to the response
watch(() => {
if (users.loading()) console.log('Loading...');
if (users.error()) console.error(users.error());
if (users.data()) console.log('Data:', users.data());
});
```
### 2. POST Request with Body
```javascript
const createUser = req({ url: '/api/users', method: 'POST' });
const handleSubmit = async (formData) => {
try {
await createUser.run(formData);
alert('User created!');
} catch (err) {
// Error already in createUser.error()
}
};
```
### 3. Aborting a Request
```javascript
const search = req({ url: '/api/search' });
// Abort if the user types again quickly
let timeout;
input({ onInput: (e) => {
clearTimeout(timeout);
search.abort(); // cancel previous in-flight request
timeout = setTimeout(() => search.run({ q: e.target.value }), 300);
}});
```
### 4. Reactive UI with Signals
```javascript
const profile = req({ url: '/api/me' });
const App = () =>
div([
when(() => profile.loading(),
() => div("Loading...")
),
when(() => profile.error(),
() => div("Error: " + profile.error())
),
when(() => profile.data(),
() => div([
h2(profile.data().name),
p(profile.data().email)
])
)
]);
profile.run();
mount(App, '#app');
```
---
## Request Lifecycle
When you call `run(body?)`:
1. Any previous request is **aborted** automatically.
2. `loading` becomes `true`.
3. `error` is cleared.
4. A 10second timeout is set (autoabort).
5. The request is sent using `fetch`.
6. On success: `data` is set with the parsed JSON, `loading` becomes `false`.
7. On error: `error` is set with the message, `data` is cleared, `loading` becomes `false`.
> **Important:** The response body is parsed as JSON. If the response is not OK or the JSON parsing fails, `error` is set and the promise rejects.
---
## Automatic Headers
- If `body` is a plain object or array, the request automatically includes `Content-Type: application/json` (unless you override it in `headers`).
- If `body` is a `FormData` instance, the `Content-Type` is not set (browser will set it automatically with the correct boundary).
- Other headers can be added via the `headers` option.
```javascript
const upload = req({
url: '/upload',
method: 'POST',
headers: { 'X-Custom': 'value' }
});
const formData = new FormData();
formData.append('file', fileInput.files[0]);
upload.run(formData);
```
---
## Error Handling
- Network errors, timeouts, and HTTP error statuses (4xx, 5xx) all set `error` and cause the promise to reject.
- The `error` signal contains a humanreadable message.
- Abort errors (calling `abort()` or timeout) are **silent** they do not set `error` or reject the promise?
Actually, according to the source: if `e.name === 'AbortError'`, it does **not** call `error(e.message)`, but the promise still rejects with the AbortError. You can handle it with `.catch()` if needed.
---
## Complete Example
```javascript
const api = req({ url: 'https://jsonplaceholder.typicode.com/posts/1' });
const App = () =>
div({ class: "demo" }, [
when(() => api.loading(), () => p("⏳ Loading...")),
when(() => api.error(), () => p("❌ " + api.error())),
when(() => api.data(), () => div([
h2(api.data().title),
p(api.data().body)
])),
button({
onClick: () => api.run(),
disabled: () => api.loading()
}, "Fetch")
]);
mount(App, '#app');
```
---
## Summary
| Member | Type | Description |
| :--- | :--- | :--- |
| `run(body?)` | `(any) => Promise` | Starts the request. Returns a promise. |
| `abort()` | `() => void` | Cancels the current request. |
| `loading` | `Signal<boolean>` | `true` while request is in flight. |
| `error` | `Signal<string\|null>` | Contains an error message, or `null`. |
| `data` | `Signal<any\|null>` | Contains the parsed response (JSON), or `null`. |