# oas-request

> Feed it a JSON Spec, it will spit out a lightweight HTTP client!

Latest version **3.0.5** (published 2023-09-05) · MIT license · 0 weekly downloads

## Install

```sh
npm install oas-request
pnpm add oas-request
yarn add oas-request
bun add oas-request
```

## Health

**Score 25/100 (F)** — status: abandoned.

Positive: no vulnerabilities.

Warnings: low downloads; no types; no esm support.

Negative: abandoned.

## Facts

| | |
|---|---|
| Version | 3.0.5 |
| Published | 2023-09-05 |
| First published | 2020-07-24 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Node | >=14 |
| Dependencies | 1 |
| Unpacked size | 17.9 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 14 |
| Author | Ahmad Nassri |
| Maintainers | ahmadnassri |
| Keywords | oas, request |

## Links

- npm: https://www.npmjs.com/package/oas-request
- Repository: https://github.com/ahmadnassri/node-oas-request
- Issues: https://github.com/ahmadnassri/node-oas-request/issues
- Funding: https://github.com/sponsors/ahmadnassri
- npm.io page: https://npm.io/package/oas-request

## Dependencies (1)

- [cross-fetch](https://npm.io/package/cross-fetch.md) ^3.1.5

## Alternatives

- [update-check](https://npm.io/package/update-check.md) — 4.0M weekly downloads
- [react-native-onesignal](https://npm.io/package/react-native-onesignal.md) — 134.5K weekly downloads
- [react-redux-toastr](https://npm.io/package/react-redux-toastr.md) — 33.7K weekly downloads
- [@nocobase/plugin-notification-manager](https://npm.io/package/@nocobase/plugin-notification-manager.md) — 2.0K weekly downloads
- [react-simple-toasts](https://npm.io/package/react-simple-toasts.md) — 1.9K weekly downloads

## Recent versions

- 3.0.5 (latest) — 2023-09-05
- 3.0.4 — 2023-07-23
- 3.0.3 — 2023-06-10
- 3.0.2 — 2023-01-04
- 3.0.1 — 2022-12-29
- 3.0.0 — 2022-07-28
- 2.1.4 — 2021-12-03
- 2.1.3 — 2021-10-12
- 2.1.2 — 2021-05-11
- 2.1.1 — 2021-05-11
- 2.1.0 — 2021-03-30
- 2.0.1 — 2021-03-28
- 2.0.0 — 2021-03-28
- 1.1.3 — 2021-03-12
- 1.1.2 — 2021-02-27
- … 13 more at https://npm.io/package/oas-request/versions

## README

# OpenAPI Spec HTTP Client

Feed it a JSON Spec, it will spit out a lightweight HTTP client!

[![license][license-img]][license-url]
[![release][release-img]][release-url]
[![semantic][semantic-img]][semantic-url]

## Why

While there are plenty of *"code generators"* for OpenAPI Specification, they create a lot of "garbage" code that you may not need,
and there while there are others that follow a similar path of this library, they still attempt to do too much! *(like request validation before sending)*

This library does not concern itself with anything other than constructing an HTTP request and sending it!

<details>
  <summary><strong>FAQ</strong></summary>

-   **Why no validation?**  
    You should rely on validation & sanitation at the source of truth: *The API server itself!*

-   **YAML Support?**  
    This package **does not** natively support OpenAPI Specification YAML format, but you can easily convert to JSON before calling `oas-rqeuest`

      <details>
        <summary>Example</summary>

    ###### using [`YAML`][]

    ``` js
    const YAML = require('yaml')
    const { readFile } = require('fs/promises')

    const file = await readFile('openapi.yml', 'utf8')

    const spec = YAML.parse(file)

    const OASRequest = require('oas-request')(spec)
    ```

    ###### using [`apidevtools/swagger-cli`][]

    ``` bash
    npx apidevtools/swagger-cli bundle spec/openapi.yml --outfile spec.json
    ```

      </details>

    </details>

## What

Some feature highlights:

-   Automatic methods creation
-   Path Templating
-   uses [`cross-fetch`][] for all HTTP operations

## Usage

<details>
  <summary><em>e.g. <code>petstore.json</code></em></summary>

``` json
{
  "openapi": "3.0.0",
  "info": {
    "version": "1.0.0",
    "title": "Swagger Petstore"
  },
  "servers": [
    {
      "url": "http://petstore.swagger.io/{version}",
      "variables": {
        "version": {
          "description": "api version",
          "default": "v1"
        }
      }
    }
  ],
  "paths": {
    "/pets": {
      "get": {
        "operationId": "listPets",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "description": "How many items to return at one time (max 100)",
            "required": false,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A paged array of pets",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Pets"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createPets",
        "responses": {
          "201": {
            "description": "Null response"
          }
        }
      }
    },
    "/pets/{petId}": {
      "get": {
        "operationId": "showPetById",
        "parameters": [
          {
            "name": "petId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Expected response to a valid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Pet"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Pet": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64"
          },
          "name": {
            "type": "string"
          },
          "tag": {
            "type": "string"
          }
        }
      },
      "Pets": {
        "type": "array",
        "items": {
          "$ref": "#/components/schemas/Pet"
        }
      }
    }
  }
}
```

</details>

<br/>

``` js
const spec = require('./petstore.json')
const OASRequest = require('oas-request')(spec)

// define root server url
const request = new OASRequest({
  server: 'http://petstore.swagger.io/v1'
})

// or use one from the OpenAPI Specification
const request = new OASRequest({
  server: {
    url: spec.servers[0].url
    // populate values for server (see OpenAPI Specification #4.7.5)
    variables: {
      version: 'v2'
    }
  }
})

// auto generated methods match OpenAPI Specification "operationId"
await request.listPets()
await request.createPets()
await request.showPetById()
```

<details>
<summary><em>Advanced Usage</em></summary>

``` js
const spec = require('./petstore.json')
const OASRequest = require('oas-request')(spec)

// always use JSON headers
const request = new OASRequest({
  server: 'http://petstore.swagger.io/v1'
  headers: {
    'accept': 'application/json',
    'content-type': 'application/json'
  }
})

// POST with JSON
const body = JSON.stringify(body)
const response = await request.createPets({ body })
const data = await response.json()

console.log(data)
```

</details>

### `new OASRequest(APIOptions)`

Construct a new instance of the API request, returns an Object with auto generated method names matching each of the unique OpenAPI Specification [`operationId`][]

<details>
<summary><em>Example</em></summary>

###### `spec.json`

``` json
{
  ...
  "paths": {
    "/pets": {
      "get": {
        "operationId": "listPets",
        ...
      },
      "post": {
        "operationId": "createPets",
        ...
      }
    },
    "/pets/{petId}": {
      "get": {
        "operationId": "showPetById",
        ...
      }
    }
  }
}
```

###### `app.js`

``` js
const spec = require('./petstore.json')
const OASRequest = require('oas-request')(spec)

// define root server url
const request = new OASRequest({ server: 'http://petstore.swagger.io/v1' })

// auto generated methods match OpenAPI Specification "operationId"
await request.listPets()
await request.createPets()
await request.showPetById()
```

</details>

#### `APIOptions`

| property      | type             | required | default           | description                                                             |
|---------------|------------------|----------|-------------------|-------------------------------------------------------------------------|
| **`client`**  | `Function`       | ✗        | [`unfetch`][]     | a Function that executes the HTTP request. *(see [`clientFunction`][])* |
| **`server`**  | `String｜Object` | ✗        | `spec.servers[0]` | Root server url String, or [`Server Object`][]                          |
| **`headers`** | `Object`         | ✗        | `{}`              | Global HTTP request headers *(used with every request)*                 |
| **`query`**   | `Object`         | ✗        | `{}`              | Global Query String *(used with every request)*                         |
| **`params`**  | `Object`         | ✗        | `{}`              | Global [Path Templating][] parameters *(used with every request)*       |

##### `clientFunction`

a `Function` with the signature: `Function(url, requestOptions)` to execute the HTTP request, the default built-in function uses [`cross-fetch`][], you can customize the client to use whatever HTTP library you prefer.

> **⚠️ Note**:
>
> -   `url` is an instance of [`URL`][]
> -   `options.query` will be processed to construct the `url`, then deleted.
> -   `options.params` will be processed and used in Path Templating, then deleted.

<details>
<summary><em>Example: always assume JSON</em></summary>

``` js
const spec = require('./petstore.json')
const fetch = require('cross-fetch')
const OASRequest = require('oas-request')(spec)

const request = new OASRequest({
  client: async function (url, options) {
    const response = await fetch(url, {
      ...options,

      // always set body to JSON
      body: JSON.stringify(options.body),

      headers: {
        ...options.headers,
        // always set headers to JSON
        ...{
          'accept': 'application/json',
          'content-type': 'application/json'
        }
      }
    })

    // always parse body as JSON
    response.data = await response.json()

    return response
  }
})

const response = await request.createPet({
  body { 
    id: 1,
    name: 'Ruby'
  }
})

console.log(response.data)
```

</details>

<details>
<summary><em>Example: using <code>axios</code></summary>

``` js
const spec = require('./petstore.json')
const axios = require('axios')
const OASRequest = require('oas-request')(spec)

const request = new OASRequest({
  client: async function (URL, options) {
    return axios({ 
      ...options, 
      maxRedirects: 10,
      url: URL.toString(),
      httpsAgent: new https.Agent({ keepAlive: true })
    })
  }
})

const response = await request.createPet({
  data: { 
    id: 1,
    name: 'Ruby'
  },
  timeout: 1000
})
```

</details>

##### `ServerObject`

> ***⚠️ Note**: This is not the same as OpenAPI Specification's [Server Object][], though it's similarly structured*

| property        | type     | required | description                                          |
|-----------------|----------|----------|------------------------------------------------------|
| **`url`**       | `String` | ✓        | Root server url                                      |
| **`variables`** | `Object` | ✗        | Key-value pairs for server URL template substitution |

### `__Operation__(requestOptions)`

-   Operation method names are generated from the unique OpenAPI Specification [`operationId`][]
-   Operations method will return with a call to the specified [`Client Function`][]

#### `requestOptions`

The `requestOptions` Objects maps to [Fetch `init` parameter][] with some special considerations:

-   `method` will always be set based on the OpenAPI Specification method for this operation
-   `query` is a special property used to construct the final URL
-   `params` is a special property used to construct the final URL Path *(Path Templating)*

## Full Example

``` js
const spec = require('./petstore.json')
const API = require('oas-request')(spec)

// send to httpbin so we can inspect the result
const request = new OASRequest({
  server: 'http://petstore.swagger.io/v1',
  headers: {
    'user-agent': 'my-awsome-api-client',
    'x-special-header': 'sent-with-every-request'
  }
})

await request.listPets({
  query: {
    limit: 100
  }
})

await request.getPetById({
  params: { petId: 'my-pet' }
  headers: {
    'x-additional-header': 'this operation needs this'
  }
})

await request.updatePetById({
  params: { petId: 'my-pet' },
  body: {
    name: "ruby",
    isGoodDog: true
  }
})
```

  [`YAML`]: https://www.npmjs.com/package/yaml
  [`apidevtools/swagger-cli`]: https://www.npmjs.com/package/@apidevtools/swagger-cli
  [`cross-fetch`]: https://github.com/lquixada/cross-fetch
  [`operationId`]: http://spec.openapis.org/oas/v3.0.3#operation-object
  [`unfetch`]: #clientFunction
  [`clientFunction`]: #clientfunction
  [`Server Object`]: #serverobject
  [Path Templating]: http://spec.openapis.org/oas/v3.0.3#path-templating
  [`URL`]: https://developer.mozilla.org/en-US/docs/Web/API/URL
  [Server Object]: http://spec.openapis.org/oas/v3.0.3#server-object
  [`Client Function`]: clientFunction
  [Fetch `init` parameter]: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#parameters

----
> Author: [Ahmad Nassri](https://www.ahmadnassri.com/) &bull;
> Twitter: [@AhmadNassri](https://twitter.com/AhmadNassri)

[license-url]: LICENSE
[license-img]: https://badgen.net/github/license/ahmadnassri/node-oas-request

[release-url]: https://github.com/ahmadnassri/node-oas-request/releases
[release-img]: https://badgen.net/github/release/ahmadnassri/node-oas-request

[semantic-url]: https://github.com/ahmadnassri/node-oas-request/actions?query=workflow%3Arelease
[semantic-img]: https://badgen.net/badge/📦/semantically%20released/blue

---
_Source: https://npm.io/package/oas-request · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
