Skip to content

Commit

Permalink
Replace PR workflow with a release draft, rename OpenSearch.openapi.y…
Browse files Browse the repository at this point in the history
…aml to opensearch-openapi.yaml. (#213)

* Replace PR workflow with a release draft.

Signed-off-by: dblock <[email protected]>

* Rename OpenSearch.openapi.yaml to opensearch-openapi.yaml.

Signed-off-by: dblock <[email protected]>

---------

Signed-off-by: dblock <[email protected]>
  • Loading branch information
dblock authored Apr 2, 2024
1 parent 4fe2b42 commit 83fdfbb
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 41,452 deletions.
49 changes: 0 additions & 49 deletions .github/workflows/build-single-file-specs.yml

This file was deleted.

45 changes: 45 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Build and Publish Spec

on:
push:
branches:
- main

jobs:
build:
name: Build and Publish
runs-on: ubuntu-latest
permissions: write-all

steps:
- name: Checkout the repo
uses: actions/checkout@v3

- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '20'

- name: Build
working-directory: ./tools
run: |-
mkdir -p ../build
npm install
export ROOT_PATH=../spec/opensearch-openapi.yaml
export OUTPUT_PATH=../build/opensearch-openapi.yaml
npm run merge -- $ROOT_PATH $OUTPUT_PATH
- name: Extract Branch Name
id: branch
shell: bash
run: echo "name=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT

- uses: marvinpinto/[email protected]
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
automatic_release_tag: ${{ steps.branch.outputs.name }}
prerelease: true
title: OpenSearch OpenAPI Spec (${{ steps.branch.outputs.name }})
files: |
LICENSE.txt
build/*
17 changes: 9 additions & 8 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ jobs:
- name: Build Spec
working-directory: ./tools
run: |-
mkdir -p ../build
npm install
export ROOT_PATH=../spec/OpenSearch.openapi.yaml
export OUTPUT_PATH=../builds/OpenSearch.latest.yaml
export ROOT_PATH=../spec/opensearch-openapi.yaml
export OUTPUT_PATH=../build/opensearch-openapi.yaml
npm run merge -- $ROOT_PATH $OUTPUT_PATH
- name: Build and Run Docker Container
run: |
Expand All @@ -33,20 +34,20 @@ jobs:
curl -ks -u "admin:$OPENSEARCH_INITIAL_ADMIN_PASSWORD" https://localhost:9200/ | jq
- name: Dump and Compare API
run: |
curl -ks -u "admin:$OPENSEARCH_INITIAL_ADMIN_PASSWORD" https://localhost:9200/_plugins/api | jq > ./builds/OpenSearch.current.json
docker run --rm --mount type=bind,source=./builds,target=/builds openapitools/openapi-diff:latest /builds/OpenSearch.latest.yaml /builds/OpenSearch.current.json --json /builds/diff.json
curl -ks -u "admin:$OPENSEARCH_INITIAL_ADMIN_PASSWORD" https://localhost:9200/_plugins/api | jq > ./build/local-openapi.json
docker run --rm --mount type=bind,source=./build,target=/build openapitools/openapi-diff:latest /build/opensearch-openapi.yaml /build/local-openapi.json --json /build/diff.json
- name: Show Diff
run: |
echo "-------- Missing APIs"
jq -r '.newEndpoints | group_by(.pathUrl)[] | "\(.[0].pathUrl): \([.[].method])"' builds/diff.json
jq -r '.newEndpoints | group_by(.pathUrl)[] | "\(.[0].pathUrl): \([.[].method])"' build/diff.json
echo "-------- Legacy APIs"
jq -r '.missingEndpoints | group_by(.pathUrl)[] | "\(.[0].pathUrl): \([.[].method])"' builds/diff.json
jq -r '.missingEndpoints | group_by(.pathUrl)[] | "\(.[0].pathUrl): \([.[].method])"' build/diff.json
- name: Gather Coverage
id: coverage
shell: bash
run: |
current=`docker run --rm -i mikefarah/yq:latest -r '.paths | keys | length' < builds/OpenSearch.latest.yaml`
total=`jq -r '.paths | keys | length' builds/OpenSearch.current.json`
current=`docker run --rm -i mikefarah/yq:latest -r '.paths | keys | length' < build/opensearch-openapi.yaml`
total=`jq -r '.paths | keys | length' build/local-openapi.json`
percent=$((current * 100 / total))
echo "API specs implemented for $current/$total ($percent%) APIs."
cat >>"$GITHUB_OUTPUT" <<EOL
Expand Down
4 changes: 2 additions & 2 deletions CLIENT_GENERATOR_GUIDE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Generate Clients for OpenSearch using OpenAPI Specification

OpenSearch Clients are available in multiple programming languages. The biggest challenge with this is keeping the clients up to date with the latest changes in OpenSearch. To solve this problem, we're automating the process of generating clients for OpenSearch using the OpenAPI specification. While OpenAPI comes with many well established off-the-shelf client generators for most languages, the OpenSearch APIs come with a lot of quirkiness that makes it near impossible to use these off-the-shelf generators. For this reason, we've opted to write our own client generators that is specifically tailored to the OpenSearch APIs. This document will walk you through the process of generating clients from [OpenSearch OpenAPI spec](builds/OpenSearch.latest.yaml), more specifically client API methods.
OpenSearch Clients are available in multiple programming languages. The biggest challenge with this is keeping the clients up to date with the latest changes in OpenSearch. To solve this problem, we're automating the process of generating clients for OpenSearch using the OpenAPI specification. While OpenAPI comes with many well established off-the-shelf client generators for most languages, the OpenSearch APIs come with a lot of quirkiness that makes it near impossible to use these off-the-shelf generators. For this reason, we've opted to write our own client generators that is specifically tailored to the OpenSearch APIs. This document will walk you through the process of generating clients from [the published OpenSearch OpenAPI spec](https://github.com/opensearch-project/opensearch-api-specification/releases), more specifically client API methods.

## The Grouping of API Operations
The OpenSearch clients, though written in different languages for different frameworks, share one distinct characteristic: API Operations are grouped into actions and namespaces. Operations serving the same functionality are often grouped together into a single API Action, which is represented in the client as an API method.
Expand All @@ -17,7 +17,7 @@ The **indices.get_field_mapping**, is consisted of 2 operations:

In a client, the `search` operations are grouped in to a single API method, `client.search(...)`, and the `indices.get_field_mapping` operations are grouped into a single API method, `get_field_mapping` of the `indices` namespace, `client.indices.get_field_mapping(...)`

In the [OpenAPI spec](./builds/OpenSearch.latest.yaml), this grouping is denoted by `x-operation-group` vendor extension in every operation definition. The value of this extension is the name of the API action (like `search` or `indices.get_field_mapping`). Operations with the same `x-operation-group` value are guaranteed to have the same query string parameters, response body, and request body (for PUT/POST/DELETE operations). Common path parameters are also guaranteed to be the same. The only differences between operations are the HTTP method and the path. With that in mind, below are rules on how to combine operations of different HTTP methods and path compositions.
In the [published OpenAPI spec](https://github.com/opensearch-project/opensearch-api-specification/releases), this grouping is denoted by `x-operation-group` vendor extension in every operation definition. The value of this extension is the name of the API action (like `search` or `indices.get_field_mapping`). Operations with the same `x-operation-group` value are guaranteed to have the same query string parameters, response body, and request body (for PUT/POST/DELETE operations). Common path parameters are also guaranteed to be the same. The only differences between operations are the HTTP method and the path. With that in mind, below are rules on how to combine operations of different HTTP methods and path compositions.

- If an operation is marked with `x-ignorable: "true"`, then ignore the operation. Such an operation has been deprecated and has been replaced by a newer one. As far as the clients are concerned, ignorable operations do not exist.
- If two operations have identical HTTP methods, but different paths: use the path that best matches the path parameters provided.
Expand Down
30 changes: 19 additions & 11 deletions DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,22 @@
- [Linting](#linting)

# Developer Guide

Welcome to the ```opensearch-api-specification``` developer guide! Glad you want to contribute. Here are the things you need to know while getting started!

## Getting Started

Fork [opensearch-api-specification](https://github.com/opensearch-project/opensearch-api-specification) repository to your GitHub account and clone it to your local machine. Whenever you're drafting a change, create a new branch for the change on your fork instead of on the upstream repository.
Fork the [opensearch-api-specification](https://github.com/opensearch-project/opensearch-api-specification) repository to your GitHub account and clone it to your local machine. Whenever you're drafting a change, create a new branch for the change on your fork instead of on the upstream repository.

The Specification is written in OpenAPI 3, so understanding the OpenAPI 3 specification is a must. If you are new to OpenAPI, you can start by reading the [OpenAPI 3 Specification](https://swagger.io/specification/).

## File Structure
To make editing the specification easier, we split the OpenAPI spec into multiple files that can be found in the `spec` directory. The file structure is as follows:
- The API Operations are grouped by namespaces in `spec/namespaces` directory. Each `yaml` file in this directory represents a namespace and holds all paths and operations of the namespace.
- The data schemas are grouped by categories in `spec/schemas` directory. Each `yaml` file in this directory represents a category.
- The `OpenSearch.openapi.yaml` file is the OpenAPI root file that ties everything together.

To make editing the specification easier, we split the OpenAPI spec into multiple files that can be found in the [spec](spec) directory. The file structure is as follows:

- The API Operations are grouped by namespaces in [spec/namespaces](spec/namespaces/) directory. Each `.yaml` file in this directory represents a namespace and holds all paths and operations of the namespace.
- The data schemas are grouped by categories in [spec/schemas](spec/schemas/) directory. Each `.yaml` file in this directory represents a category.
- The [spec/opensearch-openapi.yaml](spec/opensearch-openapi.yaml) file is the OpenAPI root file that ties everything together.

```
spec
Expand All @@ -40,13 +43,14 @@ spec
│ ├── cat.aliases.yaml
│ └── ...
└── OpenSearch.openapi.yaml
└── opensearch-openapi.yaml
```
Every `yaml` file is a valid OpenAPI 3 document. This means that you can use any OpenAPI 3 compatible tool to view and edit the files, and IDEs with OpenAPI support will provide you with autocompletion and validation in real-time.
Every `.yaml` file is a valid OpenAPI 3 document. This means that you can use any OpenAPI 3 compatible tool to view and edit the files, and IDEs with OpenAPI support will provide you with autocompletion and validation in real-time.

## Grouping Operations

Each API action is composed of multiple operations. The `search` action, for example, is consisted of 4 operations:
Each API action is composed of multiple operations. The `search` action, for example, consists of 4 operations:

- `GET /_search`
- `POST /_search`
- `GET /{index}/_search`
Expand All @@ -56,11 +60,12 @@ To group these operations together in the `search` action, we mark them with the

Note that this extension tells the client generators that these operations serve identical purpose and should be grouped together in the same API method. This extension also tells the generators the namespace and the name of the API method. For example, operations with `x-operation-group` value of `indicies.create` will result in `client.indices.create()` method to be generated, while operation group of `search` will result in `client.search()` as it's part of the `_core` namespace.

For this reason, every operation MUST be accompanied by the `x-operation-group` extension, and operations in the same group MUST have identical descriptions, request and response bodies, and querystring parameters.
For this reason, every operation *must* be accompanied by the `x-operation-group` extension, and operations in the same group MUST have identical descriptions, request and response bodies, and query string parameters.

## Grouping Schemas

Schemas are grouped by categories to keep their names short and aid in client generation:
Schemas are grouped by categories to keep their names short and aid in client generation:

- `_common` category holds the common schemas that are used across multiple namespaces and features.
- `_common.<sub_category>` category holds the common schemas of a specific sub_category. (e.g. `_common.mapping`)
- `<namespace>._common` category holds the common schemas of a specific namespace. (e.g. `cat._common`, `_core._common`)
Expand All @@ -69,6 +74,7 @@ Schemas are grouped by categories to keep their names short and aid in client g
## OpenAPI Extensions

This repository includes several penAPI Specification Extensions to fill in any metadata not directly supported OpenAPI:

- `x-operation-group`: Used to group operations into API actions.
- `x-version-added`: OpenSearch version when the operation/parameter was added.
- `x-version-deprecated`: OpenSearch version when the operation/parameter was deprecated.
Expand All @@ -77,5 +83,7 @@ This repository includes several penAPI Specification Extensions to fill in any
- `x-ignorable`: Denotes that the operation should be ignored by the client generator. This is used in operation groups where some operations have been replaced by newer ones, but we still keep them in the specs because the server still supports them.

## Linting
[WORK IN PROGRESS]

[WORK IN PROGRESS](https://github.com/opensearch-project/opensearch-api-specification/issues/205)

We are working on a linter that will validate every `yaml` file in the `./spec` folder to assure that they follow the guidelines we have set. The linter will be run on every pull request to make sure that the changes are in line with the guidelines.
4 changes: 2 additions & 2 deletions PUBLISHING_SPECS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

## Publishing OpenSearch API Specs

* The [build-single-file-specs](.github/workflows/build-single-file-specs.yml) workflow raises a PR for the changes to the [./build/OpenSearch.latest.yaml](builds/OpenSearch.latest.yaml) whenever a change is made to the [spec folder](./spec).
* The updated OpenAPI specs are hosted on GitHub pages at https://opensearch-project.github.io/opensearch-api-specification/.
* The [build](.github/workflows/build.yml) workflow publishes [a release draft](https://github.com/opensearch-project/opensearch-api-specification/releases) whenever a change is pushed to `main`.
* The updated OpenAPI specs are hosted on GitHub pages at https://opensearch-project.github.io/opensearch-api-specification/.
Loading

0 comments on commit 83fdfbb

Please sign in to comment.