Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions demo/apis.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@
"agents-api/agents-api.yaml": { "type": "OAS 3.0", "mime": "application/yaml" },
"tags-flights/tags-flights.yml": { "type": "OAS 3.0", "mime": "application/yaml" },
"oas32-query/oas32-query.yaml": { "type": "OAS 3.2", "mime": "application/yaml" },
"oas31-webhooks/oas31-webhooks.yaml": { "type": "OAS 3.1", "mime": "application/yaml" },
"grpc-test.json": { "type": "gRPC", "mime": "application/json" }
}
1 change: 1 addition & 0 deletions demo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class ApiDemo extends ApiDemoPage {
["APIC-641", "APIC-641"],
["W-10881270", "W-10881270"],
["oas32-query", "OAS 3.2 (QUERY)"],
["oas31-webhooks", "OAS 3.1 (Webhooks)"],
].map(
([file, label]) => html`
<anypoint-item data-src="${file}-compact.json">${label}</anypoint-item>
Expand Down
136 changes: 136 additions & 0 deletions demo/oas31-webhooks/oas31-webhooks.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
openapi: 3.1.0
info:
title: Webhooks + Schema Composition Spike
version: 1.0.0
paths:
/pets:
get:
operationId: listPets
summary: List pets
responses:
"200":
description: A list of pets
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Pet"

# Top-level `webhooks` map of Path Item Objects, confirmed in OAS 3.1.0 spec
# (versions/3.1.0.md, field `webhooks`, sibling to `paths`/`components`).
webhooks:
newPet:
post:
operationId: newPetWebhook
summary: Notify subscriber of a newly created pet
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
responses:
"200":
description: Webhook received successfully

components:
schemas:
Pet:
# allOf: base fields + discriminated extra fields
allOf:
- $ref: "#/components/schemas/PetBase"
- $ref: "#/components/schemas/PetKindFields"

PetBase:
type: object
required: [id, name]
properties:
id:
type: integer
name:
type: string
kind:
type: string
enum: [dog, cat]

# if/then/else conditional (JSON Schema 2020-12, dialect used by OAS 3.1)
PetKindFields:
if:
properties:
kind:
const: dog
then:
properties:
breed:
type: string
required: [breed]
else:
properties:
indoor:
type: boolean
required: [indoor]

# oneOf: mutually exclusive contact methods
ContactMethod:
oneOf:
- $ref: "#/components/schemas/EmailContact"
- $ref: "#/components/schemas/PhoneContact"

EmailContact:
type: object
required: [email]
properties:
email:
type: string
format: email

PhoneContact:
type: object
required: [phone]
properties:
phone:
type: string

# anyOf: owner may have one or more identifiers present
OwnerIdentifiers:
anyOf:
- required: [ownerId]
properties:
ownerId:
type: integer
- required: [ownerEmail]
properties:
ownerEmail:
type: string
format: email

# oneOf with inline anonymous object members (no $ref). AMF assigns synthetic
# names (item0/item1); the component must render positional "Option N" labels.
InlineChoice:
oneOf:
- type: object
properties:
a:
type: string
- type: object
properties:
b:
type: integer

# oneOf whose first member is an inline anonymous scalar. The synthetic name
# must be replaced by the datatype label ("String").
ScalarChoice:
oneOf:
- type: string
- type: integer

# allOf mixing a named $ref (PetBase, preserved) with an inline anonymous
# member (synthetic name -> label nulled).
MixedAllOf:
allOf:
- $ref: "#/components/schemas/PetBase"
- type: object
properties:
extra:
type: string
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@api-components/api-summary",
"description": "A summary view for an API base on AMF data model",
"version": "4.6.20",
"version": "4.6.21",
"license": "Apache-2.0",
"main": "index.js",
"module": "index.js",
Expand All @@ -28,7 +28,7 @@
"@advanced-rest-client/arc-marked": "^1.1.2",
"@advanced-rest-client/icons": "^4.0.2",
"@advanced-rest-client/markdown-styles": "^3.1.5",
"@api-components/amf-helper-mixin": "^4.5.36",
"@api-components/amf-helper-mixin": "^4.5.38",
"@api-components/api-method-documentation": "^5.2.5",
"@api-components/api-model-generator": "^0.4.0",
"@api-components/http-method-label": "^3.1.4",
Expand Down
9 changes: 9 additions & 0 deletions src/ApiSummary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export declare class ApiSummary extends AmfHelperMixin(LitElement) {
_licenseName: string;
_licenseUrl: string;
_endpoints: any[];
_webhooks: any[];
_termsOfService: string;
_version: string;
_apiTitle: string;
Expand Down Expand Up @@ -96,6 +97,12 @@ export declare class ApiSummary extends AmfHelperMixin(LitElement) {
*/
_computeEndpoints(webApi: any): any[]|undefined;

/**
* Computes view model for the webhooks list (OAS 3.1/3.2 top-level webhooks).
* @param webApi Web API model
*/
_computeWebhooks(webApi: any): any[]|undefined;

/**
* Computes a view model for supported operations for an endpoint.
* @param {any} endpoint Endpoint model.
Expand Down Expand Up @@ -142,6 +149,8 @@ export declare class ApiSummary extends AmfHelperMixin(LitElement) {

_endpointsTemplate(): TemplateResult|string;

_webhooksTemplate(): TemplateResult|string;

_endpointTemplate(item): TemplateResult|string;

_endpointPathTemplate(item): TemplateResult;
Expand Down
65 changes: 64 additions & 1 deletion src/ApiSummary.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export class ApiSummary extends AmfHelperMixin(LitElement) {
_licenseName: { type: String },
_licenseUrl: { type: String },
_endpoints: { type: Array },
_webhooks: { type: Array },
_termsOfService: { type: String },
_version: { type: String },
_apiTitle: { type: String },
Expand Down Expand Up @@ -134,6 +135,7 @@ export class ApiSummary extends AmfHelperMixin(LitElement) {
this._version = undefined;
this._termsOfService = undefined;
this._endpoints = undefined;
this._webhooks = undefined;

this._providerName = undefined;
this._providerEmail = undefined;
Expand All @@ -149,6 +151,7 @@ export class ApiSummary extends AmfHelperMixin(LitElement) {
this._version = this._computeVersion(webApi);
this._termsOfService = this._computeToS(webApi);
this._endpoints = this._computeEndpoints(webApi);
this._webhooks = this._computeWebhooks(webApi);

const provider = this._computeProvider(webApi);
this._providerName = this._computeName(provider);
Expand Down Expand Up @@ -318,6 +321,45 @@ export class ApiSummary extends AmfHelperMixin(LitElement) {
});
}

/**
* Computes view model for the webhooks list (OAS 3.1/3.2 top-level webhooks).
* Webhooks are `apiContract#EndPoint` nodes — the same shape as endpoints — so
* they reuse the endpoint item view model and `_endpointTemplate` for rendering.
* @param {any} webApi Web API model
* @return {any[]|undefined}
*/
_computeWebhooks(webApi) {
if (!webApi) {
return undefined;
}
const key = this._getAmfKey(this.ns.aml.vocabularies.apiContract.webhooks);
const webhooks = this._ensureArray(webApi[key]);
if (!webhooks || !webhooks.length) {
return undefined;
}
return webhooks.map((item) => {
const path = this._getValue(
item,
this.ns.aml.vocabularies.apiContract.path
);
const name = this._getValue(item, this.ns.aml.vocabularies.core.name);
const pathStr = typeof path === "string" ? path : `/${name || ""}`;
const supportedOperations = this._endpointOperations(item);
const webhookDisplayInfo = this._computeEndpointName(
item,
webApi,
supportedOperations
);
return {
name: webhookDisplayInfo?.name,
description: webhookDisplayInfo?.description,
path: pathStr,
id: item["@id"],
ops: supportedOperations,
};
});
}

/**
* Computes a descriptive name for an endpoint based on its operations and tags.
* @param {any} endpoint Endpoint model
Expand Down Expand Up @@ -637,7 +679,8 @@ export class ApiSummary extends AmfHelperMixin(LitElement) {
${this._licenseTemplate()} ${this._termsOfServiceTemplate()}
</div>

${this.hideToc ? "" : this._endpointsTemplate()} `;
${this.hideToc ? "" : this._endpointsTemplate()}
${this.hideToc ? "" : this._webhooksTemplate()} `;
}

_titleTemplate() {
Expand Down Expand Up @@ -879,6 +922,26 @@ export class ApiSummary extends AmfHelperMixin(LitElement) {
`;
}

/**
* @return {TemplateResult|string} A template for the top-level webhooks list
* (OAS 3.1/3.2). Webhooks share the endpoint item shape, so each renders with
* the same `_endpointTemplate`.
*/
_webhooksTemplate() {
const { _webhooks } = this;
if (!_webhooks || !_webhooks.length) {
return "";
}
const result = _webhooks.map((item) => this._endpointTemplate(item));
return html`
<div class="separator" part="separator"></div>
<div class="toc" part="toc">
<label class="section webhooks-title">Webhooks</label>
${result}
</div>
`;
}

_endpointTemplate(item) {
const ops =
item.ops && item.ops.length
Expand Down
3 changes: 2 additions & 1 deletion src/Styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@ export default css`
font-size: var(--api-summary-section-title-font-size);
}

.section.endpoints-title {
.section.endpoints-title,
.section.webhooks-title {
font-weight: var(--arc-font-title-font-weight, 500);
color: var(--arc-font-title-color);
font-weight: var(--arc-font-title-font-weight);
Expand Down
Loading
Loading