feat: implement API v2 with feature flag control

- Added /api/v2/greet POST endpoint with JSON request/response

- Implemented ServiceV2 with Hello my friend <name>! greeting format

- Added api.v2_enabled feature flag (default: false)

- Extended BDD tests to cover v2 scenarios

- Maintained full backward compatibility with v1 API

- Added DLC_API_V2_ENABLED environment variable support

- Created ADR 0010-api-v2-feature-flag.md

- Updated configuration system to support API versioning
This commit is contained in:
2026-04-04 20:39:46 +02:00
parent d29d7a221a
commit 875eb09fb7
12 changed files with 453 additions and 3 deletions

View File

@@ -1,6 +1,8 @@
package testserver
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
@@ -19,12 +21,37 @@ func NewClient(server *Server) *Client {
}
}
func (c *Client) Request(method, path string, body []byte) error {
func (c *Client) Request(method, path string, body interface{}) error {
url := c.server.GetBaseURL() + path
req, err := http.NewRequest(method, url, nil)
var reqBody io.Reader
if body != nil {
// Handle different body types
switch b := body.(type) {
case []byte:
reqBody = bytes.NewReader(b)
case string:
reqBody = strings.NewReader(b)
case map[string]string:
jsonBody, err := json.Marshal(b)
if err != nil {
return fmt.Errorf("failed to marshal JSON body: %w", err)
}
reqBody = bytes.NewReader(jsonBody)
default:
return fmt.Errorf("unsupported body type: %T", body)
}
}
req, err := http.NewRequest(method, url, reqBody)
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}
// Set content type for JSON bodies
if body != nil && reqBody != nil {
req.Header.Set("Content-Type", "application/json")
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
@@ -41,6 +68,53 @@ func (c *Client) Request(method, path string, body []byte) error {
return nil
}
func (c *Client) CustomRequest(method, path string, body interface{}) (*http.Response, error) {
url := c.server.GetBaseURL() + path
var reqBody io.Reader
if body != nil {
// Handle different body types
switch b := body.(type) {
case []byte:
reqBody = bytes.NewReader(b)
case string:
reqBody = strings.NewReader(b)
case map[string]string:
jsonBody, err := json.Marshal(b)
if err != nil {
return nil, fmt.Errorf("failed to marshal JSON body: %w", err)
}
reqBody = bytes.NewReader(jsonBody)
default:
return nil, fmt.Errorf("unsupported body type: %T", body)
}
}
req, err := http.NewRequest(method, url, reqBody)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
// Set content type for JSON bodies
if body != nil && reqBody != nil {
req.Header.Set("Content-Type", "application/json")
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
// Don't close the body here - let the caller handle it
c.lastResp = resp
c.lastBody, err = io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %w", err)
}
return resp, nil
}
func (c *Client) ExpectResponseBody(expected string) error {
if c.lastResp == nil {
return fmt.Errorf("no response received")