From 194083c313fc320456e427bbe76ab34cf6d4e7ef Mon Sep 17 00:00:00 2001 From: David Farr Date: Tue, 19 Dec 2023 15:40:26 -0800 Subject: [PATCH] Allow slashes in promise name --- internal/app/subsystems/api/http/http.go | 8 ++-- internal/app/subsystems/api/http/http_test.go | 46 ++++++++++++++----- internal/app/subsystems/api/http/promise.go | 8 ++-- internal/app/subsystems/api/http/schedule.go | 8 +++- internal/app/subsystems/api/http/util.go | 8 ++++ 5 files changed, 57 insertions(+), 21 deletions(-) create mode 100644 internal/app/subsystems/api/http/util.go diff --git a/internal/app/subsystems/api/http/http.go b/internal/app/subsystems/api/http/http.go index 30420800..2673d6a1 100644 --- a/internal/app/subsystems/api/http/http.go +++ b/internal/app/subsystems/api/http/http.go @@ -42,13 +42,13 @@ func New(api api.API, config *Config) api.Subsystem { // Promises API r.POST("/promises", s.createPromise) r.GET("/promises", s.searchPromises) - r.GET("/promises/:id", s.readPromise) - r.PATCH("/promises/:id", s.completePromise) + r.GET("/promises/*id", s.readPromise) + r.PATCH("/promises/*id", s.completePromise) // Schedules API r.POST("/schedules", s.createSchedule) - r.GET("/schedules/:id", s.readSchedule) - r.DELETE("/schedules/:id", s.deleteSchedule) + r.GET("/schedules/*id", s.readSchedule) + r.DELETE("/schedules/*id", s.deleteSchedule) return &Http{ config: config, diff --git a/internal/app/subsystems/api/http/http_test.go b/internal/app/subsystems/api/http/http_test.go index adb92e96..26070da6 100644 --- a/internal/app/subsystems/api/http/http_test.go +++ b/internal/app/subsystems/api/http/http_test.go @@ -84,6 +84,28 @@ func TestHttpServer(t *testing.T) { }, status: 200, }, + { + name: "ReadPromiseWithSlash", + path: "promises/foo/bar", + method: "GET", + req: &t_api.Request{ + Kind: t_api.ReadPromise, + ReadPromise: &t_api.ReadPromiseRequest{ + Id: "foo/bar", + }, + }, + res: &t_api.Response{ + Kind: t_api.ReadPromise, + ReadPromise: &t_api.ReadPromiseResponse{ + Status: t_api.StatusOK, + Promise: &promise.Promise{ + Id: "foo/bar", + State: promise.Pending, + }, + }, + }, + status: 200, + }, { name: "ReadPromiseNotFound", path: "promises/bar", @@ -302,7 +324,7 @@ func TestHttpServer(t *testing.T) { "Strict": "true", }, body: []byte(`{ - "id": "foo", + "id": "foo/bar", "param": { "headers": {"a":"a","b":"b","c":"c"}, "data": "cGVuZGluZw==" @@ -312,7 +334,7 @@ func TestHttpServer(t *testing.T) { req: &t_api.Request{ Kind: t_api.CreatePromise, CreatePromise: &t_api.CreatePromiseRequest{ - Id: "foo", + Id: "foo/bar", IdempotencyKey: test.IdempotencyKeyToPointer("bar"), Strict: true, Param: promise.Value{ @@ -327,7 +349,7 @@ func TestHttpServer(t *testing.T) { CreatePromise: &t_api.CreatePromiseResponse{ Status: t_api.StatusCreated, Promise: &promise.Promise{ - Id: "foo", + Id: "foo/bar", State: promise.Pending, }, }, @@ -369,7 +391,7 @@ func TestHttpServer(t *testing.T) { }, { name: "CancelPromise", - path: "promises/foo", + path: "promises/foo/bar", method: "PATCH", headers: map[string]string{ "Idempotency-Key": "bar", @@ -385,7 +407,7 @@ func TestHttpServer(t *testing.T) { req: &t_api.Request{ Kind: t_api.CancelPromise, CancelPromise: &t_api.CancelPromiseRequest{ - Id: "foo", + Id: "foo/bar", IdempotencyKey: test.IdempotencyKeyToPointer("bar"), Strict: true, Value: promise.Value{ @@ -399,7 +421,7 @@ func TestHttpServer(t *testing.T) { CancelPromise: &t_api.CompletePromiseResponse{ Status: t_api.StatusCreated, Promise: &promise.Promise{ - Id: "foo", + Id: "foo/bar", State: promise.Canceled, }, }, @@ -439,7 +461,7 @@ func TestHttpServer(t *testing.T) { }, { name: "ResolvePromise", - path: "promises/foo", + path: "promises/foo/bar", method: "PATCH", headers: map[string]string{ "Idempotency-Key": "bar", @@ -455,7 +477,7 @@ func TestHttpServer(t *testing.T) { req: &t_api.Request{ Kind: t_api.ResolvePromise, ResolvePromise: &t_api.ResolvePromiseRequest{ - Id: "foo", + Id: "foo/bar", IdempotencyKey: test.IdempotencyKeyToPointer("bar"), Strict: true, Value: promise.Value{ @@ -469,7 +491,7 @@ func TestHttpServer(t *testing.T) { ResolvePromise: &t_api.CompletePromiseResponse{ Status: t_api.StatusCreated, Promise: &promise.Promise{ - Id: "foo", + Id: "foo/bar", State: promise.Resolved, }, }, @@ -509,7 +531,7 @@ func TestHttpServer(t *testing.T) { }, { name: "RejectPromise", - path: "promises/foo", + path: "promises/foo/bar", method: "PATCH", headers: map[string]string{ "Idempotency-Key": "bar", @@ -525,7 +547,7 @@ func TestHttpServer(t *testing.T) { req: &t_api.Request{ Kind: t_api.RejectPromise, RejectPromise: &t_api.RejectPromiseRequest{ - Id: "foo", + Id: "foo/bar", IdempotencyKey: test.IdempotencyKeyToPointer("bar"), Strict: true, Value: promise.Value{ @@ -539,7 +561,7 @@ func TestHttpServer(t *testing.T) { RejectPromise: &t_api.CompletePromiseResponse{ Status: t_api.StatusCreated, Promise: &promise.Promise{ - Id: "foo", + Id: "foo/bar", State: promise.Rejected, }, }, diff --git a/internal/app/subsystems/api/http/promise.go b/internal/app/subsystems/api/http/promise.go index 019a362d..127c405b 100644 --- a/internal/app/subsystems/api/http/promise.go +++ b/internal/app/subsystems/api/http/promise.go @@ -16,13 +16,15 @@ import ( // Read Promise func (s *server) readPromise(c *gin.Context) { + id := ExtractId(c.Param("id")) + var header service.Header if err := c.ShouldBindHeader(&header); err != nil { c.JSON(http.StatusBadRequest, api.HandleValidationError(err)) return } - resp, err := s.service.ReadPromise(c.Param("id"), &header) + resp, err := s.service.ReadPromise(id, &header) if err != nil { var apiErr *api.APIErrorResponse if errors.As(err, &apiErr) { @@ -97,6 +99,8 @@ func (s *server) createPromise(c *gin.Context) { // Complete Promise func (s *server) completePromise(c *gin.Context) { + id := ExtractId(c.Param("id")) + var header service.CompletePromiseHeader if err := c.ShouldBindHeader(&header); err != nil { c.JSON(http.StatusBadRequest, api.HandleValidationError(err)) @@ -109,8 +113,6 @@ func (s *server) completePromise(c *gin.Context) { return } - id := c.Param("id") - var ( resp *t_api.CompletePromiseResponse err error diff --git a/internal/app/subsystems/api/http/schedule.go b/internal/app/subsystems/api/http/schedule.go index 89434f36..ec21b3bb 100644 --- a/internal/app/subsystems/api/http/schedule.go +++ b/internal/app/subsystems/api/http/schedule.go @@ -40,7 +40,9 @@ func (s *server) createSchedule(c *gin.Context) { // READ func (s *server) readSchedule(c *gin.Context) { - res, err := s.service.ReadSchedule(c.Param("id")) + id := ExtractId(c.Param("id")) + + res, err := s.service.ReadSchedule(id) if err != nil { var apiErr *api.APIErrorResponse if errors.As(err, &apiErr) { @@ -60,7 +62,9 @@ func (s *server) readSchedule(c *gin.Context) { // DELETE func (s *server) deleteSchedule(c *gin.Context) { - res, err := s.service.DeleteSchedule(c.Param("id")) + id := ExtractId(c.Param("id")) + + res, err := s.service.DeleteSchedule(id) if err != nil { var apiErr *api.APIErrorResponse if errors.As(err, &apiErr) { diff --git a/internal/app/subsystems/api/http/util.go b/internal/app/subsystems/api/http/util.go new file mode 100644 index 00000000..9744f795 --- /dev/null +++ b/internal/app/subsystems/api/http/util.go @@ -0,0 +1,8 @@ +package http + +import "github.com/resonatehq/resonate/internal/util" + +func ExtractId(id string) string { + util.Assert(len(id) > 0 && id[0] == '/', "invalid id, gin trailing ids should start with '/'") + return id[1:] +}