Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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
20 changes: 18 additions & 2 deletions .githooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,26 @@ if [ -z "$changed" ]
then
exit 0
else
# check required tools
for tool in swag jq yq api-spec-converter openapi; do
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially fixed. Tool checks were added, but openapi is now required in preflight and still not pinned in mise.toml. Please add it so mise install matches the hook requirements.

command -v "$tool" >/dev/null 2>&1 || { echo "❌ $tool not found. Install with 'mise install' or manually:"; echo " swag: go install github.com/swaggo/swag/cmd/swag@latest"; echo " jq: brew install jq"; echo " yq: brew install yq"; echo " api-spec-converter: npm install -g api-spec-converter"; echo " openapi: go install github.com/speakeasy-api/openapi/cmd/openapi@latest"; exit 1; }
done

# regenerate docs
swag init --generatedTime --parseDependency --parseInternal -g handlers/main.go -d api/ api/*
go run docs/annotate_dtos/main.go
swag init --generatedTime --parseDependency --parseDependencyLevel 3 --parseInternal -g handlers/main.go -d api/ api/*
swag fmt -d ./api
go run v3gen/main.go
bash docs/fix_openapi_spec.sh
api-spec-converter --from=swagger_2 --to=openapi_3 -s yaml ./docs/swagger.yaml > ./docs/v3/openapi3.yaml
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hook now requires jq, yq, and api-spec-converter. Please add command -v checks with install hints so failures are clear for non-mise setups.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not require anyone to install these on their machines imo. That's why the dependency manager exists. These tools will never run in CI or in prod, it will always run locally.

api-spec-converter --from=swagger_2 --to=openapi_3 ./docs/swagger.json > ./docs/v3/openapi3.json
# add region descriptions and EU server (swag only supports a single host)
yq -i '.servers[0].description = "US Region" | .servers += [{"url": "https://eu.getconvoy.cloud/api", "description": "EU Region"}]' ./docs/v3/openapi3.yaml
jq '.servers[0].description = "US Region" | .servers += [{"url": "https://eu.getconvoy.cloud/api", "description": "EU Region"}]' ./docs/v3/openapi3.json > ./docs/v3/openapi3.json.tmp && mv ./docs/v3/openapi3.json.tmp ./docs/v3/openapi3.json
# validate specs
openapi swagger validate ./docs/swagger.json
openapi swagger validate ./docs/swagger.yaml
openapi spec validate ./docs/v3/openapi3.yaml

git add docs/ # add all files under the generated doc folder to git
fi

Expand Down
28 changes: 27 additions & 1 deletion .mise-tasks/gen/docs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,33 @@

set -e

# preflight: check required tools
for tool in swag jq yq api-spec-converter openapi; do
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially fixed. Preflight is in place, but it now checks openapi and mise.toml still does not include it.

command -v "$tool" >/dev/null 2>&1 || { echo "❌ $tool not found. Run 'mise install' to install required tools."; exit 1; }
done

echo "Generating docs"

#generate custom swag tags
go run docs/annotate_dtos/main.go

#generate v2 openapi specs
swag init --generatedTime --parseDependency --parseDependencyLevel 3 --parseInternal -g handlers/main.go -d api/ api/*
swag fmt -d ./api
go run v3gen/main.go

# fix openapi2 specs (structural fixes, add proper produce/consume tags, replace x-nullable..)
bash docs/fix_openapi_spec.sh

#generate v3 specs
api-spec-converter --from=swagger_2 --to=openapi_3 -s yaml ./docs/swagger.yaml > ./docs/v3/openapi3.yaml
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Please add a small required-tools preflight (jq, yq, api-spec-converter) so it fails fast with a clear message.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing here. Forcing people to install a tool they'll only use to generate docs and making sure everyone is on the same version is a problem we struggled with for a long time and it makes no sense to keep supporting it

api-spec-converter --from=swagger_2 --to=openapi_3 ./docs/swagger.json > ./docs/v3/openapi3.json

# add region descriptions and EU server (swag only supports a single host)
yq -i '.servers[0].description = "US Region" | .servers += [{"url": "https://eu.getconvoy.cloud/api", "description": "EU Region"}]' ./docs/v3/openapi3.yaml
jq '.servers[0].description = "US Region" | .servers += [{"url": "https://eu.getconvoy.cloud/api", "description": "EU Region"}]' ./docs/v3/openapi3.json > ./docs/v3/openapi3.json.tmp && mv ./docs/v3/openapi3.json.tmp ./docs/v3/openapi3.json

# validate specs
echo "Validating specs..."
openapi swagger validate ./docs/swagger.json
openapi swagger validate ./docs/swagger.yaml
openapi spec validate ./docs/v3/openapi3.yaml
20 changes: 19 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,25 @@ migrate_create:
@go run cmd/main.go migrate create

generate_docs:
swag init --generatedTime --parseDependency --parseInternal -d api/ api/*
@echo "Checking required tools..."
@command -v swag >/dev/null 2>&1 || { echo "swag not found. Install: go install github.com/swaggo/swag/cmd/swag@latest"; exit 1; }
@command -v jq >/dev/null 2>&1 || { echo "jq not found. Install: brew install jq (macOS) or apt-get install jq (Linux)"; exit 1; }
@command -v yq >/dev/null 2>&1 || { echo "yq not found. Install: brew install yq (macOS) or snap install yq (Linux)"; exit 1; }
@command -v api-spec-converter >/dev/null 2>&1 || { echo "api-spec-converter not found. Install: npm install -g api-spec-converter"; exit 1; }
@command -v openapi >/dev/null 2>&1 || { echo "openapi not found. Install: go install github.com/speakeasy-api/openapi/cmd/openapi@latest"; exit 1; }
@echo "Generating docs..."
go run docs/annotate_dtos/main.go
swag init --generatedTime --parseDependency --parseDependencyLevel 3 --parseInternal -g handlers/main.go -d api/ api/*
swag fmt -d ./api
bash docs/fix_openapi_spec.sh
api-spec-converter --from=swagger_2 --to=openapi_3 -s yaml ./docs/swagger.yaml > ./docs/v3/openapi3.yaml
api-spec-converter --from=swagger_2 --to=openapi_3 ./docs/swagger.json > ./docs/v3/openapi3.json
yq -i '.servers[0].description = "US Region" | .servers += [{"url": "https://eu.getconvoy.cloud/api", "description": "EU Region"}]' ./docs/v3/openapi3.yaml
jq '.servers[0].description = "US Region" | .servers += [{"url": "https://eu.getconvoy.cloud/api", "description": "EU Region"}]' ./docs/v3/openapi3.json > ./docs/v3/openapi3.json.tmp && mv ./docs/v3/openapi3.json.tmp ./docs/v3/openapi3.json
@echo "Validating specs..."
openapi swagger validate ./docs/swagger.json
openapi swagger validate ./docs/swagger.yaml
openapi spec validate ./docs/v3/openapi3.yaml

run_dependencies:
docker compose -f docker-compose.dep.yml up -d
21 changes: 12 additions & 9 deletions api/handlers/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package handlers
// This is the main doc file, swag cli needs it to be named main.go

// @title Convoy API Reference
// @version 24.1.4
// @description Convoy is a fast and secure webhooks proxy. This document contains datastore.s API specification.
// @version 26.3.5
// @description Convoy is a fast and secure webhooks proxy. This document contains datastore's API specification.
// @termsOfService https://getconvoy.io/terms

// @contact.name Convoy Support
Expand All @@ -15,16 +15,13 @@ package handlers
// @license.url https://www.mozilla.org/en-US/MPL/2.0/

// @schemes https
// @host dashboard.getconvoy.io
// @host us.getconvoy.cloud
// @BasePath /api

// @securityDefinitions.apikey ApiKeyAuth
// @in header
// @name Authorization

// @tag.name Organisations
// @tag.description Organisation related APIs

// @tag.name Subscriptions
// @tag.description Subscription related APIs

Expand All @@ -43,14 +40,20 @@ package handlers
// @tag.name Delivery Attempts
// @tag.description Delivery Attempt related APIs

// @tag.name Projects
// @tag.description Project related APIs

// @tag.name Portal Links
// @tag.description Portal Links related APIs

// @tag.name Meta Events
// @tag.description Meta Events related APIs

// @tag.name EventTypes
// @tag.description Event Types related APIs

// @tag.name Filters
// @tag.description Filters related APIs

// @tag.name Onboard
// @tag.description Onboard related APIs

// Stub represents empty json or arbitrary json bodies for our doc annotations
type Stub struct{}
8 changes: 4 additions & 4 deletions api/models/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (

type PagedResponse struct {
Content interface{} `json:"content,omitempty"`
Pagination *datastore.PaginationData `json:"pagination,omitempty"`
Pagination *datastore.PaginationData `json:"pagination,omitempty" extensions:"x-nullable"`
}

type Organisation struct {
Expand All @@ -39,14 +39,14 @@ type APIKeyByIDResponse struct {
Name string `json:"name"`
Role auth.Role `json:"role"`
Type datastore.KeyType `json:"key_type"`
ExpiresAt null.Time `json:"expires_at,omitempty"`
ExpiresAt null.Time `json:"expires_at,omitempty" extensions:"x-nullable"`
CreatedAt time.Time `json:"created_at,omitempty"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
}

type UserInviteTokenResponse struct {
Token *datastore.OrganisationInvite `json:"token"`
User *datastore.User `json:"user"`
Token *datastore.OrganisationInvite `json:"token" extensions:"x-nullable"`
User *datastore.User `json:"user" extensions:"x-nullable"`
}

type DeliveryAttempt struct {
Expand Down
4 changes: 2 additions & 2 deletions api/models/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,8 @@ type ProjectResponse struct {
}

type CreateProjectResponse struct {
APIKey *datastore.APIKeyResponse `json:"api_key"`
Project *ProjectResponse `json:"project"`
APIKey *datastore.APIKeyResponse `json:"api_key" extensions:"x-nullable"`
Project *ProjectResponse `json:"project" extensions:"x-nullable"`
}

func NewListProjectResponse(projects []*datastore.Project) []*ProjectResponse {
Expand Down
4 changes: 2 additions & 2 deletions api/models/source.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,8 @@ type CustomResponse struct {
}

type UpdateCustomResponse struct {
Body *string `json:"body"`
ContentType *string `json:"content_type"`
Body *string `json:"body" extensions:"x-nullable"`
ContentType *string `json:"content_type" extensions:"x-nullable"`
}

type VerifierConfig struct {
Expand Down
Loading
Loading