Skip to content

Commit

Permalink
Merge pull request #24 from gabrielg2020/structured-repsonses
Browse files Browse the repository at this point in the history
feat: structured responses
  • Loading branch information
0xnu authored Oct 12, 2024
2 parents 83bc22c + 90e8fc2 commit fd8d215
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 58 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
- name: Setup Go
uses: actions/setup-go@v3
with:
go-versions: ${{ matrix.go-version }}
go-version: ${{ matrix.go-version }}

- name: Install Dependencies
run: go mod download
Expand Down
19 changes: 6 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,12 @@ func main() {
printJSON(data)
}

func printJSON(data json.RawMessage) {
var prettyJSON map[string]interface{}
err := json.Unmarshal(data, &prettyJSON)
if err != nil {
log.Fatalf("failed to parse JSON: %v", err)
}

prettyData, err := json.MarshalIndent(prettyJSON, "", " ")
if err != nil {
log.Fatalf("failed to format JSON: %v", err)
}

fmt.Println(string(prettyData))
func printJSON[T any](data *T) {
prettyData, err := json.MarshalIndent(data, "", " ")
if err != nil {
log.Fatalf("failed to marshal vehicle data: %v", err)
}
fmt.Println(string(prettyData))
}
```

Expand Down
32 changes: 22 additions & 10 deletions mothistory.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ var errorMessages = map[int]string{
504: "Gateway Timeout - The upstream server failed to send a request in the time allowed by the server",
}

func (c *Client) doRequest(method, endpoint string, queryParams url.Values) ([]byte, error) {
func doRequest[T any](c *Client, method, endpoint string, queryParams url.Values)(*T, error) {
limiterCtx := context.Background()
if err := c.dayLimiter.Wait(limiterCtx); err != nil {
return nil, fmt.Errorf("daily quota exceeded: %v", err)
Expand Down Expand Up @@ -114,24 +114,30 @@ func (c *Client) doRequest(method, endpoint string, queryParams url.Values) ([]b
return nil, fmt.Errorf("%s", errMsg)
}

return body, nil
var structuredResponse T
err = json.Unmarshal(body, &structuredResponse)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal body: %v", err)
}

return &structuredResponse, nil
}

func (c *Client) GetByRegistration(registration string) (json.RawMessage, error) {
func (c *Client) GetByRegistration(registration string) (*VehicleDetailsResponse, error) {
endpoint := fmt.Sprintf("/registration/%s", url.PathEscape(registration))
return c.doRequest(http.MethodGet, endpoint, nil)
return doRequest[VehicleDetailsResponse](c, http.MethodGet, endpoint, nil)
}

func (c *Client) GetByVIN(vin string) (json.RawMessage, error) {
func (c *Client) GetByVIN(vin string) (*VehicleDetailsResponse, error) {
endpoint := fmt.Sprintf("/vin/%s", url.PathEscape(vin))
return c.doRequest(http.MethodGet, endpoint, nil)
return doRequest[VehicleDetailsResponse](c, http.MethodGet, endpoint, nil)
}

func (c *Client) GetBulkDownload() (json.RawMessage, error) {
return c.doRequest(http.MethodGet, "/bulk-download", nil)
func (c *Client) GetBulkDownload() (*BulkDownloadResponse, error) {
return doRequest[BulkDownloadResponse](c, http.MethodGet, "/bulk-download", nil)
}

func (c *Client) RenewCredentials(apiKeyValue, email string) (json.RawMessage, error) {
func (c *Client) RenewCredentials(apiKeyValue, email string) (*ClientSecretResponse, error) {
payload := url.Values{}
payload.Set("awsApiKeyValue", apiKeyValue)
payload.Set("email", email)
Expand Down Expand Up @@ -159,5 +165,11 @@ func (c *Client) RenewCredentials(apiKeyValue, email string) (json.RawMessage, e
return nil, fmt.Errorf("%s", errMsg)
}

return body, nil
var structuredResponse ClientSecretResponse
err = json.Unmarshal(body, &structuredResponse)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal body: %v", err)
}

return &structuredResponse, nil
}
44 changes: 10 additions & 34 deletions mothistory_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package mothistory

import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
Expand All @@ -22,7 +21,7 @@ func createMockServer() *httptest.Server {
})

handler.HandleFunc("/vin/BNR32305366", func(w http.ResponseWriter, r *http.Request) {
mockResponse := `{"vin": "BNR32305366"}`
mockResponse := `{"registration": "ML58FOU"}`
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, mockResponse)
Expand Down Expand Up @@ -60,14 +59,8 @@ func TestGetByRegistration(t *testing.T) {
t.Fatalf("GetByRegistration failed: %v", err)
}

var response map[string]interface{}
err = json.Unmarshal(data, &response)
if err != nil {
t.Fatalf("Failed to unmarshal response: %v", err)
}

if response["registration"] != registration {
t.Errorf("Expected registration %s, got %s", registration, response["registration"])
if data.Registration != registration {
t.Errorf("Expected registration %s, got %s", registration, data.Registration)
}
}

Expand All @@ -78,20 +71,15 @@ func TestGetByVIN(t *testing.T) {
BaseURL = mockServer.URL
client := createTestClient(mockServer)

registration := "ML58FOU"
vin := "BNR32305366"
data, err := client.GetByVIN(vin)
if err != nil {
t.Fatalf("GetByVIN failed: %v", err)
}

var response map[string]interface{}
err = json.Unmarshal(data, &response)
if err != nil {
t.Fatalf("Failed to unmarshal response: %v", err)
}

if response["vin"] != vin {
t.Errorf("Expected VIN %s, got %s", vin, response["vin"])
if data.Registration != registration {
t.Errorf("Expected registration %s, got %s", registration, data.Registration)
}
}

Expand All @@ -107,16 +95,10 @@ func TestGetBulkDownload(t *testing.T) {
t.Fatalf("GetBulkDownload failed: %v", err)
}

var response map[string]interface{}
err = json.Unmarshal(data, &response)
if err != nil {
t.Fatalf("Failed to unmarshal response: %v", err)
}

if _, ok := response["bulk"]; !ok {
if data.Bulk == nil {
t.Error("Expected 'bulk' key in response")
}
if _, ok := response["delta"]; !ok {
if data.Bulk == nil {
t.Error("Expected 'delta' key in response")
}
}
Expand All @@ -135,14 +117,8 @@ func TestRenewCredentials(t *testing.T) {
t.Fatalf("RenewCredentials failed: %v", err)
}

var response map[string]interface{}
err = json.Unmarshal(data, &response)
if err != nil {
t.Fatalf("Failed to unmarshal response: %v", err)
}

if _, ok := response["clientSecret"]; !ok {
t.Error("Expected 'clientSecret' key in response")
if len(data.ClientSecret) == 0 {
t.Error("Expected 'clientSecret' length > 0")
}
}

Expand Down
55 changes: 55 additions & 0 deletions responses.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package mothistory

import (
// "encoding/json"
)
// Response for {baseURL}/[registration|vin]/<registration|vin>
type VehicleDetailsResponse struct {
Registration string `json:"registration"`
Make string `json:"make"`
FirstUsedDate string `json:"firstUsedDate"`
FuelType string `json:"fuelType"`
PrimaryColour string `json:"primaryColour"`
RegistrationDate string `json:"registrationDate"`
ManufactureDate string `json:"manufactureDate"`
EngineSize string `json:"engineSize"`
HasOutstandingRecall string `json:"hasOutstandingRecall"`
MotTests []MOTTest `json:"motTests"`
}

type MOTTest struct {
CompletedDate string `json:"completedDate"`
TestResult string `json:"testResult"`
ExpiryDate string `json:"expiryDate"`
OdometerValue string `json:"odometerValue"`
OdometerUnit string `json:"odometerUnit"`
OdometerResultType string `json:"odometerResultType"`
MotTestNumber string `json:"motTestNumber"`
DataSource string `json:"dataSource"`
Location string `json:"location,omitempty"` // Optional field
Defects []Defect `json:"defects,omitempty"` // Optional field
}

type Defect struct {
Text string `json:"text"`
TypeOfDefect string `json:"type"`
Dangerous bool `json:"dangerous"`
}

// Response for {baseURL}/[bulk-download]
type BulkDownloadResponse struct {
Bulk []BulkDelta `json:"bulk"`
Delta []BulkDelta `json:"delta"`
}

type BulkDelta struct {
Filename string `json:"filename"`
DownloadURL string `json:"downloadUrl"`
FileSize int `json:"fileSize"`
FileCreatedOn string `json:"fileCreatedOn"`
}

// Response for v1/trade/[credentials]
type ClientSecretResponse struct {
ClientSecret string `json:"clientSecret"`
}

0 comments on commit fd8d215

Please sign in to comment.