Skip to content

Commit

Permalink
docs: v5 (#553)
Browse files Browse the repository at this point in the history
* docs: v5

* Update bin/build-markdown.js

* Update docs/authentication.md

Co-authored-by: Kanad Gupta <[email protected]>

* Update docs/faq.md

Co-authored-by: Kanad Gupta <[email protected]>

* Update packages/api/README.md

Co-authored-by: Kanad Gupta <[email protected]>

* Update docs/upgrading-from-v4.md

Co-authored-by: Kanad Gupta <[email protected]>

* Update docs/making-requests.md

Co-authored-by: Kanad Gupta <[email protected]>

* Update docs/upgrading-from-v4.md

Co-authored-by: Kanad Gupta <[email protected]>

* Update docs/making-requests.md

Co-authored-by: Kanad Gupta <[email protected]>

* Update docs/making-requests.md

Co-authored-by: Kanad Gupta <[email protected]>

* Update docs/making-requests.md

Co-authored-by: Kanad Gupta <[email protected]>

* Update docs/making-requests.md

Co-authored-by: Kanad Gupta <[email protected]>

* Update docs/making-requests.md

Co-authored-by: Kanad Gupta <[email protected]>

Co-authored-by: Kanad Gupta <[email protected]>
  • Loading branch information
erunion and kanadgupta authored Oct 31, 2022
1 parent 5b6a86a commit 5faaa11
Show file tree
Hide file tree
Showing 14 changed files with 161 additions and 63 deletions.
4 changes: 2 additions & 2 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ const sdk = require('api')(
);

sdk
.get('/anything', { foo: ['bar', 'baz'], baz: 'abc', key: 'value' })
.then(res => console.log(res))
.getAnything({ foo: ['bar', 'baz'], baz: 'abc', key: 'value' })
.then(({ data }) => console.log(data))
.catch(err => console.error(err));
```

Expand Down
10 changes: 3 additions & 7 deletions bin/build-markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,18 @@ const path = require('path');
// eslint-disable-next-line import/no-extraneous-dependencies
const { transcludeFile } = require('hercule/promises');

/**
* all Markdown files located at within the `docs` directory
* @type {Array.<String>}
*/
// All Markdown files are located within the `docs` directory.
const files = fs
.readdirSync('docs', { withFileTypes: true })
.filter(fileHandle => fileHandle.isFile())
.map(fileHandle => path.join('docs', fileHandle.name))
.filter(file => file.endsWith('.md') || file.endsWith('.markdown'));

// Clears out and recreates `dist` folder
// Clears out and recreates `dist` folder.
fs.rmSync('dist', { force: true, recursive: true });
fs.mkdirSync('dist/docs', { recursive: true });

// Populates any partials using hercule and then
// writes output to `dist` folder
// Populates any partials using hercule and then writes output to `dist` folder.
files.forEach(fileName => {
transcludeFile(fileName).then(({ output }) => {
fs.writeFileSync(`dist/${fileName}`, output, 'utf-8');
Expand Down
12 changes: 7 additions & 5 deletions docs/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ category: 62cc6ce22b8b6601da6cb12d
`api` supports API authentication through an `.auth()` method:

```js
sdk.auth('myApiToken');
sdk.listPets().then(res => {
// response
const petstore = require('@api/petstore');

petstore.auth('myApiToken');
petstore.listPets().then(({ data }) => {
// authenticated response
});
```

With the exception of OpenID, it supports all forms of authentication supported by the OpenAPI specification! Supply `.auth()` with your auth credentials and it'll magically figure out how to use it according to the API you're using. 🧙‍♀️
With the exception of OpenID and Mutual TLS it supports all forms of authentication supported by the OpenAPI specification! Supply `.auth()` with your auth credentials and it'll magically figure out how to use it according to the API you're using. 🧙‍♀️

For example:

Expand All @@ -22,4 +24,4 @@ For example:

> 📘
>
> Note that `sdk.auth()` is not chainable.
> The `.auth()` method is not chainable.
28 changes: 15 additions & 13 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ Yes! YAML definitions will be automatically converted to JSON when they're fetch

At the moment it does not. If you wish to use an API that has a Swagger 2.0 file, you'll need to first convert it to an OpenAPI 3 definition.

### Does this support OpenAPI 3.1 definitions?

Yes!

### Does this support OpenAPI 4 (Moonwalk) definitions?

No! Since v4 is still in the early planning stages we don't support it but once it's finalized we will.

### Does this support traditional OAuth 2 flows of creating tokens?

Not yet, unfortunately. For APIs that use OAuth 2, you'll need a fully-qualified token already for `api` to make requests.
Expand All @@ -19,19 +27,21 @@ Not yet, unfortunately. For APIs that use OAuth 2, you'll need a fully-qualified

Not yet! This is something we're thinking about how to handle, but it's difficult with the simplified nature of the `.auth()` method as it by design does not ask the user to inform the SDK of what kind of authentication scheme the token they're supplying it should match up against.

If you have ideas on how to handle this [we'd love to hear them](https://github.com/readmeio/api/discussions/547).

### Will this work in browsers?

If you generate an SDK with the CLI installation process, then yes! If you're having troubles getting autogenerated SDKs working in a browser, [please let us know](https://github.com/readmeio/api/issues)!
If you generate an SDK with the CLI installation process then yes! If you're having trouble getting autogenerated SDKs working in a browser, [please let us know](https://github.com/readmeio/api/issues)!

Unfortunately the dynamic version of `api` will **not** work in browsers as it requires access to some filesystem handling for managing its cache state.
Unfortunately the dynamic version of `api` will **not** work in browsers as it requires access to the filesystem for handling and managing its cache state.

### Will this validate my data before it reaches the API?

Not yet! This is something we've got planned down the road.
Not yet! This is something we're thinking about in the future.

### Does this support OpenAPI definitions that require authentication to download?
### Does this support fetching OpenAPI definitions that require authentication to download?

Not yet! The URL that you give the module must be publicy accessible. If it isn't, you can download it to your computer/server and then use the absolute path to that file instead.
Not yet! The URL that you give the module must be publicly accessible. If it isn't, you can download it to your computer or server and then use the absolute path to that file instead.

```sh
$ npx api install ./path/to/downloaded.json
Expand All @@ -41,14 +51,6 @@ $ npx api install ./path/to/downloaded.json
const sdk = require('api')('./path/to/downloaded.json');
```

### How do I access the Response object (for status and headers)?

By default we parse the response based on the `content-type` header for you. You can disable this by doing the following:

```js
sdk.config({ parseResponse: false });
```

### Where is the cache stored?

See [How does it work?](https://api.readme.dev/docs/how-it-works) for some information on how, when, and where `api` caches its data.
6 changes: 3 additions & 3 deletions docs/how-it-works.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ The `hash` within this is an `md5` of the full OpenAPI definition that we retrie

If for some reason this file gets lost, or the accessor you're supplying to `api` changes for whatever reason `api` will re-retrieve the OpenAPI definition at run-time.

```
```json
{
"d6b93e95fa1a7efdce6d1406dc599923": {
"hash": "cbb821db3609f8983ce1a372dadd122c",
Expand All @@ -113,7 +113,7 @@ const sdk = require('api')('https://raw.githubusercontent.com/readmeio/oas-examp
cacheDir: './path/to/my/custom/cache/dir',
});

sdk.listPets().then(res => {
console.log(`My pets name is ${res[0].name}!`);
sdk.listPets().then(({ data })) => {
console.log(`My pets name is ${data[0].name}!`);
});
```
12 changes: 0 additions & 12 deletions docs/http-requests.md

This file was deleted.

76 changes: 76 additions & 0 deletions docs/making-requests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
---
title: Making Requests
category: 62cc6ce22b8b6601da6cb12d
---

If the API you're using doesn't have any documented [operation IDs](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#user-content-operationid), `api` will generate some for you to use.

If you're using code generation, these will be immediately available to use in your generated library. However, due to the nature of the [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) architecture in the dynamic version of the library, this isn't the case for dynamically generated libraries. For these cases, you can check out the documentation for the API you're using.

> ⚠️
>
> We recommend using code generation as it'll give you the additional benefit of TypeScript type assistance and autocompletion (even if you aren't using TypeScript in your codebase).
With an instance of your SDK, you make an HTTP request against an operation on the API like so:

```js
const petstore = require('@api/petstore');

petstore.listPets().then(({ data, status, headers, res }) => {
console.log(`My pets name is ${data[0].name}!`);
});
```

Here, the data returned in the promise from `listPets` is an object containing the following data:

- `data`: The data that came back in the API request. Under the hood this is the result of `api` running `res.json()` or `res.text()` on the [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) object from the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).
- `status`: This is the HTTP status code of the response.
- `headers`: The headers that came back in the response. This is an instance of the [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) object.
- `res`: This is the raw [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) object we received from the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).

## Error Handling

For every response that is returned with an HTTP status code between 400 and 599, `api` will throw a custom error: `FetchError`. Identical to how responses are returned from successful requests, instances of `FetchError` can be destructured to obtain the same data. For example:

```js
await petstore.deletePet({ id: petId }).catch(({ status, data }) => {
// status = 404
// data = 'Not Found'
});
```

Alternatively if you'd like to check for an error other than `FetchError` (i.e., an error with the SDK itself), you can do that too:

```js
await petstore.deletePet({ id: petId }).catch(err => {
if (!(err instanceof FetchError)) {
throw err;
}

// err.status = 404
// err.data = 'Not Found'
});
```

## Request Timeouts

By default, the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) generally has a default timeout of 30 seconds. If you wish to configure this, you can with the `.config()` method:

```js
petstore.config({ timeout: 100 }); // 100 milliseconds

await petstore
.deletePet({ id: petId })
.then(() => {
// goodbye, friend
})
.catch(err => {
// err.message = The operation was aborted.
});
```

By supplying a timeout to `.config({ timeout })`, in milliseconds, `api` will automatically initialize an [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) to abort your request if it takes longer than your `timeout` value. Please note that if you set a custom timeout, the error that is thrown will be an instance of `AbortError`, **not** `FetchError`.

> 📘
>
> The `.config()` method is not chainable.
6 changes: 3 additions & 3 deletions docs/parameters-and-payloads.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ When supplying parameters and/or request body payloads to an API request, you do
For example, if you wanted to make a GET request:

```js
sdk.showPetById({ petId: 1234 }).then(...)
sdk.showPetById({ id: 1234 }).then(...)
```

Since `petId` matches up with the `petId` path parameter, the SDK here will issue a GET request against `/pets/1234`.
Since `id` matches up with the `id` path parameter, the SDK here will issue a GET request against `/pets/1234`.

What about a POST request?

Expand All @@ -27,7 +27,7 @@ Since `name` here would correspond on `createPets` to request body payload, this
What about operations that require both? Well you can mix them too!

```js
sdk.updatePet({ name: 'Buster 2' }, { petId: 1234 }).then(...)
sdk.updatePet({ name: 'Buster 2' }, { id: 1234 }).then(...)
```

Since we've supplied two objects here, the SDK automatically knows that you're supplying both a `body` and `metadata`, and can make a PUT request against `/pets/1234` for you.
Expand Down
2 changes: 1 addition & 1 deletion docs/server-configurations.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ sdk.server('https://{region}.api.example.com/{basePath}', {
basePath: 'v14',
});

sdk.get('/pets').then(...)
sdk.getPets().then(...)
```

When your request is executed, it will be made to `https://eu.api.example.com/v14/pets`. Alternatively if you don't want to deal with URL templates, you can opt to pass a full URL in instead:
Expand Down
38 changes: 38 additions & 0 deletions docs/upgrading-from-v4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
title: Upgrading from v4
category: 5d4c940cae4e610060475769
---

If you're upgrading from v4 of `api`, welcome 👋 a lot's changed! With the introduction of v5, `api` now offers a complete [code generation offering](https://api.readme.dev/docs/usage#code-generation), complete with:

- Full TypeScript types (generated off your OpenAPI definition) 📖
- Ability to export to TypeScript, CJS, and ESM compiled files 📦
- Ability to run your SDK within a browser 🌍

It's neat, and you should check it out. 🥺

If you'd like to continue using the [dynamic syntax](https://api.readme.dev/docs/usage#dynamically) you will need to update how you're handling promises that are returned from API requests, but it shouldn't be too bad.

Here's what your `api` implementation may have looked like before under v4:

```js
const petstore = require('api')('https://raw.githubusercontent.com/readmeio/oas-examples/main/3.0/json/petstore.json');

petstore.listPets().then(res => {
console.log(`My pets name is ${res[0].name}!`);
});
```

And here's what it should look like now:

```js
const petstore = require('api')('https://raw.githubusercontent.com/readmeio/oas-examples/main/3.0/json/petstore.json');

petstore.listPets().then(({ data }) => {
console.log(`My pets name is ${data[0].name}!`);
});
```

If you were using the `.config({ parseResponse: false })` option, that option has been removed in favor of this new resolved data shape where we return `data`, `status`, `headers`, and `res` to you. You can see documentation on those [here](https://api.readme.dev/docs/making-requests).

And if you have any trouble or need help we're more than happy to give you an assist. https://github.com/readmeio/api/issues
8 changes: 4 additions & 4 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ Once you have your library generated and installed you can use your SDK like you
```js
const petstore = require('@api/petstore');

petstore.listPets().then(res => {
console.log(`My pets name is ${res[0].name}!`);
petstore.listPets().then(({ data, status, headers, res }) => {
console.log(`My pets name is ${data[0].name}!`);
});
```

Expand All @@ -39,8 +39,8 @@ If you don't wish to use code generation, you can load `api` and supply it an Op
```js
const petstore = require('api')('https://raw.githubusercontent.com/readmeio/oas-examples/main/3.0/json/petstore.json');

petstore.listPets().then(res => {
console.log(`My pets name is ${res[0].name}!`);
petstore.listPets().then(({ data, status, headers, res }) => {
console.log(`My pets name is ${data[0].name}!`);
});
```

Expand Down
18 changes: 7 additions & 11 deletions packages/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,37 +17,33 @@
- [Usage](https://api.readme.dev/docs/usage)
- [Authentication](https://api.readme.dev/docs/authentication)
- [Parameters and Payloads](https://api.readme.dev/docs/parameters-and-payloads)
- [HTTP requests](https://api.readme.dev/docs/http-requests)
- [Making requests](https://api.readme.dev/docs/making-requests)
- [Server configurations](https://api.readme.dev/docs/server-configurations)
- [How does it work?](https://api.readme.dev/docs/how-it-works)
- [FAQ](https://api.readme.dev/docs/faq)

`api` is a library that facilitates creating an SDK from an OpenAPI definition. You can use its codegen offering to create an opinionated SDK for TypeScript or JS (+ TypeScript types).

```sh
$ npx api@beta install https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.json
$ npx api install https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.json
```

```js
const petstore = require('@api/petstore');

petstore.listPets().then(res => {
console.log(`My pets name is ${res[0].name}!`);
petstore.listPets().then(({ data }) => {
console.log(`My pets name is ${data[0].name}!`);
});
```

> 📘
>
> Please note that using `api` through `npx` is currently only available on the v5 beta that we're still working on. If you're using v4 or sooner the [dynamic usage documentation](https://api.readme.dev/docs/usage#dynamically) pertains to you.
Or you can use it dynamically (though you won't have fancy TypeScript types):
Or you can use it dynamically (though you won't have fancy TypeScript types to help you out!):

```js
const petstore = require('api')(
'https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.json'
);

petstore.listPets().then(res => {
console.log(`My pets name is ${res[0].name}!`);
petstore.listPets().then(({ data })) => {
console.log(`My pets name is ${data[0].name}!`);
});
```
2 changes: 1 addition & 1 deletion packages/api/src/cli/codegen/languages/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export default class TSGenerator extends CodeGeneratorLanguage {
super(spec, specPath, identifier);

this.requiredPackages = {
'api@beta': {
api: {
reason: "Required for the `api/dist/core` library that the codegen'd SDK uses for making requests.",
url: 'https://npm.im/api',
},
Expand Down
2 changes: 1 addition & 1 deletion packages/api/test/cli/codegen/languages/typescript.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ describe('typescript', function () {
const ts = new TSGenerator(oas, './openapi.json', 'petstore', { compilerTarget: 'cjs' });
await ts.installer(storage, { logger, dryRun: true });

expect(logger).to.be.calledWith('npm install --save --dry-run api@beta json-schema-to-ts oas');
expect(logger).to.be.calledWith('npm install --save --dry-run api json-schema-to-ts oas');
expect(logger).to.be.calledWith('npm install --save --dry-run'); // This is the `@api/petstore` install.
});
});
Expand Down

0 comments on commit 5faaa11

Please sign in to comment.