Skip to content

Commit

Permalink
Publish generator and client to npm (#240)
Browse files Browse the repository at this point in the history
* move generator and client into directories in packages/

* move package.json into generator package dir

* rework gen.sh so it can be run from anywhere, take gen script out of openapi-gen

* add tsup, rename openapi-gen to openapi-gen-ts

* put config in package.json

* move stuff into src dir

* try to make CI work

* put tsconfig where it belongs, whoops

* put some stuff in package.json like we're really gonna publish

* maybe make CI linting work

* try to fix update spec action

* Autogenerate config update

* try crunchbang

* fix exports and main

* 0.1.1

* Autogenerate config update

* 0.1.2

* 0.1.3

* remove publish command

* fix bin name, 0.1.4

* switch bin to cjs

* npm pkg fix

* use tsup-node! yes!

* try different approach to static files

* add tsup and package.json for @oxide/api, move src into src/

* try adding /validate sub export with zod

* give each package its own readme

* bump package versions

* fix links in generator readme and bump version

* Autogenerate config update

* add barebones readme to @oxide/api

* remove stray TBD from readme

* Update README.md

* move packages up a dir, kill packages directory

* update readme with versioning scheme

* put msw, zod, and type test behind --features flag in CLI

* fail earlier if dest dir does not exist, fix tools/gen.sh

---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
david-crespo and github-actions[bot] authored May 6, 2024
1 parent e662ca5 commit a3b9d1e
Show file tree
Hide file tree
Showing 41 changed files with 4,849 additions and 1,253 deletions.
8 changes: 3 additions & 5 deletions .github/workflows/update-api-spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,9 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: "18"
- name: Generate spec
shell: bash
run: |
npm install
npm run gen
- working-directory: "./oxide-openapi-gen-ts"
run: 'npm install'
- run: ./tools/gen.sh
- uses: EndBug/add-and-commit@v9
with:
add: .
Expand Down
13 changes: 8 additions & 5 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: "18"
- name: npm install
- working-directory: "./oxide-openapi-gen-ts"
run: npm install
- name: Generate client
run: npm run gen
- name: TypeCheck
run: "./tools/gen.sh"
- name: Typecheck
working-directory: "./oxide-openapi-gen-ts"
run: npm run tsc
- name: Lint
run: npx eslint .
working-directory: "./oxide-openapi-gen-ts"
run: npm run lint
- name: Test
run: npm test
working-directory: "./oxide-openapi-gen-ts"
run: npm test run
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
packages/openpi-gen/node_modules
node_modules
dist
spec.json
spec.json
54 changes: 5 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,58 +7,14 @@ The generator is built specifically for use with specs generated by
[Dropshot](https://github.com/oxidecomputer/dropshot). It has not been tested on
any other specs and is unlikely to handle them well.

## Why a custom generator?

We tried many existing generators, and while most worked in a basic sense, we
found it hard to make customizations, whether through CLI flags, templates, or
patching with [patch-package](https://github.com/ds300/patch-package). We
decided to prototype our own TS generator after seeing other Oxide devs do the
same for Rust ([progenitor](https://github.com/oxidecomputer/progenitor) and
[oxide.rs](https://github.com/oxidecomputer/oxide.rs)) and Go
([oxide.go](https://github.com/oxidecomputer/oxide.go)). It quickly became clear
that a special-purpose generator could be dramatically simpler than a general
one, so writing one was easier than existing generators made it look.

## Repo guide

The source of the generator is in [`generator`](generator/). The core logic for
looping over the spec and creating the methods is in
[`generator/client/api.ts`](generator/client/api.ts) and the mapping from
OpenAPI schemas to TS types is in
[`generator/schema/types.ts`](generator/schema/types.ts). The mapping from
OpenAPI schemas to Zod schemas is in
[`generator/schema/zod.ts`](generator/schema/zod.ts).

The generated client can be found in [`client`](client/). The files in
[`static`](static/) are copied over to `client` as-is during generation. We
generate several distinct pieces:

| File | Description |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| [`Api.ts`](client/Api.ts) | A [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)-based TS client to the Oxide API |
| [`validate.ts`](client/validate.ts) | [Zod](https://github.com/colinhacks/zod) validators for API request and response types |
| [`msw-handlers.ts`](client/msw-handlers.ts) | Helpers used to build a mock API with [Mock Service Worker](https://mswjs.io/) in the console repo |
|Package| Description|
|---|---|
| [`@oxide/openapi-gen-ts`](./oxide-openapi-gen-ts) | TypeScript OpenAPI client generator |
| [`@oxide/api`](./oxide-api) | The client generated for the Omicron commit specified in `OMICRON_VERSION` |

## Using the API client

We intend to publish the generated code on npm, but have not done so yet. In
the [Oxide web console](https://github.com/oxidecomputer/console) (the primary
consumer of the TS client) we use the client by generating it from a pinned
spec version with `tsx generator/index.ts` and versioning a full copy of the
generated code in that repo.

The generated client uses the Fetch API, so in
order to be used in Node.js, it requires either Node.js v18 or a polyfill.

## Generating the client

```bash
# optional: update omicron sha in OMICRON_VERSION
npm i
npm run gen
```

The TypeScript client code will be written to [`client`](client/).
See the [README](./oxide-api/README.md) for the `@oxide/api` package.

## Contributing

Expand Down
50 changes: 0 additions & 50 deletions generator/index.ts

This file was deleted.

61 changes: 61 additions & 0 deletions oxide-api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Oxide TypeScript SDK

## Usage

### Installation

```
npm install @oxide/api
```

### Getting an API token

The easiest way to get a device token is to use the CLI.

```
oxide auth login --host https://my-oxide-rack.com
```

Then print the token:

```
oxide auth status --show-token
```

In the following example it's passed to the script through the `OXIDE_TOKEN`
environment variable on the assumption that you don't want to hard-code a token
into a script, but this can of course be done however you want. `OXIDE_TOKEN` is
not a special variable for the TypeScript SDK (it is for the CLI).

### Example

```ts
import { Api } from "@oxide/api"

const api = new Api({
host: "https://my-oxide-rack.com",
token: process.env.OXIDE_TOKEN,
})

const result = await api.methods.projectList({})

if (result.type === "success") {
console.log(result.data.items.map((p) => p.name))
}
```

## How does it all work?

### Methods

### Request bodies

### Responses: `ApiResult<T>`

## Other stuff in the package

Most likely nobody but us wants this, and we should take it out of the npm package.

### Mock Service Worker API skeleton

### Zod validators
Loading

0 comments on commit a3b9d1e

Please sign in to comment.