Skip to content

Commit c1f7ca9

Browse files
authored
Merge pull request #16 from rh-amarin/gcp-oas2
Enhance API Schema and Build Process
2 parents c592fe5 + dbce87b commit c1f7ca9

15 files changed

Lines changed: 7455 additions & 775 deletions

README.md

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ Contains shared models used by all service variants:
8181
- **`models/clusters/`** - Cluster resource definitions (interfaces and base models)
8282
- **`models/statuses/`** - Status resource definitions for clusters and nodepools
8383
- **`models/nodepools/`** - NodePool resource definitions
84-
- **`models/compatibility/`** - Compatibility endpoints
8584
- **`models/common/`** - Common models and types (APIResource, Error, QueryParams, etc.)
8685

8786
### `/models-core`
@@ -98,9 +97,24 @@ Contains GCP provider-specific model definitions:
9897
Contains service definitions that generate the OpenAPI specifications:
9998

10099
- **`services/clusters.tsp`** - Cluster resource endpoints
101-
- **`services/statuses.tsp`** - Status resource endpoints
100+
- **`services/statuses.tsp`** - Status resource endpoints (GET only - public API)
101+
- **`services/statuses-internal.tsp`** - Status write endpoints (POST - internal API, see below)
102102
- **`services/nodepools.tsp`** - NodePool resource endpoints
103-
- **`services/compatibility.tsp`** - Compatibility endpoints
103+
104+
#### Public vs Internal API Split
105+
106+
The status endpoints are split into two files to support different API consumers:
107+
108+
| File | Operations | Audience | Included in Build |
109+
|------|------------|----------|-------------------|
110+
| `statuses.tsp` | GET (read) | External clients | ✅ Yes (default) |
111+
| `statuses-internal.tsp` | POST (write) | Internal adapters | ❌ No (opt-in) |
112+
113+
**Why the split?**
114+
- **External clients** (UI, CLI, monitoring) only need to read status information
115+
- **Internal adapters** (validator, provisioner, dns) need to write/update status reports
116+
- Separating these allows generating different API contracts for different audiences
117+
104118

105119
## Prerequisites
106120

@@ -137,23 +151,53 @@ This installs all required TypeSpec libraries to the local `node_modules/` direc
137151

138152
The repository uses a single `main.tsp` entry point. To generate either the core API or GCP API, you need to re-link the `aliases.tsp` file to point to the desired provider aliases file.
139153

140-
### Using the Build Script (Recommended)
154+
### Output Formats
155+
156+
The build system supports two OpenAPI formats:
157+
- **OpenAPI 3.0** (default) - Modern format with full feature support
158+
- **OpenAPI 2.0 (Swagger)** - Legacy format for compatibility with older tools
141159

142-
The easiest way to build the OpenAPI schema is using the provided `build-schema.sh` script:
160+
### Using npm Scripts (Recommended)
161+
162+
The easiest way to build the OpenAPI schema is using the provided npm scripts:
143163

144164
```bash
145-
# Build Core API
146-
./build-schema.sh core
165+
# Build OpenAPI 3.0 only
166+
npm run build:core # Build Core API (OpenAPI 3.0)
167+
npm run build:gcp # Build GCP API (OpenAPI 3.0)
168+
169+
# Build both OpenAPI 3.0 and OpenAPI 2.0 (Swagger)
170+
npm run build:core:swagger # Build Core API with Swagger
171+
npm run build:gcp:swagger # Build GCP API with Swagger
172+
173+
# Build all providers with both formats
174+
npm run build:all
175+
```
147176

148-
# Build GCP API
177+
### Using the Build Script Directly
178+
179+
You can also use the `build-schema.sh` script directly:
180+
181+
```bash
182+
# Build OpenAPI 3.0 only
183+
./build-schema.sh core
149184
./build-schema.sh gcp
185+
186+
# Build with OpenAPI 2.0 (Swagger) output
187+
./build-schema.sh core --swagger
188+
./build-schema.sh gcp --swagger
189+
# or use the alias:
190+
./build-schema.sh gcp --openapi2
150191
```
151192

152193
The script automatically:
153194
1. Validates the provider parameter
154195
2. Re-links `aliases.tsp` to the appropriate provider aliases file
155-
3. Compiles the TypeSpec to generate the OpenAPI schema
156-
4. Outputs the result to `schemas/{provider}/openapi.yaml` (e.g., `schemas/core/openapi.yaml` or `schemas/gcp/openapi.yaml`)
196+
3. Compiles the TypeSpec to generate the OpenAPI 3.0 schema
197+
4. (If `--swagger` flag is used) Converts OpenAPI 3.0 to OpenAPI 2.0 (Swagger)
198+
5. Outputs the results to `schemas/{provider}/`:
199+
- `openapi.yaml` - OpenAPI 3.0 specification
200+
- `swagger.yaml` - OpenAPI 2.0 (Swagger) specification (if `--swagger` flag is used)
157201

158202
**Extending to new providers**: Simply create `aliases-{provider}.tsp` and the script will automatically detect and support it.
159203

@@ -174,6 +218,12 @@ If you prefer to build manually:
174218

175219
Output: `tsp-output/schema/openapi.yaml`
176220

221+
3. (Optional) Convert to OpenAPI 2.0 (Swagger):
222+
```bash
223+
npx api-spec-converter --from=openapi_3 --to=swagger_2 --syntax=yaml \
224+
tsp-output/schema/openapi.yaml > tsp-output/schema/swagger.yaml
225+
```
226+
177227
#### Build GCP API
178228
1. Re-link `aliases.tsp` to `aliases-gcp.tsp`:
179229
```bash
@@ -187,6 +237,12 @@ If you prefer to build manually:
187237

188238
Output: `tsp-output/schema/openapi.yaml`
189239

240+
3. (Optional) Convert to OpenAPI 2.0 (Swagger):
241+
```bash
242+
npx api-spec-converter --from=openapi_3 --to=swagger_2 --syntax=yaml \
243+
tsp-output/schema/openapi.yaml > tsp-output/schema/swagger.yaml
244+
```
245+
190246
**Note**: The `aliases.tsp` file controls which provider-specific `ClusterSpec` definition is used throughout the service definitions. By re-linking it to either `aliases-core.tsp` or `aliases-gcp.tsp`, you switch between the generic `Record<unknown>` spec and the GCP-specific `GCPClusterSpec`.
191247

192248
## Architecture
@@ -249,6 +305,7 @@ To add a new service (e.g., with additional endpoints):
249305
- `@typespec/http` - HTTP protocol support
250306
- `@typespec/openapi` - OpenAPI decorators
251307
- `@typespec/openapi3` - OpenAPI 3.0 emitter
308+
- `api-spec-converter` - Converts OpenAPI 3.0 to OpenAPI 2.0 (Swagger)
252309

253310

254311
## Developing with the Visual Studio Typespec extension

aliases-core.tsp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ import "./models-core/cluster/example_cluster.tsp";
33
import "./models-core/cluster/example_post.tsp";
44
import "./models-core/nodepool/model.tsp";
55
import "./models-core/nodepool/example_nodepool.tsp";
6-
import "./models-core/nodepool/example_post.tsp";
6+
import "./models-core/nodepool/example_post.tsp";
7+
import "./services/statuses-internal.tsp";

build-schema.sh

Lines changed: 79 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
#!/bin/bash
22

33
# Build HyperFleet OpenAPI Schema
4-
# Usage: ./build-schema.sh [provider]
5-
# provider: core, gcp, or any provider with aliases-{provider}.tsp file
4+
# Usage: ./build-schema.sh <provider> [--swagger|--openapi2]
5+
# provider: core, gcp, or any provider with aliases-{provider}.tsp file (required, must be first argument)
6+
# --swagger, --openapi2: Also generate OpenAPI 2.0 (Swagger) format
67

78
set -e
89

@@ -12,21 +13,51 @@ GREEN='\033[0;32m'
1213
YELLOW='\033[1;33m'
1314
NC='\033[0m' # No Color
1415

15-
# Get the provider from command line argument
16-
PROVIDER="${1:-core}"
16+
# Parse arguments
17+
GENERATE_SWAGGER=false
1718

18-
# Script directory (where the script is located)
19-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
20-
cd "$SCRIPT_DIR"
21-
22-
# Validate provider argument
23-
if [ -z "$PROVIDER" ]; then
19+
# Provider is required and must be the first argument
20+
if [ $# -lt 1 ]; then
2421
echo -e "${RED}Error: Provider argument is required${NC}"
25-
echo "Usage: $0 [provider]"
22+
echo "Usage: $0 <provider> [--swagger|--openapi2]"
2623
echo " provider: core, gcp, or any provider with aliases-{provider}.tsp file"
24+
echo " --swagger, --openapi2: Also generate OpenAPI 2.0 (Swagger) format"
2725
exit 1
2826
fi
2927

28+
PROVIDER="$1"
29+
shift
30+
31+
# Check if provider looks like an option (starts with -)
32+
if [[ "$PROVIDER" == -* ]]; then
33+
echo -e "${RED}Error: Provider must be the first argument${NC}"
34+
echo "Usage: $0 <provider> [--swagger|--openapi2]"
35+
exit 1
36+
fi
37+
38+
# Parse remaining options
39+
for arg in "$@"; do
40+
case $arg in
41+
--swagger|--openapi2)
42+
GENERATE_SWAGGER=true
43+
;;
44+
-*)
45+
echo -e "${RED}Error: Unknown option: $arg${NC}"
46+
echo "Usage: $0 <provider> [--swagger|--openapi2]"
47+
exit 1
48+
;;
49+
*)
50+
echo -e "${RED}Error: Unexpected argument: $arg${NC}"
51+
echo "Usage: $0 <provider> [--swagger|--openapi2]"
52+
exit 1
53+
;;
54+
esac
55+
done
56+
57+
# Script directory (where the script is located)
58+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
59+
cd "$SCRIPT_DIR"
60+
3061
# Define the aliases file for the provider
3162
ALIASES_FILE="aliases-${PROVIDER}.tsp"
3263

@@ -57,7 +88,21 @@ if ! command -v tsp &> /dev/null; then
5788
exit 1
5889
fi
5990

91+
# Check if api-spec-converter is available when swagger output is requested
92+
if [ "$GENERATE_SWAGGER" = true ]; then
93+
if ! npx api-spec-converter --version &> /dev/null; then
94+
echo -e "${RED}Error: api-spec-converter not found. Please install it.${NC}"
95+
echo "Install with: npm install --save-dev api-spec-converter"
96+
exit 1
97+
fi
98+
fi
99+
60100
echo -e "${GREEN}Building HyperFleet API schema for provider: ${PROVIDER}${NC}"
101+
if [ "$GENERATE_SWAGGER" = true ]; then
102+
echo -e "${GREEN}Output formats: OpenAPI 3.0 + OpenAPI 2.0 (Swagger)${NC}"
103+
else
104+
echo -e "${GREEN}Output format: OpenAPI 3.0${NC}"
105+
fi
61106
echo ""
62107

63108
# Step 1: Re-link aliases.tsp to the provider-specific aliases file
@@ -93,7 +138,7 @@ if tsp compile main.tsp --output-dir "$TEMP_OUTPUT_DIR"; then
93138
if [ -f "${TEMP_OUTPUT_DIR}/schema/openapi.yaml" ]; then
94139
mv "${TEMP_OUTPUT_DIR}/schema/openapi.yaml" "${OUTPUT_DIR}/openapi.yaml"
95140
echo ""
96-
echo -e "${GREEN}✓ Successfully generated OpenAPI schema${NC}"
141+
echo -e "${GREEN}✓ Successfully generated OpenAPI 3.0 schema${NC}"
97142
echo -e "${GREEN}Output: ${OUTPUT_DIR}/openapi.yaml${NC}"
98143
else
99144
echo ""
@@ -107,3 +152,25 @@ else
107152
exit 1
108153
fi
109154

155+
# Step 4: Convert to OpenAPI 2.0 (Swagger) if requested
156+
if [ "$GENERATE_SWAGGER" = true ]; then
157+
echo ""
158+
echo -e "${YELLOW}Step 4: Converting to OpenAPI 2.0 (Swagger)...${NC}"
159+
160+
if npx api-spec-converter \
161+
--from=openapi_3 \
162+
--to=swagger_2 \
163+
--syntax=yaml \
164+
"${OUTPUT_DIR}/openapi.yaml" > "${OUTPUT_DIR}/swagger.yaml" 2>/dev/null; then
165+
echo -e "${GREEN}✓ Successfully generated OpenAPI 2.0 (Swagger) schema${NC}"
166+
echo -e "${GREEN}Output: ${OUTPUT_DIR}/swagger.yaml${NC}"
167+
else
168+
echo -e "${RED}✗ Failed to convert to OpenAPI 2.0 (Swagger)${NC}"
169+
echo "The OpenAPI 3.0 schema may contain features not supported in OpenAPI 2.0"
170+
rm -f "${OUTPUT_DIR}/swagger.yaml"
171+
exit 1
172+
fi
173+
fi
174+
175+
echo ""
176+
echo -e "${GREEN}Build complete!${NC}"

main.tsp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import "@typespec/openapi3";
55
import "./services/clusters.tsp";
66
import "./services/statuses.tsp";
77
import "./services/nodepools.tsp";
8-
import "./services/compatibility.tsp";
8+
// Provider-specific security is imported via aliases.tsp
9+
import "./aliases.tsp";
10+
911
using Http;
1012
using OpenAPI;
1113

@@ -18,8 +20,8 @@ using OpenAPI;
1820
*
1921
*/
2022
@service(#{ title: "HyperFleet API" })
21-
@info(#{ version: "1.0.0", contact: #{ name: "HyperFleet Team" } })
22-
@server("http://localhost:8000", "Development")
23+
@info(#{ version: "1.0.0", contact: #{ name: "HyperFleet Team" }, license: #{ name: "Apache 2.0" ,url: "https://www.apache.org/licenses/LICENSE-2.0"} })
24+
@server("https://hyperfleet.redhat.com", "Production")
2325
@route("/api/hyperfleet/v1")
2426
namespace HyperFleet;
2527

0 commit comments

Comments
 (0)