<bmx-api-explorer>
An OpenAPI console in the page: point it at an API description - OpenAPI 3.0 or 3.1, JSON or YAML, or a Swagger 2.0 file - and it lists every operation by tag, documents each one (parameters, request body, every response and its schema as a field table), and lets the reader try it: fill in the parameters, edit the body (started from the example), authorize once, and send. The response comes back with its status, time, size, headers and pretty-printed body, checked against the documented schema.
15 properties · 5 events · 9 methods · 9 parts
Example
This example runs in mock mode: requests are answered from the description's own examples, so nothing leaves the page. Authorize with any key to get past the 401.
Show markup
<bmx-api-explorer id="ex-ae" mock selected="getOrder" style="--bmx-api-explorer-height: 46rem"></bmx-api-explorer>
<p class="note" id="ex-ae-out" role="status" style="margin: 12px 0 0">This example runs in <code>mock</code> mode: requests are answered from the description's own examples, so nothing leaves the page. Authorize with any key to get past the 401.</p>
<script type="text/yaml" id="ex-ae-spec">
openapi: 3.1.0
info:
title: Harbour & Pine Orders API
version: 2.3.0
description: |
Create, find and fulfil orders for the Harbour & Pine trade counter.
- Amounts are in **pence**, as integers.
- Times are UTC, in ISO 8601.
- Lists are paged with `limit` and `cursor`.
servers:
- url: https://sandbox.harbourpine.example/v2
description: Sandbox
- url: https://{region}.api.harbourpine.example/v2
description: Production
variables:
region:
default: eu
enum: [eu, uk, us]
tags:
- name: Orders
description: Orders placed by trade customers.
- name: Customers
description: Trade accounts and their credit limits.
security:
- apiKey: []
- bearer: []
paths:
/orders:
get:
tags: [Orders]
operationId: listOrders
summary: List orders
description: Newest first. Filter by status, customer or the date they were placed.
parameters:
- name: status
in: query
description: One or more statuses.
schema:
type: array
items: { type: string, enum: [open, paid, dispatched, cancelled] }
- name: customerId
in: query
schema: { type: string, example: CUS-2041 }
- name: placedAfter
in: query
schema: { type: string, format: date }
- name: limit
in: query
schema: { type: integer, minimum: 1, maximum: 100, default: 25 }
- name: cursor
in: query
description: The `nextCursor` of the previous page.
schema: { type: string }
responses:
'200':
description: A page of orders
headers:
X-RateLimit-Remaining:
description: Requests left this minute
schema: { type: integer }
content:
application/json:
schema:
type: object
required: [items]
properties:
items:
type: array
items: { $ref: '#/components/schemas/Order' }
nextCursor: { type: [string, 'null'] }
example:
items:
- id: ORD-10482
customerId: CUS-2041
status: paid
placedAt: 2026-10-14T09:12:00Z
currency: GBP
lines: [{ sku: OAK-SHELF-90, description: Oak shelf 90 cm, quantity: 4, unitPrice: 4250 }]
total: 17000
nextCursor: eyJwIjoyfQ
'401': { $ref: '#/components/responses/Unauthorized' }
post:
tags: [Orders]
operationId: createOrder
summary: Place an order
description: The order is checked against the customer's credit limit before it is accepted.
parameters:
- name: Idempotency-Key
in: header
description: Send the same key to retry safely; the order is placed once.
schema: { type: string, format: uuid }
requestBody:
required: true
content:
application/json:
schema: { $ref: '#/components/schemas/NewOrder' }
examples:
shelves:
summary: Four oak shelves
value: { customerId: CUS-2041, lines: [{ sku: OAK-SHELF-90, quantity: 4 }] }
mixed:
summary: A mixed order with a note
value: { customerId: CUS-2041, note: Deliver to the side gate, lines: [{ sku: OAK-SHELF-90, quantity: 2 }, { sku: PINE-DESK-140, quantity: 1 }] }
responses:
'201':
description: Placed
content:
application/json:
schema: { $ref: '#/components/schemas/Order' }
example:
id: ORD-10483
customerId: CUS-2041
status: open
placedAt: 2026-10-15T08:30:00Z
currency: GBP
lines: [{ sku: OAK-SHELF-90, description: Oak shelf 90 cm, quantity: 4, unitPrice: 4250 }]
total: 17000
'422':
description: Over the credit limit, or an unknown product
content:
application/json:
schema: { $ref: '#/components/schemas/Problem' }
'401': { $ref: '#/components/responses/Unauthorized' }
/orders/{orderId}:
parameters:
- name: orderId
in: path
required: true
schema: { type: string, pattern: '^ORD-[0-9]+$' }
example: ORD-10482
get:
tags: [Orders]
operationId: getOrder
summary: Find an order
responses:
'200':
description: The order
content:
application/json:
schema: { $ref: '#/components/schemas/Order' }
example:
id: ORD-10482
customerId: CUS-2041
status: paid
placedAt: 2026-10-14T09:12:00Z
currency: GBP
lines: [{ sku: OAK-SHELF-90, description: Oak shelf 90 cm, quantity: 4, unitPrice: 4250 }]
total: 17000
'404':
description: No such order
content:
application/json:
schema: { $ref: '#/components/schemas/Problem' }
delete:
tags: [Orders]
operationId: cancelOrder
summary: Cancel an order
description: Only an order that has not been dispatched can be cancelled.
responses:
'204': { description: Cancelled }
'409':
description: Already dispatched
content:
application/json:
schema: { $ref: '#/components/schemas/Problem' }
/orders/{orderId}/dispatch:
post:
tags: [Orders]
operationId: dispatchOrder
summary: Mark an order dispatched
parameters:
- name: orderId
in: path
required: true
schema: { type: string }
example: ORD-10482
requestBody:
content:
application/json:
schema:
type: object
properties:
carrier: { type: string, enum: [Parcelpoint, Northline, Collection] }
tracking: { type: string, maxLength: 40 }
responses:
'200':
description: Dispatched
content:
application/json:
schema: { $ref: '#/components/schemas/Order' }
/customers/{customerId}:
get:
tags: [Customers]
operationId: getCustomer
summary: Find a trade customer
parameters:
- name: customerId
in: path
required: true
schema: { type: string }
example: CUS-2041
responses:
'200':
description: The customer
content:
application/json:
schema: { $ref: '#/components/schemas/Customer' }
example: { id: CUS-2041, name: Fenwick Joinery Ltd, email: accounts@fenwick-joinery.example, creditLimit: 500000, balance: 128400 }
/health:
get:
summary: Health check
security: []
responses:
'204': { description: The API is up }
components:
securitySchemes:
apiKey:
type: apiKey
in: header
name: X-Api-Key
description: Your key from the trade portal's Developer page.
bearer:
type: http
scheme: bearer
bearerFormat: JWT
responses:
Unauthorized:
description: No key, or a key that has been revoked
content:
application/json:
schema: { $ref: '#/components/schemas/Problem' }
schemas:
NewOrder:
type: object
required: [customerId, lines]
properties:
customerId: { type: string, example: CUS-2041 }
note: { type: string, maxLength: 200, description: Shown on the delivery note }
lines:
type: array
minItems: 1
items:
type: object
required: [sku, quantity]
properties:
sku: { type: string, example: OAK-SHELF-90 }
quantity: { type: integer, minimum: 1, maximum: 999 }
Order:
type: object
required: [id, customerId, status, placedAt, lines, total]
properties:
id: { type: string, readOnly: true, example: ORD-10482 }
customerId: { type: string }
status: { type: string, enum: [open, paid, dispatched, cancelled] }
placedAt: { type: string, format: date-time }
currency: { type: string, default: GBP }
lines:
type: array
items:
type: object
properties:
sku: { type: string }
description: { type: string }
quantity: { type: integer }
unitPrice: { type: integer, description: In pence }
total: { type: integer, description: 'In pence, including VAT' }
Customer:
type: object
properties:
id: { type: string }
name: { type: string }
email: { type: string, format: email }
creditLimit: { type: integer, description: In pence }
balance: { type: integer, description: 'Owed now, in pence' }
Problem:
type: object
properties:
title: { type: string }
detail: { type: string }
</script>
<script type="module">
await customElements.whenDefined('bmx-api-explorer');
const explorer = document.getElementById('ex-ae');
const out = document.getElementById('ex-ae-out');
explorer.spec = document.getElementById('ex-ae-spec').textContent;
explorer.addEventListener('bmxResponse', e => {
const { operation, response, problems, error } = e.detail;
out.textContent = error ? `bmxResponse: ${error}` : `bmxResponse: ${operation.key} answered ${response.status} in ${response.duration} ms${problems.length ? `, ${problems.length} differences from the schema` : ''}.`;
});
</script>
<bmx-api-explorer spec-url="/openapi.yaml"></bmx-api-explorer>
Every request also appears as code - cURL, JavaScript, C# and Python - with
the credentials replaced by placeholders, so a sample can be pasted into a
ticket without a live key. mock answers from the description's own
examples instead of a server (400 for bad input, 401 without credentials),
for a developer portal before the API is live, or for a demonstration.
fetcher sends through the page's own code (a proxy, a test double), and
bmxRequest can be cancelled to send the request yourself.
Nothing is stored and nothing is sent anywhere but to the API: credentials
live in memory until the page is closed (bmxAuthChange hands them over if
the page wants to keep them, which it must do safely). A request goes
straight from the reader's browser, so the API must allow it (CORS).
The list of operations is a navigation landmark with one tab stop (arrow keys move, Enter opens); every field is a labelled form control, mistakes are marked on the field and announced, Ctrl+Enter (Command+Enter) sends, and the response status is announced when it arrives.
Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
credentials |
property only | BmxApiCredentials |
{} |
Credentials to start with, by security scheme id (from script). Mutable: the reader's changes are written back. |
fetcher |
property only | BmxApiFetcher |
— | Sends requests instead of fetch (from script). |
headingLevel |
heading-level |
number |
2 |
The level of the operation's heading (1 to 5); sections are one below. |
label |
label |
string |
— | The element's accessible name. Default: the API's title. |
languages |
languages |
BmxApiLanguage[] | string |
[...LANGUAGES] |
The code sample languages offered, in order: curl, javascript, csharp, python. |
mock |
mock |
boolean |
false |
Answer from the description's examples instead of sending anything. |
requestHeaders |
request-headers |
Record<string, string> | string |
— | Headers every request carries, as an object or JSON (a tenant id, a trace header). |
revealSecrets |
reveal-secrets |
boolean |
false |
Show credentials in code samples instead of placeholders. |
selected |
selected |
string |
'' |
The chosen operation: GET /orders/{id} or an operationId. Empty shows the overview. Mutable. |
server |
server |
string |
'' |
The chosen server (its URL as the description writes it, or its index). Mutable. |
spec |
spec |
Record<string, unknown> | string |
— | The API description: an object, or JSON or YAML text. |
specUrl |
spec-url |
string |
— | Where to fetch the description from (JSON or YAML), when spec is not set. |
strings |
strings |
Partial<BmxApiExplorerStrings> | string |
— | Words to show instead of the English ones, as an object or JSON. |
timeout |
timeout |
number |
30000 |
Milliseconds before a request is given up. |
tryIt |
try-it |
boolean |
true |
Show the Send button and the editable fields. False makes it read-only documentation. |
Events
| Event | Detail | Description |
|---|---|---|
bmxAuthChange |
BmxApiAuthDetail |
Fired when the reader changes the credentials. |
bmxLoad |
BmxApiLoadDetail |
Fired when the description has been read. |
bmxRequest |
BmxApiRequestDetail |
Fired before a request is sent. Cancel it to send the request yourself. |
bmxResponse |
BmxApiResponseDetail |
Fired when a response arrives, or the request fails. |
bmxSelect |
BmxApiSelectDetail |
Fired when the reader chooses an operation. |
Methods
| Method | Signature | Description |
|---|---|---|
clearCredentials |
clearCredentials() => Promise<void> |
Forgets every credential. |
getRequest |
getRequest() => Promise<BmxApiRequest | undefined> |
The request the chosen operation would send now. |
getSnippet |
getSnippet(language?: BmxApiLanguage) => Promise<string> |
A code sample of the chosen operation's request (credentials as placeholders unless reveal-secrets). |
getSpec |
getSpec() => Promise<BmxApiSpec | null> |
The description as read (null until it is). |
selectOperation |
selectOperation(id: string) => Promise<boolean> |
Chooses an operation by key or operationId; empty shows the overview. Resolves whether it was found. |
send |
send() => Promise<BmxApiResponseData | undefined> |
Sends the chosen operation's request as filled in. Resolves with the response (undefined when it failed or was cancelled). |
setCredentials |
setCredentials(credentials: BmxApiCredentials) => Promise<void> |
Sets the credentials (merged with those set). |
setFocus |
setFocus() => Promise<void> |
Focuses the list of operations. |
setValue |
setValue(param: string, value: string, operation?: string) => Promise<void> |
Sets a parameter's value for an operation (default: the chosen one), by in:name (query:limit). |
CSS shadow parts
| Part | Description |
|---|---|
code |
A code sample. |
detail |
The chosen operation, or the overview. |
method |
A method badge (GET, POST...). |
nav |
The list of operations. |
operation |
One operation in the list; also operation-selected. |
response |
The response panel. |
section |
A section of the detail (parameters, body, responses, code). |
send |
The Send button. |
sidebar |
The column with the server, authorization and operations. |
CSS custom properties
| Property | Description |
|---|---|
--bmx-api-explorer-background |
The detail pane's background. |
--bmx-api-explorer-code-background |
The background of code samples and response bodies. |
--bmx-api-explorer-code-font-size |
The font size of code. |
--bmx-api-explorer-height |
The element's height (each column scrolls inside it); auto lets it grow with the page. |
--bmx-api-explorer-radius |
Corner radius of the element and its panels. |
--bmx-api-explorer-sidebar-background |
The operations column's background. |
--bmx-api-explorer-sidebar-width |
The operations column's width. |