1+ #! /bin/bash
2+
3+ # Generate Go SDK from OpenAPI specification
4+ # This script generates a Go SDK for the Portal DB API
5+ # - Go SDK: Uses oapi-codegen for client and models generation
6+
7+ set -e
8+
9+ # Configuration
10+ OPENAPI_DIR=" ../openapi"
11+ OPENAPI_V2_FILE=" $OPENAPI_DIR /openapi-v2.json"
12+ OPENAPI_V3_FILE=" $OPENAPI_DIR /openapi.json"
13+ GO_OUTPUT_DIR=" ../../sdk/go"
14+ CONFIG_MODELS=" ./codegen-models.yaml"
15+ CONFIG_CLIENT=" ./codegen-client.yaml"
16+ POSTGREST_URL=" http://localhost:3000"
17+
18+ # Colors for output
19+ RED=' \033[0;31m'
20+ GREEN=' \033[0;32m'
21+ YELLOW=' \033[1;33m'
22+ BLUE=' \033[0;34m'
23+ NC=' \033[0m' # No Color
24+
25+ echo " 🔧 Generating Go SDK from OpenAPI specification..."
26+
27+ # ============================================================================
28+ # PHASE 1: ENVIRONMENT VALIDATION
29+ # ============================================================================
30+
31+ echo " "
32+ echo -e " ${BLUE} 📋 Phase 1: Environment Validation${NC} "
33+
34+ # Check if Go is installed
35+ if ! command -v go > /dev/null 2>&1 ; then
36+ echo -e " ${RED} ❌ Go is not installed. Please install Go first.${NC} "
37+ echo " - Mac: brew install go"
38+ echo " - Or download from: https://golang.org/"
39+ exit 1
40+ fi
41+
42+ echo -e " ${GREEN} ✅ Go is installed: $( go version) ${NC} "
43+
44+ # Check if oapi-codegen is installed
45+ if ! command -v oapi-codegen > /dev/null 2>&1 ; then
46+ echo " 📦 Installing oapi-codegen..."
47+ go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
48+
49+ # Verify installation
50+ if ! command -v oapi-codegen > /dev/null 2>&1 ; then
51+ echo -e " ${RED} ❌ Failed to install oapi-codegen. Please check your Go installation.${NC} "
52+ exit 1
53+ fi
54+ fi
55+
56+ echo -e " ${GREEN} ✅ oapi-codegen is available: $( oapi-codegen -version 2> /dev/null || echo ' installed' ) ${NC} "
57+
58+ # Check if PostgREST is running
59+ echo " 🌐 Checking PostgREST availability..."
60+ if ! curl -s --connect-timeout 5 " $POSTGREST_URL " > /dev/null 2>&1 ; then
61+ echo -e " ${RED} ❌ PostgREST is not accessible at $POSTGREST_URL ${NC} "
62+ echo " Please ensure PostgREST is running:"
63+ echo " cd .. && docker compose up -d"
64+ echo " cd api && docker compose up -d"
65+ exit 1
66+ fi
67+
68+ echo -e " ${GREEN} ✅ PostgREST is accessible at $POSTGREST_URL ${NC} "
69+
70+ # Check if configuration files exist
71+ for config_file in " $CONFIG_MODELS " " $CONFIG_CLIENT " ; do
72+ if [ ! -f " $config_file " ]; then
73+ echo -e " ${RED} ❌ Configuration file not found: $config_file ${NC} "
74+ echo " This should have been created as a permanent file."
75+ exit 1
76+ fi
77+ done
78+
79+ echo -e " ${GREEN} ✅ Configuration files found: models, client${NC} "
80+
81+ # ============================================================================
82+ # PHASE 2: SPEC RETRIEVAL & CONVERSION
83+ # ============================================================================
84+
85+ echo " "
86+ echo -e " ${BLUE} 📋 Phase 2: Spec Retrieval & Conversion${NC} "
87+
88+ # Create openapi directory if it doesn't exist
89+ mkdir -p " $OPENAPI_DIR "
90+
91+ # Clean any existing files to start fresh
92+ echo " 🧹 Cleaning previous OpenAPI files..."
93+ rm -f " $OPENAPI_V2_FILE " " $OPENAPI_V3_FILE "
94+
95+ # Generate JWT token for authenticated access to get all endpoints
96+ echo " 🔑 Generating JWT token for authenticated OpenAPI spec..."
97+ JWT_TOKEN=$( cd ../scripts && ./gen-jwt.sh portal_db_admin 2> /dev/null | grep -A1 " 🎟️ Token:" | tail -1)
98+
99+ if [ -z " $JWT_TOKEN " ]; then
100+ echo " ⚠️ Could not generate JWT token, fetching public endpoints only..."
101+ AUTH_HEADER=" "
102+ else
103+ echo " ✅ JWT token generated, will fetch all endpoints (public + protected)"
104+ AUTH_HEADER=" Authorization: Bearer $JWT_TOKEN "
105+ fi
106+
107+ # Fetch OpenAPI spec from PostgREST (Swagger 2.0 format)
108+ echo " 📥 Fetching OpenAPI specification from PostgREST..."
109+ if ! curl -s " $POSTGREST_URL " -H " Accept: application/openapi+json" ${AUTH_HEADER: +-H " $AUTH_HEADER " } > " $OPENAPI_V2_FILE " ; then
110+ echo -e " ${RED} ❌ Failed to fetch OpenAPI specification from $POSTGREST_URL ${NC} "
111+ exit 1
112+ fi
113+
114+ # Verify the file was created and has content
115+ if [ ! -f " $OPENAPI_V2_FILE " ] || [ ! -s " $OPENAPI_V2_FILE " ]; then
116+ echo -e " ${RED} ❌ OpenAPI specification file is empty or missing${NC} "
117+ exit 1
118+ fi
119+
120+ echo -e " ${GREEN} ✅ Swagger 2.0 specification saved to: $OPENAPI_V2_FILE ${NC} "
121+
122+ # Convert Swagger 2.0 to OpenAPI 3.x
123+ echo " 🔄 Converting Swagger 2.0 to OpenAPI 3.x..."
124+
125+ # Check if swagger2openapi is available
126+ if ! command -v swagger2openapi > /dev/null 2>&1 ; then
127+ echo " 📦 Installing swagger2openapi converter..."
128+ if command -v npm > /dev/null 2>&1 ; then
129+ npm install -g swagger2openapi
130+ else
131+ echo -e " ${RED} ❌ npm not found. Please install Node.js and npm first.${NC} "
132+ echo " - Mac: brew install node"
133+ echo " - Or download from: https://nodejs.org/"
134+ exit 1
135+ fi
136+ fi
137+
138+ if ! swagger2openapi " $OPENAPI_V2_FILE " -o " $OPENAPI_V3_FILE " ; then
139+ echo -e " ${RED} ❌ Failed to convert Swagger 2.0 to OpenAPI 3.x${NC} "
140+ exit 1
141+ fi
142+
143+ # Fix boolean format issues in the converted spec (in place)
144+ echo " 🔧 Fixing boolean format issues..."
145+ sed -i.bak ' s/"format": "boolean",//g' " $OPENAPI_V3_FILE "
146+ rm -f " ${OPENAPI_V3_FILE} .bak"
147+
148+ # Remove the temporary Swagger 2.0 file since we only need the OpenAPI 3.x version
149+ echo " 🧹 Cleaning temporary Swagger 2.0 file..."
150+ rm -f " $OPENAPI_V2_FILE "
151+
152+ echo -e " ${GREEN} ✅ OpenAPI 3.x specification ready: $OPENAPI_V3_FILE ${NC} "
153+
154+ # ============================================================================
155+ # PHASE 3: SDK GENERATION
156+ # ============================================================================
157+
158+ echo " "
159+ echo -e " ${BLUE} 📋 Phase 3: SDK Generation${NC} "
160+
161+ echo " 🐹 Generating Go SDK in separate files for better readability..."
162+
163+ # Clean previous generated files
164+ echo " 🧹 Cleaning previous generated files..."
165+ rm -f " $GO_OUTPUT_DIR /models.go" " $GO_OUTPUT_DIR /client.go"
166+
167+ # Generate models file (data types and structures)
168+ echo " Generating models.go..."
169+ if ! oapi-codegen -config " $CONFIG_MODELS " " $OPENAPI_V3_FILE " ; then
170+ echo -e " ${RED} ❌ Failed to generate models${NC} "
171+ exit 1
172+ fi
173+
174+ # Generate client file (API client and methods)
175+ echo " Generating client.go..."
176+ if ! oapi-codegen -config " $CONFIG_CLIENT " " $OPENAPI_V3_FILE " ; then
177+ echo -e " ${RED} ❌ Failed to generate client${NC} "
178+ exit 1
179+ fi
180+
181+ echo -e " ${GREEN} ✅ Go SDK generated successfully in separate files${NC} "
182+
183+ # ============================================================================
184+ # PHASE 4: MODULE SETUP
185+ # ============================================================================
186+
187+ echo " "
188+ echo -e " ${BLUE} 📋 Phase 4: Module Setup${NC} "
189+
190+ # Navigate to SDK directory for module setup
191+ cd " $GO_OUTPUT_DIR "
192+
193+ # Run go mod tidy to resolve dependencies
194+ echo " 🔧 Resolving dependencies..."
195+ if ! go mod tidy; then
196+ echo -e " ${RED} ❌ Failed to resolve Go dependencies${NC} "
197+ cd - > /dev/null
198+ exit 1
199+ fi
200+
201+ echo -e " ${GREEN} ✅ Go dependencies resolved${NC} "
202+
203+ # Test compilation
204+ echo " 🔍 Validating generated code compilation..."
205+ if ! go build ./...; then
206+ echo -e " ${RED} ❌ Generated code does not compile${NC} "
207+ cd - > /dev/null
208+ exit 1
209+ fi
210+
211+ echo -e " ${GREEN} ✅ Generated code compiles successfully${NC} "
212+
213+ # Return to scripts directory
214+ cd - > /dev/null
215+
216+ # ============================================================================
217+ # SUCCESS SUMMARY
218+ # ============================================================================
219+
220+ echo " "
221+ echo -e " ${GREEN} 🎉 SDK generation completed successfully!${NC} "
222+ echo " "
223+ echo -e " ${BLUE} 📁 Generated Files:${NC} "
224+ echo " API Docs: $OPENAPI_V3_FILE "
225+ echo " Go SDK: $GO_OUTPUT_DIR "
226+ echo " "
227+ echo -e " ${BLUE} 🐹 Go SDK:${NC} "
228+ echo " Module: github.com/buildwithgrove/path/portal-db/sdk/go"
229+ echo " Package: portaldb"
230+ echo " Files:"
231+ echo " • models.go - Generated data models and types (updated)"
232+ echo " • client.go - Generated SDK client and methods (updated)"
233+ echo " • go.mod - Go module definition (permanent)"
234+ echo " • README.md - Documentation (permanent)"
235+ echo " "
236+ echo -e " ${BLUE} 📚 API Documentation:${NC} "
237+ echo " • openapi.json - OpenAPI 3.x specification (updated)"
238+ echo " "
239+ echo -e " ${BLUE} 🚀 Next Steps:${NC} "
240+ echo " "
241+ echo -e " ${BLUE} Go SDK:${NC} "
242+ echo " 1. Review generated models: cat $GO_OUTPUT_DIR /models.go | head -50"
243+ echo " 2. Review generated client: cat $GO_OUTPUT_DIR /client.go | head -50"
244+ echo " 3. Import in your project: go get github.com/buildwithgrove/path/portal-db/sdk/go"
245+ echo " 4. Check documentation: cat $GO_OUTPUT_DIR /README.md"
246+ echo " "
247+ echo -e " ${BLUE} 💡 Tips:${NC} "
248+ echo " • Go: Full client with methods, types separated for readability"
249+ echo " • SDK updates automatically when you run this script"
250+ echo " • Run after database schema changes to stay in sync"
251+ echo " "
252+ echo -e " ${GREEN} ✨ Happy coding!${NC} "
0 commit comments