Skip to content

Commit

Permalink
[SLT-131] +X-API-Version http header, +versions.json (#3108)
Browse files Browse the repository at this point in the history
* +X-API-Version http header, +versions.json

* lint

* switch to hard stop error upon version lookup failure

* error wrap

* lint

* versions.json path tweak

* abandoning versions.json in favor of versions.go

* lint

* convert json to struct

* lint

* lint

* tests for X-API-Version header
  • Loading branch information
parodime authored Sep 7, 2024
1 parent 8b8fe86 commit 0d552d9
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 0 deletions.
8 changes: 8 additions & 0 deletions services/rfq/api/rest/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ func NewHandler(db db.APIDB, cfg config.Config) *Handler {
}
}

// APIVersionMiddleware adds the X-API-Version header to the response with the current version # from versions.json file.
func APIVersionMiddleware(serverVersion string) gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Set("X-API-Version", serverVersion)
c.Next()
}
}

// ModifyQuote upserts a quote
//
// PUT /quotes
Expand Down
15 changes: 15 additions & 0 deletions services/rfq/api/rest/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package rest

import (
"context"

"fmt"
"net/http"
"sync"
Expand Down Expand Up @@ -33,6 +34,14 @@ import (

const meterName = "github.com/synapsecns/sanguine/services/rfq/api/rest"

func getCurrentVersion() (string, error) {
if len(APIversions.Versions) == 0 {
return "", fmt.Errorf("no versions found")
}

return APIversions.Versions[0].Version, nil
}

// QuoterAPIServer is a struct that holds the configuration, database connection, gin engine, RPC client, metrics handler, and fast bridge contracts.
// It is used to initialize and run the API server.
type QuoterAPIServer struct {
Expand Down Expand Up @@ -158,6 +167,12 @@ func (r *QuoterAPIServer) Run(ctx context.Context) error {
// TODO: Use Gin Helper
engine := ginhelper.New(logger)
h := NewHandler(r.db, r.cfg)

versionNumber, versionNumErr := getCurrentVersion()
if versionNumErr != nil {
return fmt.Errorf("could not get current API version: %w", versionNumErr)
}
engine.Use(APIVersionMiddleware(versionNumber))
engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler))

// Apply AuthMiddleware only to the PUT routes
Expand Down
24 changes: 24 additions & 0 deletions services/rfq/api/rest/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ func (c *ServerSuite) TestEIP191_SuccessfulSignature() {
c.Require().NoError(err)
}()

// Check for X-API-Version on the response
c.Equal(resp.Header.Get("X-API-Version"), rest.APIversions.Versions[0].Version)

// Assert that the response status code is HTTP 200 OK.
c.Equal(http.StatusOK, resp.StatusCode)
}
Expand Down Expand Up @@ -146,6 +149,9 @@ func (c *ServerSuite) TestEIP191_SuccessfulPutSubmission() {
_ = resp.Body.Close()
}()

// Check for X-API-Version on the response
c.Equal(resp.Header.Get("X-API-Version"), rest.APIversions.Versions[0].Version)

// Log the response body for debugging.
body, err := io.ReadAll(resp.Body)
c.Require().NoError(err)
Expand All @@ -170,6 +176,9 @@ func (c *ServerSuite) TestPutAndGetQuote() {
}()
c.Assert().Equal(http.StatusOK, putResp.StatusCode)

// Check for X-API-Version on the response
c.Equal(putResp.Header.Get("X-API-Version"), rest.APIversions.Versions[0].Version)

// Send GET request to verify the PUT
client := &http.Client{}
req, err := http.NewRequestWithContext(c.GetTestContext(), http.MethodGet, fmt.Sprintf("http://localhost:%d/quotes?originChainId=1&originTokenAddr=0xOriginTokenAddrdestChainId=42161&destTokenAddr=0xDestTokenAddr", c.port), nil)
Expand All @@ -182,6 +191,9 @@ func (c *ServerSuite) TestPutAndGetQuote() {
}()
c.Assert().Equal(http.StatusOK, getResp.StatusCode)

// Check for X-API-Version on the response
c.Equal(getResp.Header.Get("X-API-Version"), rest.APIversions.Versions[0].Version)

var quotes []*model.GetQuoteResponse
err = json.NewDecoder(getResp.Body).Decode(&quotes)
c.Require().NoError(err)
Expand Down Expand Up @@ -212,6 +224,9 @@ func (c *ServerSuite) TestPutAndGetQuoteByRelayer() {
}()
c.Assert().Equal(http.StatusOK, putResp.StatusCode)

// Check for X-API-Version on the response
c.Equal(putResp.Header.Get("X-API-Version"), rest.APIversions.Versions[0].Version)

// Send GET request to verify the PUT
client := &http.Client{}
req, err := http.NewRequestWithContext(c.GetTestContext(), http.MethodGet, fmt.Sprintf("http://localhost:%d/quotes?relayerAddress=%s", c.port, c.testWallet.Address().Hex()), nil)
Expand All @@ -224,6 +239,9 @@ func (c *ServerSuite) TestPutAndGetQuoteByRelayer() {
}()
c.Assert().Equal(http.StatusOK, getResp.StatusCode)

// Check for X-API-Version on the response
c.Equal(getResp.Header.Get("X-API-Version"), rest.APIversions.Versions[0].Version)

var quotes []*model.GetQuoteResponse
err = json.NewDecoder(getResp.Body).Decode(&quotes)
c.Require().NoError(err)
Expand Down Expand Up @@ -264,6 +282,9 @@ func (c *ServerSuite) TestMultiplePutRequestsWithIncorrectAuth() {
body, err := io.ReadAll(resp.Body)
c.Require().NoError(err)

// Check for X-API-Version on the response
c.Equal(resp.Header.Get("X-API-Version"), rest.APIversions.Versions[0].Version)

// Log the response body for debugging
fmt.Printf("Request %d response: Status: %d, Body: %s\n", i+1, resp.StatusCode, string(body))

Expand Down Expand Up @@ -323,6 +344,9 @@ func (c *ServerSuite) TestPutAck() {
err = resp.Body.Close()
c.Require().NoError(err)

// Check for X-API-Version on the response
c.Equal(resp.Header.Get("X-API-Version"), rest.APIversions.Versions[0].Version)

// Send another request with same txID
header, err = c.prepareAuthHeader(c.testWallet)
c.Require().NoError(err)
Expand Down
27 changes: 27 additions & 0 deletions services/rfq/api/rest/versions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package rest

// APIVersionHistory lists historical ApiVersion structs in descending chronological order (current version index 0), each containing further detail about the version.
type APIVersionHistory struct {
Versions []APIVersion `json:"versions"`
}

// APIVersion specifies the date of a particular API version along with any comments & alerts for integrators to review.
type APIVersion struct {
Version string `json:"version"`
Date string `json:"date"`
Comments string `json:"comments"`
Alerts string `json:"alerts"`
}

// APIversions contains version information for the Synapse RFQ API. Deprecation notices & other alerts, if any, will be listed here.
// Note: Items must be listed in descending chronological order (current version index 0).
var APIversions = APIVersionHistory{
Versions: []APIVersion{
{
Version: "1.0",
Date: "2024-01-01",
Comments: "",
Alerts: "",
},
},
}

0 comments on commit 0d552d9

Please sign in to comment.