# OpenAPI UI: a browser-based OpenAPI console that doubles as a simplified Postman

> openapi-ui renders an OpenAPI or Swagger document in the browser, generates mock request parameters from the schema, and lets you fire the request against a live gateway without an account or a local install. It ships as a CDN script, an npm package and a Docker image, and it is MIT licensed.

**rookie-luochao/openapi-ui** — OpenAPI/Swagger UI document, quickly generate mock params and call api, also simplified postman tool.   基于 OpenAPI/Swagger 规范的接口文档，快速模拟请求参数并调用接口，也是简化版 postman 工具，欢迎提功能请求、bug

- Repository: https://github.com/rookie-luochao/openapi-ui
- Website: https://openapi-ui.vercel.app/service/findPetsByStatus?serviceURL=https%3A%2F%2Fpetstore3.swagger.io%2Fapi%2Fv3%2Fopenapi.json&importModeType=url
- Stars: 642 · Forks: 58
- Language: TypeScript
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/rookie-luochao-openapi-ui

## It is a static bundle, and that is the whole distribution model

The fastest way to understand openapi-ui is to look at how it is meant to be used. There is a container div with a spec-url attribute and a theme attribute, and one script tag.

```tsx
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>openAPI UI</title>
  </head>
  <body>
    <div id="openapi-ui-container" spec-url="https://petstore3.swagger.io/api/v3/openapi.json" theme="light"></div>
    <script src="https://cdn.jsdelivr.net/npm/openapi-ui-dist@latest/lib/openapi-ui.umd.js"></script>
  </body>
</html>
```

There is no build step, no server component and no account. The script reads the spec from the URL, fetches it, renders the documentation, and from then on the page is an API console. The only configuration in the markup is where the spec lives and whether the theme is light or dark.

The spec-url attribute accepts a full path or a path relative to the page, which is the second example in the README, and that difference matters in practice: a relative path means the console can be deployed next to a static copy of the specification inside an intranet without any CORS arrangement, while a full path means one console can point at several gateways.

The npm package name is openapi-ui-dist, and the dist suffix is doing real work. The name tells you this is the distribution artefact rather than the source, which is why the README's React example imports from openapi-ui-dist and loads it dynamically inside a useEffect.

```tsx
import { useEffect } from "react";

const SetUpOpenApiUI = () => {
  useEffect(() => {
    import("openapi-ui-dist")
  }, []);

  return (
    <div id="openapi-ui-container" spec-url="https://petstore3.swagger.io/api/v3/openapi.json" theme="light" />
  );
}

export const openapiRoutes = {
  path: "/openapi",
  id: "openapi",
  element: <SetUpOpenApiUI />,
};
```

The dynamic import inside the effect keeps the bundle out of the initial page load, which is the right pattern when the console is one route inside a larger application rather than the whole application.

The primary language is TypeScript, the licence is MIT, and the last push was on 2026-06-18 with the newest release tag v2.3.3 from 2024-10-13.

## Mock parameters come from the schema, with a fallback when the schema is thin

The feature that separates this from a plain documentation viewer is that it fills in request parameters for you.

The rule has two branches. If the schema contains the format field, then openapi-sampler is used to mock the request params. If the schema does not contain the format field, then faker is used to mock the request params.

That is a sensible fallback chain, and it explains the two dependencies in the manifest. openapi-sampler is at 1.7.0 and @faker-js/faker is at 10.4.0. The sampler works from the schema's format information, so it produces values that match what the API expects, for instance a date-shaped string for a date field. When the schema lacks format, there is nothing to infer from, and faker generates a generic value that satisfies the type.

The practical consequence is that a well specified API produces realistic example requests, and a loosely specified one produces plausible but arbitrary ones. If you are evaluating whether a schema is good enough to be usable, running it through this tool and looking at the generated parameters is a quick way to see where the specification is thin.

The import formats are also worth noting. openapi-ui supports swagger2.json and swagger2.yml as well as openapi3.json and openapi3.yml, and the dependency list includes swagger2openapi at 7.0.8, which converts a Swagger 2 document to OpenAPI 3 in the browser rather than requiring you to convert it beforehand. The topic tags cover swagger2, openapi3 and openapi31.

There are three ways to get a document into the page: enter a swagger2 or openapi3 API gateway URL and refresh the page to update the interface, upload a swagger2 or openapi3 file, or paste swagger2 or openapi3 text. The first is the live case, the second is the offline case, and the third is the case where the document is in a ticket or a chat message.

The editor components come from @monaco-editor/react and monaco-editor, and json-schema-enhanced-editor-react is in the dependency list for editing request bodies against their schema.

## Error reporting has an explicit five step precedence

The README documents the request error message display rules with a precision that is unusual, and it is worth reading as a specification because it tells you exactly what a request failure will look like.

If the returned structure contains a message field, display the message field. If the returned structure contains a msg field, display the msg field. If the returned result is a string, display the string. Display the AxiosResponse.statusText field. Display the AxiosError.message field.

Five rules in priority order, and they are rules rather than a fallback chain. The first three look inside the response body, which is where a well behaved API puts its error message. The last two are transport-level fallbacks for when the body is empty or unparseable, and they come from axios, which is the HTTP client in use at 1.13.6.

Getting this right matters more than it looks. The naive implementation shows a generic network error for every failure, which means an API returning {"message": "quota exceeded"} and an API returning an HTML 502 gateway page look identical in the UI. The rules here mean the console surfaces the API's own error text when there is one, so a developer debugging an integration sees the same message the backend produced.

The global configuration is described in two lines and both are practical. It supports configuring the request timeout, with the default request timeout being 2 minutes, and it supports configuring the request Authorization, and the Authorization can be overridden in the current request.

The override is the part that makes the tool usable for testing a gateway with different credentials. A single console can hold a default token for the shared team environment and, for a particular call, be given a different one without changing the global setting.

The environment variable handling is what makes a deployment configurable rather than forked. The Docker section shows APP_CONFIG as an environment variable with a value of env=zh,appNameZH=简洁美观的接口文档, so the same image can serve an English or a Chinese instance and can carry a different application name, chosen at container start rather than at build time.

## Shareable URLs and session storage are what make it a shared tool

Two features decide whether openapi-ui is a personal tool or a shared one.

The first is URL sharing. The url can only be shared when imported through url mode, and the instruction is to copy the url and share it with those who need it, they can echo the url to the specified interface.

That is a narrow and deliberate limitation. The mode matters because the URL carries the reference to the specification, and in file mode or text mode there is no URL to carry. The homepage in the repository metadata shows the shape of a shared link, with the spec URL and an importModeType of url in the query string.

What the link carries is the pointer to the specification, not the state of your session. So the recipient lands on the same console pointed at the same gateway, and any parameters they type are their own.

The second feature is multiple gateway URLs, and its mechanism is stated plainly: the caching strategy used is session storage, so you can open multiple pages at the same time.

Session storage rather than local storage is the correct choice here and the reason is worth understanding. Local storage is shared across every tab of the same origin, so two tabs pointing at different gateways would fight over one cache slot and the second tab would show the first tab's specification. Session storage is per tab, so two tabs can hold two different specifications at once and neither disturbs the other.

That is a small design decision with a disproportionate effect on whether the tool is usable for comparing two versions of an API side by side, which is a common task when a gateway is being rolled out.

The trade-off is that session storage is per tab and does not survive the tab being closed, so a specification loaded by URL has to be re-fetched in a new tab. For a shared console behind a gateway, that is a refresh rather than a problem.

## The Docker image is a static bundle behind nginx

The deployment path is a prebuilt image, and the Dockerfile shows how little there is to it.

```dockerfile
# syntax = docker/dockerfile:experimental
FROM --platform=${BUILDPLATFORM:-linux/amd64,linux/arm64} node:20-buster AS builder

ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
RUN corepack enable

WORKDIR /src
COPY ./ /src

RUN --mount=type=cache,target=/src/node_modules,id=myapp_pnpm_module,sharing=locked \
    --mount=type=cache,target=/pnpm/store,id=pnpm_cache \
        pnpm install

RUN --mount=type=cache,target=/src/node_modules,id=myapp_pnpm_module,sharing=locked \
        pnpm run build

FROM --platform=${BUILDPLATFORM:-linux/amd64,linux/arm64} ghcr.io/rookie-luochao/nginx-runner:latest

COPY --from=builder /src/dist /app
```

The build stage is node:20-buster with pnpm enabled through corepack, and both the install and the build use BuildKit cache mounts, one for node_modules and one for the pnpm store, so a repeated build does not re-download. The runtime stage is a prebuilt nginx image, and the only thing copied into it is the dist directory. There is no application server in the final image because there is no server-side application. The output is static files.

That architecture has a consequence for the problem of reaching an intranet API, which the README addresses directly: if unable to connect intranet api, you can run this project locally or use docker to deploy this project locally or on the server. The reason for that advice is browser-side security, not a server-side one. The console runs in the browser and the request to the intranet gateway is made by the browser, so it is subject to the user's network position and to the gateway's CORS policy. Hosting the console on a machine inside the network does not move the request into that network, because the request originates from wherever the browser is.

So the deployment advice is about giving the browser a same-origin console to load, which reduces the number of cross-origin requests, rather than about proxying the API call.

The image is published at ghcr.io/rookie-luochao/openapi-ui:latest and is run with the port mapping and the configuration environment variable shown earlier. The makefile in the repository root provides the same steps locally as make docker-build, make docker-run and make docker-build-run.

## Where OpenAPI UI is the wrong tool

The first wrong-tool case is a team that needs a real API client. The project describes itself as a simplified Postman tool, and the simplification is real: state lives in session storage, there is no mention of environments, no collection of saved requests, no test scripts, no variables shared across requests, and no way to chain a sequence of calls. If you need to script a multi-step flow or keep a reusable request catalogue, Postman or Insomnia does that and openapi-ui does not pretend to.

The second case is an API behind strict CORS. The console is a browser page making cross-origin calls, and a gateway that does not send permissive CORS headers will refuse the request from the browser while working perfectly from curl. If you cannot change the gateway's headers, this tool will look broken in a way that is not the tool's fault, and the deployment advice in the README about running it locally does not change the origin of the request.

The third case is a specification you do not control the hosting of. The spec-url has to be reachable by the browser, and if the OpenAPI document lives behind the same authentication as the API, the console cannot fetch it either.

The fourth case is a project that needs to try a live API against a generated request with realistic values. openapi-sampler fills parameters from the schema, which is exactly what you want when you are learning an API and exactly what you do not want when you are testing an edge case with a value the schema forbids. It is a convenience generator, not a fuzzer.

On maintenance, the release history is the thing to check. The recent releases are v2.3.3 from 2024-10-13, v2.3.2 from 2024-10-11 and v2.3.1 from 2024-09-28, and the last push to the repository was on 2026-06-18. The package.json version is 2.3.3, which matches the newest tag, so the published npm artefact is older than the source tree. The stack is current React at 19.2.4, antd at 6.3.5, Vite and TypeScript 5, zustand for state and i18next for translations with a browser language detector, which is why the interface appears in Chinese by default in the container example.

One licence point. The project is MIT licensed with the LICENSE file at the repository root, which permits commercial use and modification, and the npm package is published under the same terms. The dependencies carry their own licences, and antd and faker in particular are worth checking against a policy that tracks transitive licences.

## Conclusion

openapi-ui suits a team that wants a shareable API console for a gateway without running anything, since the whole thing is a static bundle that can be dropped behind nginx or served from a CDN. It does not suit a team that needs workspaces, environment variables and test suites, because it keeps its state in session storage and describes itself as a simplified Postman rather than a replacement for one. Before adopting, check the release gap: the newest tag is v2.3.3 from 2024-10-13 while the last push was on 2026-06-18, so confirm which build you are actually deploying, and run npm run build:package if you intend to consume the npm package rather than the CDN file.

## FAQ

### What is openapi-ui?

openapi-ui is a browser based OpenAPI and Swagger UI that renders an API document, quickly generates mock request parameters and calls the API. The project describes it as a simplified Postman tool, and it is MIT licensed.

### How do I add OpenAPI UI to a page?

Add a div with the id openapi-ui-container and a spec-url attribute, then load the UMD script from the CDN. The spec-url can be a full path or a path relative to the page, and a theme attribute of light or dark is supported.

### How does openapi-ui mock request parameters?

If the schema contains the format field, openapi-sampler is used to mock the request params. If the schema does not contain the format field, faker is used to mock the request params instead.

### Which specification formats does openapi-ui support?

It supports swagger2.json and swagger2.yml as well as openapi3.json and openapi3.yml. The swagger2openapi dependency converts Swagger 2 documents in the browser, and a document can be loaded from a gateway URL, uploaded as a file, or pasted as text.

### How do I deploy openapi-ui with Docker?

Pull ghcr.io/rookie-luochao/openapi-ui:latest and run it with a port mapping, for example docker run -d -p 8081:80 ghcr.io/rookie-luochao/openapi-ui:latest. Configuration is injected with environment variables such as APP_CONFIG, and the image serves the built static files through nginx.

### What license is openapi-ui released under?

The project is MIT licensed, with the LICENSE file at the root of the repository. The npm package openapi-ui-dist is at version 2.3.3, and the last push to the repository was on 2026-06-18.

## Sources

- [License: MIT](https://github.com/rookie-luochao/openapi-ui/blob/master/LICENSE)
- [Project website](https://openapi-ui.vercel.app/service/findPetsByStatus?serviceURL=https%3A%2F%2Fpetstore3.swagger.io%2Fapi%2Fv3%2Fopenapi.json&importModeType=url)
- [README](https://github.com/rookie-luochao/openapi-ui/blob/master/README.md)
- [Releases](https://github.com/rookie-luochao/openapi-ui/releases)
- [rookie-luochao/openapi-ui on GitHub](https://github.com/rookie-luochao/openapi-ui)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/rookie-luochao-openapi-ui
