Skip to content

Commit 1d97a90

Browse files
commoddityfredteumerOlshansk
authored
[PostgREST][Portal DB] Add Go SDK generation and module (#471)
Adds Go SDK generated from PostgREST OpenAPI spec. --------- Co-authored-by: fred <[email protected]> Co-authored-by: Daniel Olshansky <[email protected]>
1 parent a9154e7 commit 1d97a90

19 files changed

+21015
-3593
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,9 @@ pg_dump.sql
8585

8686
# Benchmark Results
8787
bench_results
88+
89+
# Node Modules (Portal DBTypeScript SDK)
90+
node_modules
91+
92+
# JWKS file
93+
jwks.json

Makefile

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ help: ## Prints all the targets in all the Makefiles
3232
@echo "$(BOLD)=== 📋 Information & Discovery ===$(RESET)"
3333
@grep -h -E '^(help|help-unclassified):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
3434
@echo ""
35+
@echo "$(BOLD)=== 🗄️ Portal Database Makefile Targets ===$(RESET)"
36+
@grep -h -E '^(portal_db_help):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
37+
@echo ""
3538
@echo "$(BOLD)=== 🔨 Build & Run ===$(RESET)"
3639
@grep -h -E '^path_(build|run):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
3740
@echo ""
@@ -54,9 +57,6 @@ help: ## Prints all the targets in all the Makefiles
5457
@echo "$(BOLD)=== ✋ Manual Testing ===$(RESET)"
5558
@grep -h -E '^(get_disqualified_endpoints|grove_get_disqualified_endpoints|shannon_preliminary_services_test_help|shannon_preliminary_services_test|source_shannon_preliminary_services_helpers):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
5659
@echo ""
57-
@echo "$(BOLD)=== 🗄️ Portal Database ===$(RESET)"
58-
@grep -h -E '^(portal_db_help):.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
59-
@echo ""
6060
@echo "$(BOLD)=== 📦 Protocol Buffers ===$(RESET)"
6161
@grep -h -E '^proto.*:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(CYAN)%-40s$(RESET) %s\n", $$1, $$2}'
6262
@echo ""
@@ -155,4 +155,27 @@ include ./makefiles/proto.mk
155155
include ./makefiles/debug.mk
156156
include ./makefiles/claude.mk
157157
include ./makefiles/release.mk
158-
include ./makefiles/helpers.mk
158+
include ./makefiles/helpers.mk
159+
160+
###############################
161+
### Global Error Handling ###
162+
###############################
163+
164+
# Catch-all rule for undefined targets
165+
# This must be defined AFTER includes so color variables are available
166+
# and it acts as a fallback for any undefined target
167+
%:
168+
@echo ""
169+
@echo "$(RED)❌ Error: Unknown target '$(BOLD)$@$(RESET)$(RED)'$(RESET)"
170+
@echo ""
171+
@if echo "$@" | grep -q "^postgrest"; then \
172+
echo "$(YELLOW)💡 Hint: Portal DB targets should be run from the portal-db directory:$(RESET)"; \
173+
echo " $(CYAN)cd ./portal-db && make $@$(RESET)"; \
174+
echo " Or see: $(CYAN)make portal_db_help$(RESET)"; \
175+
else \
176+
echo "$(YELLOW)💡 Available targets:$(RESET)"; \
177+
echo " Run $(CYAN)make help$(RESET) to see all available targets"; \
178+
echo " Run $(CYAN)make help-unclassified$(RESET) to see unclassified targets"; \
179+
fi
180+
@echo ""
181+
@exit 1

portal-db/Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,11 @@ postgrest-swagger-ui: postgrest-generate-openapi ## Start Swagger UI to view Ope
166166
-v $(PWD)/api/openapi/openapi.json:/openapi.json:ro \
167167
swaggerapi/swagger-ui
168168

169+
.PHONY: postgrest-generate-sdks
170+
postgrest-generate-sdks: postgrest-generate-openapi ## Generate Go and TypeScript SDKs from OpenAPI specification
171+
@echo "🔧 Generating Go and TypeScript SDKs from OpenAPI specification..."
172+
cd api/codegen && ./generate-sdks.sh
173+
169174
# ============================================================================
170175
# AUTHENTICATION & TESTING
171176
# ============================================================================
@@ -190,7 +195,7 @@ _require-portal-db:
190195
.PHONY: test-postgrest-auth
191196
test-postgrest-auth: _require-postgrest-api ## Test JWT authentication flow
192197
@echo "🔐 Testing JWT authentication..."
193-
cd api/scripts && ./test-postgrest-auth.sh
198+
cd api/scripts && ./postgrest-test-auth.sh
194199

195200
.PHONY: test-postgrest-portal-app-creation
196201
test-postgrest-portal-app-creation: _require-postgrest-api ## Test portal application creation and retrieval via authenticated Postgres flow
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
2+
package: portaldb
3+
output: ../../sdk/go/client.go
4+
generate:
5+
client: true
6+
models: false
7+
embedded-spec: true
8+
output-options:
9+
skip-fmt: false
10+
skip-prune: false
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
2+
package: portaldb
3+
output: ../../sdk/go/models.go
4+
generate:
5+
models: true
6+
embedded-spec: false
7+
output-options:
8+
skip-fmt: false
9+
skip-prune: false
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
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

Comments
 (0)