Skip to content

Commit e511b70

Browse files
authored
Merge pull request #18 from rabbitprincess/feature/api
api: init api
2 parents 4753700 + c34318a commit e511b70

File tree

15 files changed

+999
-83
lines changed

15 files changed

+999
-83
lines changed

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ run:
77
test-e2e:
88
go test -v $(ROOT_DIR)/test/e2e
99

10+
generate-api:
11+
swag init -g api/server.go -o api/swagger --parseDependency
12+
1013
generate-abi:
1114
abigen --abi $(ROOT_DIR)/scheme/evm/eip3009/eip3009.abi \
1215
--pkg eip3009 \

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,9 @@ It Supports facilitator and client roles on EVM-compatible chains.
1212
# How to run
1313
```bash
1414
docker compose up
15-
```
15+
```
16+
17+
# Api Specification
18+
```
19+
/swagger/index.html
20+
```

api/server.go

Lines changed: 119 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,40 @@
11
package api
22

33
import (
4+
"encoding/base64"
5+
"encoding/json"
46
"net/http"
57

8+
"github.com/go-playground/validator/v10"
69
"github.com/labstack/echo/v4"
710
echomiddleware "github.com/labstack/echo/v4/middleware"
11+
_ "github.com/rabbitprincess/x402-facilitator/api/swagger"
12+
echoSwagger "github.com/swaggo/echo-swagger"
13+
814
"github.com/rabbitprincess/x402-facilitator/api/middleware"
915
"github.com/rabbitprincess/x402-facilitator/facilitator"
16+
"github.com/rabbitprincess/x402-facilitator/types"
1017
)
1118

12-
// server represents the HTTP server for the API
19+
// @title x402 Facilitator API
20+
// @version 1.0
21+
// @description API server for x402 payment facilitator
22+
// @host localhost:8080
23+
// @BasePath /
24+
// @schemes http
1325
type server struct {
1426
*echo.Echo
1527
facilitator facilitator.Facilitator
1628
}
1729

18-
// Ensure server implements http.Handler
1930
var _ http.Handler = (*server)(nil)
2031

21-
// NewServer creates and configures a new API server
2232
func NewServer(facilitator facilitator.Facilitator) *server {
2333
s := &server{
2434
Echo: echo.New(),
2535
facilitator: facilitator,
2636
}
2737

28-
// Register middleware
2938
s.Use(middleware.RequestID())
3039
s.Use(middleware.Logger())
3140
s.Use(middleware.ErrorWrapper())
@@ -34,9 +43,114 @@ func NewServer(facilitator facilitator.Facilitator) *server {
3443
}))
3544
s.Use(echomiddleware.CORS())
3645

37-
// Register routes
3846
s.POST("/verify", s.Verify)
3947
s.POST("/settle", s.Settle)
48+
s.GET("/supported", s.Supported)
49+
s.GET("/swagger/*", echoSwagger.WrapHandler)
4050

4151
return s
4252
}
53+
54+
var (
55+
validate = validator.New(validator.WithRequiredStructEnabled())
56+
)
57+
58+
// Settle handles payment settlement requests
59+
// @Summary Settle payment
60+
// @Description Settle a payment using the facilitator
61+
// @Tags payments
62+
// @Accept json
63+
// @Produce json
64+
// @Param body body types.PaymentSettleRequest true "Settlement request"
65+
// @Success 200 {object} types.PaymentSettleResponse
66+
// @Failure 400 {object} echo.HTTPError
67+
// @Failure 500 {object} echo.HTTPError
68+
// @Router /settle [post]
69+
func (s *server) Settle(c echo.Context) error {
70+
ctx := c.Request().Context()
71+
72+
requirement := &types.PaymentSettleRequest{}
73+
if err := json.NewDecoder(c.Request().Body).Decode(requirement); err != nil {
74+
return echo.NewHTTPError(http.StatusBadRequest, "Received malformed settlement request")
75+
}
76+
if err := validate.Struct(requirement); err != nil {
77+
return echo.NewHTTPError(http.StatusBadRequest, "Received invalid settlement request")
78+
}
79+
payment := &types.PaymentPayload{}
80+
paymentDecoded, err := base64.StdEncoding.DecodeString(requirement.PaymentHeader)
81+
if err != nil {
82+
return echo.NewHTTPError(http.StatusBadRequest, "Received malformed Payment header")
83+
}
84+
if err := json.Unmarshal(paymentDecoded, payment); err != nil {
85+
return echo.NewHTTPError(http.StatusBadRequest, "Received malformed Payment header")
86+
}
87+
if err := validate.Struct(payment); err != nil {
88+
return echo.NewHTTPError(http.StatusBadRequest, "Received invalid Payment header")
89+
}
90+
settle, err := s.facilitator.Settle(ctx, payment, &requirement.PaymentRequirements)
91+
if err != nil {
92+
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
93+
}
94+
return c.JSON(http.StatusOK, settle)
95+
}
96+
97+
// Verify handles payment verification requests
98+
// @Summary Verify payment
99+
// @Description Verify a payment using the facilitator
100+
// @Tags payments
101+
// @Accept json
102+
// @Produce json
103+
// @Param body body types.PaymentVerifyRequest true "Payment verification request"
104+
// @Success 200 {object} types.PaymentVerifyResponse
105+
// @Failure 400 {object} echo.HTTPError
106+
// @Failure 500 {object} echo.HTTPError
107+
// @Router /verify [post]
108+
func (s *server) Verify(c echo.Context) error {
109+
ctx := c.Request().Context()
110+
111+
// validate payment requirements
112+
requirement := &types.PaymentVerifyRequest{}
113+
if err := json.NewDecoder(c.Request().Body).Decode(requirement); err != nil {
114+
return echo.NewHTTPError(http.StatusBadRequest, "Received malformed payment requirements")
115+
}
116+
if err := validate.Struct(requirement); err != nil {
117+
return echo.NewHTTPError(http.StatusBadRequest, "Received invalid payment requirements")
118+
}
119+
120+
// validate payment payload
121+
payment := &types.PaymentPayload{}
122+
paymentDecoded, err := base64.StdEncoding.DecodeString(requirement.PaymentHeader)
123+
if err != nil {
124+
return echo.NewHTTPError(http.StatusBadRequest, "Received malformed Payment header")
125+
}
126+
if err := json.Unmarshal(paymentDecoded, payment); err != nil {
127+
return echo.NewHTTPError(http.StatusBadRequest, "Received malformed Payment header")
128+
}
129+
if err := validate.Struct(payment); err != nil {
130+
return echo.NewHTTPError(http.StatusBadRequest, "Received invalid Payment header")
131+
}
132+
133+
verified, err := s.facilitator.Verify(ctx, payment, &requirement.PaymentRequirements)
134+
if err != nil {
135+
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
136+
}
137+
138+
return c.JSON(http.StatusOK, verified)
139+
}
140+
141+
// Supported returns the list of supported payment kinds
142+
// @Summary List supported kinds
143+
// @Description Get supported payment kinds
144+
// @Tags payments
145+
// @Produce json
146+
// @Success 200 {array} types.SupportedKind
147+
// @Failure 404 {object} echo.HTTPError
148+
// @Router /supported [get]
149+
func (s *server) Supported(c echo.Context) error {
150+
kinds := s.facilitator.Supported()
151+
if len(kinds) == 0 {
152+
return echo.NewHTTPError(http.StatusNotFound, "No supported payment kinds found")
153+
}
154+
155+
return c.JSON(http.StatusOK, kinds)
156+
}

api/settle.go

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)