Skip to content

Commit 1ca8fd7

Browse files
committed
feat: add server URL to served OpenAPI specs.
1 parent f034534 commit 1ca8fd7

File tree

3 files changed

+436
-10
lines changed

3 files changed

+436
-10
lines changed

external/plugins/swaggerui/spec.go

Lines changed: 106 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
package main
22

33
import (
4+
"encoding/json"
5+
"fmt"
46
"github.com/imposter-project/imposter-go/external/shared"
7+
"gopkg.in/yaml.v3"
8+
"os"
9+
"path/filepath"
510
"strings"
611
)
712

@@ -30,20 +35,112 @@ func generateSpecConfig(configs []shared.LightweightConfig) error {
3035
return nil
3136
}
3237

33-
// serveRawSpec serves the raw OpenAPI spec file based on the provided path.
38+
// getServerURL constructs the server URL from environment variables
39+
func getServerURL() string {
40+
serverURL := os.Getenv("IMPOSTER_SERVER_URL")
41+
if serverURL != "" {
42+
return serverURL
43+
}
44+
45+
port := os.Getenv("IMPOSTER_PORT")
46+
if port == "" {
47+
port = "8080"
48+
}
49+
50+
var hostSuffix string
51+
if port != "80" {
52+
hostSuffix = fmt.Sprintf(":%s", port)
53+
}
54+
return fmt.Sprintf("http://localhost%s", hostSuffix)
55+
}
56+
57+
// serveRawSpec serves the OpenAPI spec file with server URL modifications.
3458
// If no matching spec is found, it returns nil.
3559
func serveRawSpec(path string) *shared.HandlerResponse {
36-
var response *shared.HandlerResponse
3760
for _, specConfig := range specConfigs {
3861
if path == specConfig.URL {
39-
// TODO instead of serving the raw spec, parse it and add the server URL as the first server entry, then marshal it back to JSON.
40-
response = &shared.HandlerResponse{
41-
FileBaseDir: specConfig.ConfigDir,
42-
StatusCode: 200,
43-
File: specConfig.OriginalPath,
62+
// Read and parse the spec file
63+
specPath := filepath.Join(specConfig.ConfigDir, specConfig.OriginalPath)
64+
specData, err := os.ReadFile(specPath)
65+
if err != nil {
66+
return &shared.HandlerResponse{
67+
StatusCode: 500,
68+
Body: []byte(fmt.Sprintf("Error reading spec file: %v", err)),
69+
}
70+
}
71+
72+
// Parse the spec into a map
73+
var specMap map[string]interface{}
74+
75+
// YAML parser will handle both YAML and JSON formats
76+
if err := yaml.Unmarshal(specData, &specMap); err != nil {
77+
return &shared.HandlerResponse{
78+
StatusCode: 500,
79+
Body: []byte(fmt.Sprintf("Error parsing spec file: %v", err)),
80+
}
81+
}
82+
83+
// Add server URL to the spec
84+
serverURL := getServerURL()
85+
86+
// Check if this is OpenAPI 3.x or Swagger 2.0
87+
if openapi, exists := specMap["openapi"]; exists {
88+
// OpenAPI 3.x - add to servers array
89+
if openapiVersion, ok := openapi.(string); ok && strings.HasPrefix(openapiVersion, "3.") {
90+
servers, exists := specMap["servers"]
91+
if !exists {
92+
servers = []interface{}{}
93+
}
94+
95+
serverList, ok := servers.([]interface{})
96+
if !ok {
97+
serverList = []interface{}{}
98+
}
99+
100+
// Add server URL as first entry
101+
newServer := map[string]interface{}{"url": serverURL}
102+
serverList = append([]interface{}{newServer}, serverList...)
103+
specMap["servers"] = serverList
104+
}
105+
} else if _, exists := specMap["swagger"]; exists {
106+
// Swagger 2.0 - set basePath and host
107+
if swaggerVersion, ok := specMap["swagger"].(string); ok && strings.HasPrefix(swaggerVersion, "2.") {
108+
// Parse the server URL to extract host and basePath
109+
if strings.HasPrefix(serverURL, "http://") {
110+
serverURL = strings.TrimPrefix(serverURL, "http://")
111+
} else if strings.HasPrefix(serverURL, "https://") {
112+
serverURL = strings.TrimPrefix(serverURL, "https://")
113+
specMap["schemes"] = []interface{}{"https"}
114+
}
115+
116+
parts := strings.SplitN(serverURL, "/", 2)
117+
specMap["host"] = parts[0]
118+
119+
if len(parts) > 1 {
120+
specMap["basePath"] = "/" + parts[1]
121+
} else {
122+
specMap["basePath"] = "/"
123+
}
124+
}
125+
}
126+
127+
// Marshal back to JSON
128+
jsonData, err := json.MarshalIndent(specMap, "", " ")
129+
if err != nil {
130+
return &shared.HandlerResponse{
131+
StatusCode: 500,
132+
Body: []byte(fmt.Sprintf("Error marshalling spec: %v", err)),
133+
}
134+
}
135+
136+
return &shared.HandlerResponse{
137+
StatusCode: 200,
138+
Body: jsonData,
139+
Headers: map[string]string{
140+
"Content-Type": "application/json",
141+
},
44142
}
45-
break
46143
}
47144
}
48-
return response
145+
return nil
49146
}

0 commit comments

Comments
 (0)