https://github.com/kouks/awi
Versatile, modern and lightweight http client based on promises.
https://github.com/kouks/awi
ajax client http node promise xhr
Last synced: 11 months ago
JSON representation
Versatile, modern and lightweight http client based on promises.
- Host: GitHub
- URL: https://github.com/kouks/awi
- Owner: kouks
- License: mit
- Created: 2019-02-26T21:17:18.000Z (almost 7 years ago)
- Default Branch: master
- Last Pushed: 2023-01-07T03:24:23.000Z (about 3 years ago)
- Last Synced: 2024-10-16T02:27:48.319Z (over 1 year ago)
- Topics: ajax, client, http, node, promise, xhr
- Language: TypeScript
- Homepage:
- Size: 1020 KB
- Stars: 8
- Watchers: 2
- Forks: 0
- Open Issues: 17
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# Awi
[](https://www.npmjs.com/package/awi)
[](https://travis-ci.org/kouks/awi)
[](https://codecov.io/gh/kouks/awi)
Versatile, modern and lightweight http client based on promises.
## Installation
```bash
npm i -S awi
```
```html
```
## Requirements
| Node | Chrome | Edge | Firefox | Opera | Safari |
| :----: | :----: | :--: | :-----: | :---: | :----: |
| 6.13.0 | 52 | 17 | 29 | 19 | 10 |
## Usage
### Basics
The most basic of requests can be executed seamlessly with Awi. Simply create
a new instance and call the `get` sugar method with the desired URL. This call
returns an instance of Awi's `Response` interface that has the response body,
status and headers easily accessible.
```typescript
import { Awi, Response } from 'awi'
const response: Response = await new Awi()
.get('http://server.api/todos')
console.assert(typeof response.body === 'object')
console.assert(typeof response.headers === 'object')
console.assert(response.status === 200)
```
Awi is at its best when used in TypeScript as you can type-hint all responses
and get type checks and nice auto-completion from your IDE.
```typescript
import { Awi, Response } from 'awi'
interface TodoResponse extends Response {
body: { title: string, completed: boolean }
}
const response: Response = await new Awi()
.get('http://server.api/todos/1')
console.assert(typeof response.body.title === 'string')
console.assert(typeof response.body.completed === 'boolean')
```
Awi provides syntax sugar for all basic request methods. `POST`, `PUT` and
`PATCH` helpers optionally take the body of the request as their second
argument.
```typescript
import { Awi, Response } from 'awi'
const response: Response = await new Awi()
.post('http://server.api/todos', { title: 'Start using Awi.', completed: true })
console.assert(response.status === 201)
```
Upon receiving a 400+ response status, Awi automatically rejects the promise so
that you don't have to do arbitrary checks for the response status via `if`
statements.
```typescript
import { Awi } from 'awi'
await new Awi()
.post('http://server.api/todos', { completed: false })
.catch(response => console.assert(response.status === 422))
```
Awi also provides a `body` helper to avoid repeating the infamous
`.then(res => res.body)` promise callback. This helper accepts a generic type
to type-hint the response body.
> Note that this helper sends a `GET` request by default. If you desire to use
> a different request method, the method needs to be specified using
> an [interceptor](#interceptors).
> Also note that if the promise is rejected, the whole response object is
> returned.
```typescript
import { Awi } from 'awi'
interface Todo {
title: string
completed: boolean
}
const todo: Todo = await new Awi()
.body('http://server.api/todos/1')
console.assert(typeof todo.title === 'string')
console.assert(typeof todo.completed === 'boolean')
```
Thanks to [@bausano](https://github.com/bausano) and his awesome
[data structures package](https://github.com/bausano/ts-data-structures), Awi
has an `optional` helper that returns the body of the response as an
`Optional` rather than rejecting the promise.
> Note that this helper sends a `GET` request by default. If you desire to use
> a different request method, the method needs to be specified using
> an [interceptor](#interceptors).
> Also note that if the request fails due to network issues or misconfiguration,
> the promise is still rejected.
```typescript
import { Awi, Optional } from 'awi'
interface Todo {
title: string
completed: boolean
}
const todo: Optional = await new Awi()
.optional('http://server.api/todos/1')
console.assert(todo instanceof Optional)
```
### Interceptors
Request interceptors are what makes Awi stand out. Inspired by
[Koa](https://koajs.com/), Awi provides a `use` method that accepts an
asynchronous callback that modifies the request object.
```typescript
import { Awi, Response } from 'awi'
const response: Response = await new Awi()
.use(async req => req.base = 'http://server.api')
.use(async req => req.path = 'todos')
.get()
console.assert(response.status === 200))
```
> All properties that can be modified on the request object are available in
> Awi's [API reference](https://github.com/kouks/awi/wiki/Request).
Every request in Awi is uniquely defined by the array of interceptors assigned
to the request. All Awi's helper methods are nothing more but a sugar for
assigning interceptors. All requests can be sent without using the helpers via
the `send` method.
```typescript
import { Awi, Method, Response } from 'awi'
const response: Response = await new Awi()
.use(async req => req.base = 'http://server.api')
.use(async req => req.path = 'todos')
.use(async req => req.method = Method.GET)
.send()
console.assert(response.status === 200))
```
> Although this approach is rather lenghty and using helpers is much cleaner, it
> provides a straightforward way to extend Awi and/or create request templates.
As you can see, the interceptor concept provides a way to create request
templates for your application in a very nice and reusable way. This can be
especially useful when making authorized requests.
```typescript
import { Awi, Response } from 'awi'
// Define the template to be reused.
const auth = () => new Awi()
.use(async req => req.base = 'http://server.api')
.use(async req => req.headers['authorization'] = `Bearer ${localStorage.token}`)
// Use the template and provide further parameters.
const response: Response = await auth()
.get('user')
console.assert(response.status === 200))
```
### API Reference
All of Awi's functionality is summed up on the
[wiki page](https://github.com/kouks/awi/wiki/API-Reference).
## Why Awi?
**It's lightweight**
The minified file size is 12kB and we do not intend to make it bigger!
**It's designed for developers, by developers**
Making http requests is something every developer needs to do on daily basis,
especially when it comes to TypeScript or JavaScript. Awi has a neat code base,
is strictly typed and we purposefully leave documentation blocks in the built
files - this way, you can read up on what each method does by simply
ctrl-clicking on it!
**It's flexible**
You can either choose to go the easy way and using Awi's built-in helpers to
execute your HTTP request as a one-liner, or you can define and extract reusable
templates for your requests from scratch!
Awi is also open-source, so should you be missing any features that would make
your life easier, feel free to contribute.
## Credits
The interceptor pattern is heavily inspired by [Koa](https://koajs.com/), which
is also used to create a mock server for our e2e tests.
Implemetation of executors for both web and node are inspired by no other than
[axios](https://github.com/axios/axios).
## License
MIT