Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Stoplight Elements to render OpenAPI docs #693

Merged
merged 8 commits into from
Jun 5, 2024
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
21 changes: 10 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ jobs:
- name: Run ameba
run: ameba/bin/ameba src spec

js-lint:
lint-js:
name: Lint javascript
runs-on: ubuntu-latest
continue-on-error: true
Expand All @@ -62,21 +62,20 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: latest
- name: Setup node
run: npm install -g standard
- name: Run standard
run: standard static/js
run: make lint-js

api-lint:
name: Lint and build HTTP API documentation
lint-openapi:
name: Lint OpenAPI
runs-on: ubuntu-latest
continue-on-error: true
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Lint and build HTTP API documentation
run: make docs
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: latest
- name: Run spectral
run: make lint-openapi

spec:
name: Spec
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
/lib/
/bin/
/node_modules/
/static/docs/
/static/js/lib/
/tmp/
*.log
Expand Down
10 changes: 0 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,10 @@ COPY .ameba.yml .
RUN bin/ameba
RUN crystal tool format --check

# Build docs in npm container
FROM node:lts AS docbuilder
WORKDIR /tmp
RUN npm install redoc-cli @stoplight/spectral-cli
COPY Makefile shard.yml .
COPY openapi openapi
RUN make docs

# Build
FROM base AS builder
COPY Makefile .
RUN make js lib
COPY --from=docbuilder /tmp/openapi/openapi.yaml /tmp/openapi/.spectral.json openapi/
COPY --from=docbuilder /tmp/static/docs/index.html static/docs/index.html
ARG MAKEFLAGS=-j2
RUN make all bin/lavinmq-debug

Expand Down
4 changes: 1 addition & 3 deletions Dockerfile.deb
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
ARG build_image=84codes/crystal:latest-ubuntu-20.04

FROM $build_image AS builder
RUN curl -fsSL https://deb.nodesource.com/setup_19.x | bash -
RUN apt-get install -y devscripts nodejs help2man lintian debhelper liblz4-dev
RUN apt-get update && apt-get install -y devscripts help2man lintian debhelper liblz4-dev
ARG version
WORKDIR /usr/src/lavinmq_${version}
COPY Makefile README.md LICENSE NOTICE CHANGELOG.md shard.yml shard.lock ./
COPY extras/lavinmq.service extras/lavinmq.ini extras/
COPY openapi/ openapi/
COPY static/ static/
COPY views/ views/
COPY src/ src/
Expand Down
3 changes: 1 addition & 2 deletions Dockerfile.rpm
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ ARG build_image=84codes/crystal:latest-fedora-39

FROM $build_image AS builder
RUN dnf install -y --nodocs --setopt=install_weak_deps=False \
rpmdevtools rpmlint systemd-rpm-macros /usr/bin/npm make help2man lz4-devel
rpmdevtools rpmlint systemd-rpm-macros make help2man lz4-devel
RUN rpmdev-setuptree
COPY lavinmq.spec /root/rpmbuild/SPECS/
ARG version
Expand All @@ -11,7 +11,6 @@ RUN rpmlint /root/rpmbuild/SPECS/lavinmq.spec
WORKDIR /usr/src/lavinmq
COPY Makefile README.md LICENSE NOTICE CHANGELOG.md shard.yml shard.lock ./
COPY extras/lavinmq.service extras/lavinmq.ini extras/
COPY openapi/ openapi/
COPY static/ static/
COPY views/ views/
COPY src/ src/
Expand Down
25 changes: 15 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
BINS := bin/lavinmq bin/lavinmqctl bin/lavinmqperf
SOURCES := $(shell find src/lavinmq src/stdlib -name '*.cr' 2> /dev/null)
JS := static/js/lib/chunks/helpers.segment.js static/js/lib/chart.js static/js/lib/amqp-websocket-client.mjs static/js/lib/amqp-websocket-client.mjs.map static/js/lib/luxon.js static/js/lib/chartjs-adapter-luxon.esm.js
DOCS := static/docs/index.html
JS := static/js/lib/chunks/helpers.segment.js static/js/lib/chart.js static/js/lib/amqp-websocket-client.mjs static/js/lib/amqp-websocket-client.mjs.map static/js/lib/luxon.js static/js/lib/chartjs-adapter-luxon.esm.js static/js/lib/elements-8.2.0.js static/js/lib/elements-8.2.0.css
CRYSTAL_FLAGS := --release
override CRYSTAL_FLAGS += --error-on-warnings --link-flags=-pie

Expand Down Expand Up @@ -44,9 +43,11 @@ static/js/lib/chartjs-adapter-luxon.esm.js: | static/js/lib
curl --retry 5 -sLo $@ https://cdn.jsdelivr.net/npm/[email protected]/dist/chartjs-adapter-luxon.esm.js
sed -i'' -e "s|\(import { _adapters } from\).*|\1 './chart.js'|; s|\(import { DateTime } from\).*|\1 './luxon.js'|" $@

static/docs/index.html: openapi/openapi.yaml openapi/.spectral.json $(wildcard openapi/paths/*.yaml) $(wildcard openapi/schemas/*.yaml)
npx --package=@stoplight/spectral-cli spectral --ruleset openapi/.spectral.json lint $<
npx @redocly/cli build-docs --output $@ $<
static/js/lib/elements-8.2.0.js: | static/js/lib
curl --retry 5 -sLo $@ https://unpkg.com/@stoplight/[email protected]/web-components.min.js

static/js/lib/elements-8.2.0.css: | static/js/lib
curl --retry 5 -sLo $@ https://unpkg.com/@stoplight/[email protected]/styles.min.css

man1/lavinmq.1: bin/lavinmq | man1
help2man -Nn "fast and advanced message queue server" $< -o $@
Expand All @@ -62,19 +63,23 @@ MANPAGES := man1/lavinmq.1 man1/lavinmqctl.1 man1/lavinmqperf.1
.PHONY: man
man: $(MANPAGES)

.PHONY: docs
docs: $(DOCS)

.PHONY: js
js: $(JS)

.PHONY: deps
deps: js lib docs
deps: js lib

.PHONY: lint
lint: lib
lib/ameba/bin/ameba src/
standard static/js

.PHONY: lint-js
lint-js:
npx standard static/js

.PHONY: lint-openapi
lint-openapi:
npx --package=@stoplight/spectral-cli spectral --ruleset openapi/.spectral.json lint static/docs/openapi.yaml

.PHONY: test
test: lib
Expand Down
2 changes: 1 addition & 1 deletion debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Standards-Version: 4.6.0
Homepage: https://github.com/cloudamqp/lavinmq
Section: net
Priority: optional
Build-Depends: debhelper (>= 12), crystal (>= 1.8.0), nodejs (>= 12), curl
Build-Depends: debhelper (>= 12), crystal (>= 1.8.0), curl
Maintainer: CloudAMQP <[email protected]>

Package: lavinmq
Expand Down
2 changes: 1 addition & 1 deletion lavinmq.spec
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Version: 1.0.0
Release: 1%{?dist}

License: ASL 2.0
BuildRequires: systemd-rpm-macros crystal npm curl help2man
BuildRequires: systemd-rpm-macros crystal curl help2man
Requires(pre): shadow-utils
URL: https://github.com/cloudamqp/lavinmq
Source: lavinmq.tar.gz
Expand Down
23 changes: 3 additions & 20 deletions openapi/README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,15 @@
# LavinMQ Management HTTP API OpenAPI spec
# LavinMQ HTTP API OpenAPI spec

Run `make docs` to build docs (calls `npx redoc-cli`).

It outputs to `static/docs/index.html` so you can view the docs at [http://localhost:15672/docs/](http://localhost:15672/docs/) if you have LavinMQ running.

The dependencies:

* [Spectral] is used to lint the documentation. To run it manually: `docker run --rm -it -v $(pwd):/tmp stoplight/spectral:6 --ruleset /tmp/openapi/.spectral.json lint openapi/openapi.yaml`
* [ReDoc] is to build the documentation.
To run it manually: `npx redoc-cli bundle openapi.yaml -o static/docs/index.html`

You can preview docs using:

```
npx redoc-cli serve openapi.yaml
```
OpenAPI docs rendered in browser using https://github.com/stoplightio/elements

(Note the gotcha: the browser caches the YAML files even if they have changed, open dev console in the browser to mitigate.)

## OpenAPI notes

* `summary` is the short description (used in the redoc menu for instance)
* `summary` is the short description
* `description` is a longer description (supports Markdown)

The following script was used to generate the OpenAPI Spec YAML structure

ruby openapi.rb

[Spectral]: https://github.com/stoplightio/spectral
[ReDoc]: https://github.com/Redocly/redoc
[ReDoc Docker image]: https://github.com/Redocly/redoc/tree/master/config/docker#official-redoc-docker-image
9 changes: 5 additions & 4 deletions openapi/openapi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ def ref
end
end

openapi_spec = YAML.load(File.read(File.join(__dir__, "openapi.yaml")))
docs_path = File.join("..", "static", "docs")
openapi_spec = YAML.load(File.read(File.join(__dir__, docs_path, "openapi.yaml")))
src_code_dir = File.expand_path(File.join(__dir__, ".."))
http_code_dir = File.join(src_code_dir, "src/lavinmq/http")
files = Dir.glob(File.join(http_code_dir, "**/*.cr"))
Expand Down Expand Up @@ -154,7 +155,7 @@ def ref
}

if WRITE
File.write(File.join(__dir__, Helper.schemas_path(tag_name)), YAML.dump(openapi_schemas))
File.write(File.join(__dir__, docs_path, Helper.schemas_path(tag_name)), YAML.dump(openapi_schemas))
end

schemas[tag_name] = { "$ref" => "./schemas/#{tag_name}.yaml#/#{tag_name}" }
Expand All @@ -171,7 +172,7 @@ def ref
end

if WRITE
File.write(File.join(__dir__, Helper.paths_path(src_file)), YAML.dump(openapi_routes))
File.write(File.join(__dir__, docs_path, Helper.paths_path(src_file)), YAML.dump(openapi_routes))
end
end

Expand All @@ -181,5 +182,5 @@ def ref
puts YAML.dump(openapi_spec) if DEBUG

if WRITE
File.write(File.join(__dir__, "openapi.yaml"), YAML.dump(openapi_spec))
File.write(File.join(__dir__, docs_path, "openapi.yaml"), YAML.dump(openapi_spec))
end
13 changes: 0 additions & 13 deletions openapi/redoc-serve-and-watch

This file was deleted.

3 changes: 2 additions & 1 deletion src/lavinmq/http/controller/static.cr
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,14 @@ module LavinMQ
when ".txt" then "text/plain;charset=utf-8"
when ".html" then "text/html;charset=utf-8"
when ".css" then "text/css;charset=utf-8"
when ".js", ".mjs" then "application/javascript;charset=utf-8"
when ".js", ".mjs" then "application/javascript"
when ".png" then "image/png"
when ".ico" then "image/x-icon"
when ".jpg" then "image/jpeg"
when ".gif" then "image/gif"
when ".svg" then "image/svg+xml"
when ".webp" then "image/webp"
when ".yaml" then "application/yaml"
else "application/octet-stream"
end
end
Expand Down
Empty file removed static/docs/.gitkeep
Empty file.
21 changes: 21 additions & 0 deletions static/docs/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>LavinMQ HTTP API</title>
<script src="../js/lib/elements-8.2.0.js"></script>
<link rel="stylesheet" href="../js/lib/elements-8.2.0.css">
</head>
<body>
<elements-api
apiDescriptionUrl="openapi.yaml"
router="hash"
layout="sidebar"
logo="../img/favicon.png"
tryItCredentialsPolicy="same-origin"
hideSchemas="true"
/>
</body>
</html>

7 changes: 3 additions & 4 deletions openapi/openapi.yaml → static/docs/openapi.yaml
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
---
openapi: 3.0.3
info:
version:
"$ref": "../shard.yml#/version"
title: LavinMQ Management HTTP API
version: v1.2.12
title: LavinMQ HTTP API
description: HTTP API to programmatically manage all aspects of LavinMQ.
contact:
name: LavinMQ Team
url: https://www.lavinmq.com/
email: [email protected]
servers:
- url: http://localhost:15672/api
- url: /api
components:
schemas:
ErrorResponse:
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading