diff --git a/Makefile b/Makefile index 78a69a4ffd2..d0557991462 100644 --- a/Makefile +++ b/Makefile @@ -138,8 +138,8 @@ endif .PHONY: generate-openapi generate-openapi: - swagger-codegen generate -l go -i https://raw.githubusercontent.com/onflow/flow/master/openapi/access.yaml -D packageName=models,modelDocs=false,models -o engine/access/rest/models; - go fmt ./engine/access/rest/models + swagger-codegen generate -l go -i https://raw.githubusercontent.com/onflow/flow/master/openapi/access.yaml -D packageName=models,modelDocs=false,models -o engine/access/rest/http/models; + go fmt ./engine/access/rest/http/models .PHONY: generate generate: generate-proto generate-mocks generate-fvm-env-wrappers diff --git a/cmd/access/node_builder/access_node_builder.go b/cmd/access/node_builder/access_node_builder.go index a1519934cd1..a8f238ae0a3 100644 --- a/cmd/access/node_builder/access_node_builder.go +++ b/cmd/access/node_builder/access_node_builder.go @@ -48,7 +48,8 @@ import ( "github.com/onflow/flow-go/engine/access/ingestion/tx_error_messages" pingeng "github.com/onflow/flow-go/engine/access/ping" "github.com/onflow/flow-go/engine/access/rest" - "github.com/onflow/flow-go/engine/access/rest/routes" + commonrest "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/engine/access/rest/router" "github.com/onflow/flow-go/engine/access/rpc" "github.com/onflow/flow-go/engine/access/rpc/backend" rpcConnection "github.com/onflow/flow-go/engine/access/rpc/connection" @@ -224,7 +225,7 @@ func DefaultAccessNodeConfig() *AccessNodeConfig { WriteTimeout: rest.DefaultWriteTimeout, ReadTimeout: rest.DefaultReadTimeout, IdleTimeout: rest.DefaultIdleTimeout, - MaxRequestSize: routes.DefaultMaxRequestSize, + MaxRequestSize: commonrest.DefaultMaxRequestSize, }, MaxMsgSize: grpcutils.DefaultMaxMsgSize, CompressorName: grpcutils.NoCompressor, @@ -1724,7 +1725,7 @@ func (builder *FlowAccessNodeBuilder) Build() (cmd.Node, error) { return nil }). Module("rest metrics", func(node *cmd.NodeConfig) error { - m, err := metrics.NewRestCollector(routes.URLToRoute, node.MetricsRegisterer) + m, err := metrics.NewRestCollector(router.URLToRoute, node.MetricsRegisterer) if err != nil { return err } diff --git a/cmd/observer/node_builder/observer_builder.go b/cmd/observer/node_builder/observer_builder.go index 9a0bb552510..21fe924ac0d 100644 --- a/cmd/observer/node_builder/observer_builder.go +++ b/cmd/observer/node_builder/observer_builder.go @@ -43,7 +43,8 @@ import ( "github.com/onflow/flow-go/engine/access/index" "github.com/onflow/flow-go/engine/access/rest" restapiproxy "github.com/onflow/flow-go/engine/access/rest/apiproxy" - "github.com/onflow/flow-go/engine/access/rest/routes" + commonrest "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/engine/access/rest/router" "github.com/onflow/flow-go/engine/access/rpc" "github.com/onflow/flow-go/engine/access/rpc/backend" rpcConnection "github.com/onflow/flow-go/engine/access/rpc/connection" @@ -195,7 +196,7 @@ func DefaultObserverServiceConfig() *ObserverServiceConfig { WriteTimeout: rest.DefaultWriteTimeout, ReadTimeout: rest.DefaultReadTimeout, IdleTimeout: rest.DefaultIdleTimeout, - MaxRequestSize: routes.DefaultMaxRequestSize, + MaxRequestSize: commonrest.DefaultMaxRequestSize, }, MaxMsgSize: grpcutils.DefaultMaxMsgSize, CompressorName: grpcutils.NoCompressor, @@ -1691,7 +1692,7 @@ func (builder *ObserverServiceBuilder) enqueueRPCServer() { return nil }) builder.Module("rest metrics", func(node *cmd.NodeConfig) error { - m, err := metrics.NewRestCollector(routes.URLToRoute, node.MetricsRegisterer) + m, err := metrics.NewRestCollector(router.URLToRoute, node.MetricsRegisterer) if err != nil { return err } diff --git a/engine/access/handle_irrecoverable_state_test.go b/engine/access/handle_irrecoverable_state_test.go index 911ba5c2a53..303a542339a 100644 --- a/engine/access/handle_irrecoverable_state_test.go +++ b/engine/access/handle_irrecoverable_state_test.go @@ -22,7 +22,7 @@ import ( accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rest" - "github.com/onflow/flow-go/engine/access/rest/routes" + "github.com/onflow/flow-go/engine/access/rest/router" "github.com/onflow/flow-go/engine/access/rpc" "github.com/onflow/flow-go/engine/access/rpc/backend" statestreambackend "github.com/onflow/flow-go/engine/access/state_stream/backend" @@ -249,7 +249,7 @@ func (suite *IrrecoverableStateTestSuite) TestRestInconsistentNodeState() { // optionsForBlocksIdGetOpts returns options for the BlocksApi.BlocksIdGet function. func optionsForBlocksIdGetOpts() *restclient.BlocksApiBlocksIdGetOpts { return &restclient.BlocksApiBlocksIdGetOpts{ - Expand: optional.NewInterface([]string{routes.ExpandableFieldPayload}), + Expand: optional.NewInterface([]string{router.ExpandableFieldPayload}), Select_: optional.NewInterface([]string{"header.id"}), } } diff --git a/engine/access/rest/README.md b/engine/access/rest/README.md index d94af68c238..746f9ec2415 100644 --- a/engine/access/rest/README.md +++ b/engine/access/rest/README.md @@ -5,12 +5,15 @@ the [Flow OpenAPI definition](https://github.com/onflow/flow/blob/master/openapi available on our [docs site](https://docs.onflow.org/http-api/). ## Packages - - `rest`: The HTTP handlers for the server generator and the select filter, implementation of handling local requests. -- `middleware`: The common [middlewares](https://github.com/gorilla/mux#middleware) that all request pass through. -- `models`: The generated models using openapi generators and implementation of model builders. -- `request`: Implementation of API requests that provide validation for input data and build request models. -- `routes`: The common HTTP handlers for all the requests, tests for each request. +- `common`: Includes shared components for REST requests. + - `middleware`: The common [middlewares](https://github.com/gorilla/mux#middleware) that all request pass through. + - `models`: The common generated models using openapi generators. +- `http`: Implements core HTTP handling functionality for access node. + - `models`: The generated models using openapi generators and implementation of model builders. + - `request`: Implementation of API requests that provide validation for input data and build request models. + - `routes`: The HTTP handlers for all http requests, tests for each request. +- `router`: Implementation of building HTTP routers with common middleware and routes. - `apiproxy`: Implementation of proxy backend handler which includes the local backend and forwards the methods which can't be handled locally to an upstream using gRPC API. This is used by observers that don't have all data in their local db. @@ -19,7 +22,7 @@ local db. 1. Every incoming request passes through a common set of middlewares - logging middleware, query expandable and query select middleware defined in the middleware package. -2. Each request is then wrapped by our handler (`rest/handler.go`) and request input data is used to build the request +2. Each request is then wrapped by our handler (`rest/http/handler.go`) and request input data is used to build the request models defined in request package. 3. The request is then sent to the corresponding API handler based on the configuration in the router. 4. Each handler implements actions to perform the request (database lookups etc) and after the response is built using diff --git a/engine/access/rest/models/error.go b/engine/access/rest/common/error.go similarity index 98% rename from engine/access/rest/models/error.go rename to engine/access/rest/common/error.go index 2247b38743b..d39ad03e193 100644 --- a/engine/access/rest/models/error.go +++ b/engine/access/rest/common/error.go @@ -1,4 +1,4 @@ -package models +package common import "net/http" diff --git a/engine/access/rest/routes/http_handler.go b/engine/access/rest/common/http_request_handler.go similarity index 91% rename from engine/access/rest/routes/http_handler.go rename to engine/access/rest/common/http_request_handler.go index 35dbffd52fd..bb78ff5b3a3 100644 --- a/engine/access/rest/routes/http_handler.go +++ b/engine/access/rest/common/http_request_handler.go @@ -1,4 +1,4 @@ -package routes +package common import ( "encoding/json" @@ -11,7 +11,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/onflow/flow-go/engine/access/rest/models" + "github.com/onflow/flow-go/engine/access/rest/common/models" fvmErrors "github.com/onflow/flow-go/fvm/errors" "github.com/onflow/flow-go/model/flow" ) @@ -50,15 +50,15 @@ func (h *HttpHandler) VerifyRequest(w http.ResponseWriter, r *http.Request) erro r.Body = http.MaxBytesReader(w, r.Body, h.MaxRequestSize) err := r.ParseForm() if err != nil { - h.errorHandler(w, err, errLog) + h.ErrorHandler(w, err, errLog) return err } return nil } -func (h *HttpHandler) errorHandler(w http.ResponseWriter, err error, errorLogger zerolog.Logger) { +func (h *HttpHandler) ErrorHandler(w http.ResponseWriter, err error, errorLogger zerolog.Logger) { // rest status type error should be returned with status and user message provided - var statusErr models.StatusError + var statusErr StatusError if errors.As(err, &statusErr) { h.errorResponse(w, statusErr.Status(), statusErr.UserMessage(), errorLogger) return @@ -102,8 +102,8 @@ func (h *HttpHandler) errorHandler(w http.ResponseWriter, err error, errorLogger h.errorResponse(w, http.StatusInternalServerError, msg, errorLogger) } -// jsonResponse builds a JSON response and send it to the client -func (h *HttpHandler) jsonResponse(w http.ResponseWriter, code int, response interface{}, errLogger zerolog.Logger) { +// JsonResponse builds a JSON response and send it to the client +func (h *HttpHandler) JsonResponse(w http.ResponseWriter, code int, response interface{}, errLogger zerolog.Logger) { w.Header().Set("Content-Type", "application/json; charset=UTF-8") // serialize response to JSON and handler errors @@ -135,5 +135,5 @@ func (h *HttpHandler) errorResponse( Code: int32(returnCode), Message: responseMessage, } - h.jsonResponse(w, returnCode, modelError, logger) + h.JsonResponse(w, returnCode, modelError, logger) } diff --git a/engine/access/rest/middleware/common_query_params.go b/engine/access/rest/common/middleware/common_query_params.go similarity index 100% rename from engine/access/rest/middleware/common_query_params.go rename to engine/access/rest/common/middleware/common_query_params.go diff --git a/engine/access/rest/middleware/common_query_params_test.go b/engine/access/rest/common/middleware/common_query_params_test.go similarity index 100% rename from engine/access/rest/middleware/common_query_params_test.go rename to engine/access/rest/common/middleware/common_query_params_test.go diff --git a/engine/access/rest/middleware/logging.go b/engine/access/rest/common/middleware/logging.go similarity index 100% rename from engine/access/rest/middleware/logging.go rename to engine/access/rest/common/middleware/logging.go diff --git a/engine/access/rest/middleware/metrics.go b/engine/access/rest/common/middleware/metrics.go similarity index 100% rename from engine/access/rest/middleware/metrics.go rename to engine/access/rest/common/middleware/metrics.go diff --git a/engine/access/rest/middleware/request_attribute.go b/engine/access/rest/common/middleware/request_attribute.go similarity index 100% rename from engine/access/rest/middleware/request_attribute.go rename to engine/access/rest/common/middleware/request_attribute.go diff --git a/engine/access/rest/models/model_error.go b/engine/access/rest/common/models/model_error.go similarity index 100% rename from engine/access/rest/models/model_error.go rename to engine/access/rest/common/models/model_error.go diff --git a/engine/access/rest/request/request.go b/engine/access/rest/common/request.go similarity index 50% rename from engine/access/rest/request/request.go rename to engine/access/rest/common/request.go index e8eeda9d1e6..b0b4a67f501 100644 --- a/engine/access/rest/request/request.go +++ b/engine/access/rest/common/request.go @@ -1,4 +1,4 @@ -package request +package common import ( "net/http" @@ -6,7 +6,7 @@ import ( "github.com/gorilla/mux" - "github.com/onflow/flow-go/engine/access/rest/middleware" + "github.com/onflow/flow-go/engine/access/rest/common/middleware" "github.com/onflow/flow-go/model/flow" ) @@ -18,102 +18,6 @@ type Request struct { Chain flow.Chain } -func (rd *Request) GetScriptRequest() (GetScript, error) { - var req GetScript - err := req.Build(rd) - return req, err -} - -func (rd *Request) GetBlockRequest() (GetBlock, error) { - var req GetBlock - err := req.Build(rd) - return req, err -} - -func (rd *Request) GetBlockByIDsRequest() (GetBlockByIDs, error) { - var req GetBlockByIDs - err := req.Build(rd) - return req, err -} - -func (rd *Request) GetBlockPayloadRequest() (GetBlockPayload, error) { - var req GetBlockPayload - err := req.Build(rd) - return req, err -} - -func (rd *Request) GetCollectionRequest() (GetCollection, error) { - var req GetCollection - err := req.Build(rd) - return req, err -} - -func (rd *Request) GetAccountRequest() (GetAccount, error) { - var req GetAccount - err := req.Build(rd) - return req, err -} - -func (rd *Request) GetAccountBalanceRequest() (GetAccountBalance, error) { - var req GetAccountBalance - err := req.Build(rd) - return req, err -} - -func (rd *Request) GetAccountKeysRequest() (GetAccountKeys, error) { - var req GetAccountKeys - err := req.Build(rd) - return req, err -} - -func (rd *Request) GetAccountKeyRequest() (GetAccountKey, error) { - var req GetAccountKey - err := req.Build(rd) - return req, err -} - -func (rd *Request) GetExecutionResultByBlockIDsRequest() (GetExecutionResultByBlockIDs, error) { - var req GetExecutionResultByBlockIDs - err := req.Build(rd) - return req, err -} - -func (rd *Request) GetExecutionResultRequest() (GetExecutionResult, error) { - var req GetExecutionResult - err := req.Build(rd) - return req, err -} - -func (rd *Request) GetTransactionRequest() (GetTransaction, error) { - var req GetTransaction - err := req.Build(rd) - return req, err -} - -func (rd *Request) GetTransactionResultRequest() (GetTransactionResult, error) { - var req GetTransactionResult - err := req.Build(rd) - return req, err -} - -func (rd *Request) GetEventsRequest() (GetEvents, error) { - var req GetEvents - err := req.Build(rd) - return req, err -} - -func (rd *Request) CreateTransactionRequest() (CreateTransaction, error) { - var req CreateTransaction - err := req.Build(rd) - return req, err -} - -func (rd *Request) SubscribeEventsRequest() (SubscribeEvents, error) { - var req SubscribeEvents - err := req.Build(rd) - return req, err -} - func (rd *Request) Expands(field string) bool { return rd.ExpandFields[field] } diff --git a/engine/access/rest/routes/handler.go b/engine/access/rest/http/handler.go similarity index 81% rename from engine/access/rest/routes/handler.go rename to engine/access/rest/http/handler.go index 6c05266a8f5..cac602a6888 100644 --- a/engine/access/rest/routes/handler.go +++ b/engine/access/rest/http/handler.go @@ -1,4 +1,4 @@ -package routes +package http import ( "net/http" @@ -6,8 +6,8 @@ import ( "github.com/rs/zerolog" "github.com/onflow/flow-go/access" - "github.com/onflow/flow-go/engine/access/rest/models" - "github.com/onflow/flow-go/engine/access/rest/request" + "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/engine/access/rest/http/models" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/model/flow" ) @@ -15,7 +15,7 @@ import ( // ApiHandlerFunc is a function that contains endpoint handling logic, // it fetches necessary resources and returns an error or response model. type ApiHandlerFunc func( - r *request.Request, + r *common.Request, backend access.API, generator models.LinkGenerator, ) (interface{}, error) @@ -24,7 +24,7 @@ type ApiHandlerFunc func( // Handler function allows easier handling of errors and responses as it // wraps functionality for handling error and responses outside of endpoint handling. type Handler struct { - *HttpHandler + *common.HttpHandler backend access.API linkGenerator models.LinkGenerator apiHandlerFunc ApiHandlerFunc @@ -42,7 +42,7 @@ func NewHandler( backend: backend, apiHandlerFunc: handlerFunc, linkGenerator: generator, - HttpHandler: NewHttpHandler(logger, chain, maxRequestSize), + HttpHandler: common.NewHttpHandler(logger, chain, maxRequestSize), } return handler @@ -58,22 +58,22 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if err != nil { return } - decoratedRequest := request.Decorate(r, h.Chain) + decoratedRequest := common.Decorate(r, h.Chain) // execute handler function and check for error response, err := h.apiHandlerFunc(decoratedRequest, h.backend, h.linkGenerator) if err != nil { - h.errorHandler(w, err, errLog) + h.ErrorHandler(w, err, errLog) return } // apply the select filter if any select fields have been specified response, err = util.SelectFilter(response, decoratedRequest.Selects()) if err != nil { - h.errorHandler(w, err, errLog) + h.ErrorHandler(w, err, errLog) return } // write response to response stream - h.jsonResponse(w, http.StatusOK, response, errLog) + h.JsonResponse(w, http.StatusOK, response, errLog) } diff --git a/engine/access/rest/models/account.go b/engine/access/rest/http/models/account.go similarity index 100% rename from engine/access/rest/models/account.go rename to engine/access/rest/http/models/account.go diff --git a/engine/access/rest/models/block.go b/engine/access/rest/http/models/block.go similarity index 100% rename from engine/access/rest/models/block.go rename to engine/access/rest/http/models/block.go diff --git a/engine/access/rest/models/collection.go b/engine/access/rest/http/models/collection.go similarity index 100% rename from engine/access/rest/models/collection.go rename to engine/access/rest/http/models/collection.go diff --git a/engine/access/rest/models/enums.go b/engine/access/rest/http/models/enums.go similarity index 100% rename from engine/access/rest/models/enums.go rename to engine/access/rest/http/models/enums.go diff --git a/engine/access/rest/models/event.go b/engine/access/rest/http/models/event.go similarity index 100% rename from engine/access/rest/models/event.go rename to engine/access/rest/http/models/event.go diff --git a/engine/access/rest/models/execution_result.go b/engine/access/rest/http/models/execution_result.go similarity index 100% rename from engine/access/rest/models/execution_result.go rename to engine/access/rest/http/models/execution_result.go diff --git a/engine/access/rest/models/link.go b/engine/access/rest/http/models/link.go similarity index 100% rename from engine/access/rest/models/link.go rename to engine/access/rest/http/models/link.go diff --git a/engine/access/rest/models/model_account.go b/engine/access/rest/http/models/model_account.go similarity index 100% rename from engine/access/rest/models/model_account.go rename to engine/access/rest/http/models/model_account.go diff --git a/engine/access/rest/models/model_account__expandable.go b/engine/access/rest/http/models/model_account__expandable.go similarity index 100% rename from engine/access/rest/models/model_account__expandable.go rename to engine/access/rest/http/models/model_account__expandable.go diff --git a/engine/access/rest/models/model_account_balance.go b/engine/access/rest/http/models/model_account_balance.go similarity index 100% rename from engine/access/rest/models/model_account_balance.go rename to engine/access/rest/http/models/model_account_balance.go diff --git a/engine/access/rest/models/model_account_public_key.go b/engine/access/rest/http/models/model_account_public_key.go similarity index 100% rename from engine/access/rest/models/model_account_public_key.go rename to engine/access/rest/http/models/model_account_public_key.go diff --git a/engine/access/rest/models/model_account_public_keys.go b/engine/access/rest/http/models/model_account_public_keys.go similarity index 100% rename from engine/access/rest/models/model_account_public_keys.go rename to engine/access/rest/http/models/model_account_public_keys.go diff --git a/engine/access/rest/models/model_aggregated_signature.go b/engine/access/rest/http/models/model_aggregated_signature.go similarity index 100% rename from engine/access/rest/models/model_aggregated_signature.go rename to engine/access/rest/http/models/model_aggregated_signature.go diff --git a/engine/access/rest/models/model_block.go b/engine/access/rest/http/models/model_block.go similarity index 100% rename from engine/access/rest/models/model_block.go rename to engine/access/rest/http/models/model_block.go diff --git a/engine/access/rest/models/model_block__expandable.go b/engine/access/rest/http/models/model_block__expandable.go similarity index 100% rename from engine/access/rest/models/model_block__expandable.go rename to engine/access/rest/http/models/model_block__expandable.go diff --git a/engine/access/rest/models/model_block_events.go b/engine/access/rest/http/models/model_block_events.go similarity index 100% rename from engine/access/rest/models/model_block_events.go rename to engine/access/rest/http/models/model_block_events.go diff --git a/engine/access/rest/models/model_block_header.go b/engine/access/rest/http/models/model_block_header.go similarity index 100% rename from engine/access/rest/models/model_block_header.go rename to engine/access/rest/http/models/model_block_header.go diff --git a/engine/access/rest/models/model_block_height.go b/engine/access/rest/http/models/model_block_height.go similarity index 100% rename from engine/access/rest/models/model_block_height.go rename to engine/access/rest/http/models/model_block_height.go diff --git a/engine/access/rest/models/model_block_payload.go b/engine/access/rest/http/models/model_block_payload.go similarity index 100% rename from engine/access/rest/models/model_block_payload.go rename to engine/access/rest/http/models/model_block_payload.go diff --git a/engine/access/rest/models/model_block_seal.go b/engine/access/rest/http/models/model_block_seal.go similarity index 100% rename from engine/access/rest/models/model_block_seal.go rename to engine/access/rest/http/models/model_block_seal.go diff --git a/engine/access/rest/models/model_chunk.go b/engine/access/rest/http/models/model_chunk.go similarity index 100% rename from engine/access/rest/models/model_chunk.go rename to engine/access/rest/http/models/model_chunk.go diff --git a/engine/access/rest/models/model_collection.go b/engine/access/rest/http/models/model_collection.go similarity index 100% rename from engine/access/rest/models/model_collection.go rename to engine/access/rest/http/models/model_collection.go diff --git a/engine/access/rest/models/model_collection__expandable.go b/engine/access/rest/http/models/model_collection__expandable.go similarity index 100% rename from engine/access/rest/models/model_collection__expandable.go rename to engine/access/rest/http/models/model_collection__expandable.go diff --git a/engine/access/rest/models/model_collection_guarantee.go b/engine/access/rest/http/models/model_collection_guarantee.go similarity index 100% rename from engine/access/rest/models/model_collection_guarantee.go rename to engine/access/rest/http/models/model_collection_guarantee.go diff --git a/engine/access/rest/models/model_compatible_range.go b/engine/access/rest/http/models/model_compatible_range.go similarity index 100% rename from engine/access/rest/models/model_compatible_range.go rename to engine/access/rest/http/models/model_compatible_range.go diff --git a/engine/access/rest/models/model_event.go b/engine/access/rest/http/models/model_event.go similarity index 100% rename from engine/access/rest/models/model_event.go rename to engine/access/rest/http/models/model_event.go diff --git a/engine/access/rest/models/model_execution_result.go b/engine/access/rest/http/models/model_execution_result.go similarity index 100% rename from engine/access/rest/models/model_execution_result.go rename to engine/access/rest/http/models/model_execution_result.go diff --git a/engine/access/rest/models/model_hashing_algorithm.go b/engine/access/rest/http/models/model_hashing_algorithm.go similarity index 100% rename from engine/access/rest/models/model_hashing_algorithm.go rename to engine/access/rest/http/models/model_hashing_algorithm.go diff --git a/engine/access/rest/models/model_inline_response_200.go b/engine/access/rest/http/models/model_inline_response_200.go similarity index 100% rename from engine/access/rest/models/model_inline_response_200.go rename to engine/access/rest/http/models/model_inline_response_200.go diff --git a/engine/access/rest/models/model_links.go b/engine/access/rest/http/models/model_links.go similarity index 100% rename from engine/access/rest/models/model_links.go rename to engine/access/rest/http/models/model_links.go diff --git a/engine/access/rest/models/model_network_parameters.go b/engine/access/rest/http/models/model_network_parameters.go similarity index 100% rename from engine/access/rest/models/model_network_parameters.go rename to engine/access/rest/http/models/model_network_parameters.go diff --git a/engine/access/rest/models/model_node_version_info.go b/engine/access/rest/http/models/model_node_version_info.go similarity index 100% rename from engine/access/rest/models/model_node_version_info.go rename to engine/access/rest/http/models/model_node_version_info.go diff --git a/engine/access/rest/models/model_one_of_block_height.go b/engine/access/rest/http/models/model_one_of_block_height.go similarity index 100% rename from engine/access/rest/models/model_one_of_block_height.go rename to engine/access/rest/http/models/model_one_of_block_height.go diff --git a/engine/access/rest/models/model_proposal_key.go b/engine/access/rest/http/models/model_proposal_key.go similarity index 100% rename from engine/access/rest/models/model_proposal_key.go rename to engine/access/rest/http/models/model_proposal_key.go diff --git a/engine/access/rest/models/model_scripts_body.go b/engine/access/rest/http/models/model_scripts_body.go similarity index 100% rename from engine/access/rest/models/model_scripts_body.go rename to engine/access/rest/http/models/model_scripts_body.go diff --git a/engine/access/rest/models/model_signing_algorithm.go b/engine/access/rest/http/models/model_signing_algorithm.go similarity index 100% rename from engine/access/rest/models/model_signing_algorithm.go rename to engine/access/rest/http/models/model_signing_algorithm.go diff --git a/engine/access/rest/models/model_transaction.go b/engine/access/rest/http/models/model_transaction.go similarity index 100% rename from engine/access/rest/models/model_transaction.go rename to engine/access/rest/http/models/model_transaction.go diff --git a/engine/access/rest/models/model_transaction__expandable.go b/engine/access/rest/http/models/model_transaction__expandable.go similarity index 100% rename from engine/access/rest/models/model_transaction__expandable.go rename to engine/access/rest/http/models/model_transaction__expandable.go diff --git a/engine/access/rest/models/model_transaction_execution.go b/engine/access/rest/http/models/model_transaction_execution.go similarity index 100% rename from engine/access/rest/models/model_transaction_execution.go rename to engine/access/rest/http/models/model_transaction_execution.go diff --git a/engine/access/rest/models/model_transaction_result.go b/engine/access/rest/http/models/model_transaction_result.go similarity index 100% rename from engine/access/rest/models/model_transaction_result.go rename to engine/access/rest/http/models/model_transaction_result.go diff --git a/engine/access/rest/models/model_transaction_result__expandable.go b/engine/access/rest/http/models/model_transaction_result__expandable.go similarity index 100% rename from engine/access/rest/models/model_transaction_result__expandable.go rename to engine/access/rest/http/models/model_transaction_result__expandable.go diff --git a/engine/access/rest/models/model_transaction_signature.go b/engine/access/rest/http/models/model_transaction_signature.go similarity index 100% rename from engine/access/rest/models/model_transaction_signature.go rename to engine/access/rest/http/models/model_transaction_signature.go diff --git a/engine/access/rest/models/model_transaction_status.go b/engine/access/rest/http/models/model_transaction_status.go similarity index 100% rename from engine/access/rest/models/model_transaction_status.go rename to engine/access/rest/http/models/model_transaction_status.go diff --git a/engine/access/rest/models/model_transactions_body.go b/engine/access/rest/http/models/model_transactions_body.go similarity index 100% rename from engine/access/rest/models/model_transactions_body.go rename to engine/access/rest/http/models/model_transactions_body.go diff --git a/engine/access/rest/models/network.go b/engine/access/rest/http/models/network.go similarity index 100% rename from engine/access/rest/models/network.go rename to engine/access/rest/http/models/network.go diff --git a/engine/access/rest/models/node_version_info.go b/engine/access/rest/http/models/node_version_info.go similarity index 100% rename from engine/access/rest/models/node_version_info.go rename to engine/access/rest/http/models/node_version_info.go diff --git a/engine/access/rest/models/transaction.go b/engine/access/rest/http/models/transaction.go similarity index 100% rename from engine/access/rest/models/transaction.go rename to engine/access/rest/http/models/transaction.go diff --git a/engine/access/rest/request/address.go b/engine/access/rest/http/request/address.go similarity index 100% rename from engine/access/rest/request/address.go rename to engine/access/rest/http/request/address.go diff --git a/engine/access/rest/request/address_test.go b/engine/access/rest/http/request/address_test.go similarity index 100% rename from engine/access/rest/request/address_test.go rename to engine/access/rest/http/request/address_test.go diff --git a/engine/access/rest/request/arguments.go b/engine/access/rest/http/request/arguments.go similarity index 100% rename from engine/access/rest/request/arguments.go rename to engine/access/rest/http/request/arguments.go diff --git a/engine/access/rest/request/arguments_test.go b/engine/access/rest/http/request/arguments_test.go similarity index 100% rename from engine/access/rest/request/arguments_test.go rename to engine/access/rest/http/request/arguments_test.go diff --git a/engine/access/rest/request/create_transaction.go b/engine/access/rest/http/request/create_transaction.go similarity index 60% rename from engine/access/rest/request/create_transaction.go rename to engine/access/rest/http/request/create_transaction.go index 3fa8bdafb94..951cede2c58 100644 --- a/engine/access/rest/request/create_transaction.go +++ b/engine/access/rest/http/request/create_transaction.go @@ -3,6 +3,7 @@ package request import ( "io" + "github.com/onflow/flow-go/engine/access/rest/common" "github.com/onflow/flow-go/model/flow" ) @@ -10,7 +11,13 @@ type CreateTransaction struct { Transaction flow.TransactionBody } -func (c *CreateTransaction) Build(r *Request) error { +func CreateTransactionRequest(r *common.Request) (CreateTransaction, error) { + var req CreateTransaction + err := req.Build(r) + return req, err +} + +func (c *CreateTransaction) Build(r *common.Request) error { return c.Parse(r.Body, r.Chain) } diff --git a/engine/access/rest/request/event_type.go b/engine/access/rest/http/request/event_type.go similarity index 100% rename from engine/access/rest/request/event_type.go rename to engine/access/rest/http/request/event_type.go diff --git a/engine/access/rest/request/get_account.go b/engine/access/rest/http/request/get_account.go similarity index 61% rename from engine/access/rest/request/get_account.go rename to engine/access/rest/http/request/get_account.go index 4d0a1b2bf54..8beba0cce58 100644 --- a/engine/access/rest/request/get_account.go +++ b/engine/access/rest/http/request/get_account.go @@ -1,6 +1,7 @@ package request import ( + "github.com/onflow/flow-go/engine/access/rest/common" "github.com/onflow/flow-go/model/flow" ) @@ -12,7 +13,17 @@ type GetAccount struct { Height uint64 } -func (g *GetAccount) Build(r *Request) error { +// GetAccountRequest extracts necessary variables and query parameters from the provided request, +// builds a GetAccount instance, and validates it. +// +// No errors are expected during normal operation. +func GetAccountRequest(r *common.Request) (GetAccount, error) { + var req GetAccount + err := req.Build(r) + return req, err +} + +func (g *GetAccount) Build(r *common.Request) error { return g.Parse( r.GetVar(addressVar), r.GetQueryParam(blockHeightQuery), diff --git a/engine/access/rest/request/get_account_balance.go b/engine/access/rest/http/request/get_account_balance.go similarity index 57% rename from engine/access/rest/request/get_account_balance.go rename to engine/access/rest/http/request/get_account_balance.go index 42347c3b102..8a5887e2e82 100644 --- a/engine/access/rest/request/get_account_balance.go +++ b/engine/access/rest/http/request/get_account_balance.go @@ -1,6 +1,7 @@ package request import ( + "github.com/onflow/flow-go/engine/access/rest/common" "github.com/onflow/flow-go/model/flow" ) @@ -9,7 +10,17 @@ type GetAccountBalance struct { Height uint64 } -func (g *GetAccountBalance) Build(r *Request) error { +// GetAccountBalanceRequest extracts necessary variables and query parameters from the provided request, +// builds a GetAccountBalance instance, and validates it. +// +// No errors are expected during normal operation. +func GetAccountBalanceRequest(r *common.Request) (GetAccountBalance, error) { + var req GetAccountBalance + err := req.Build(r) + return req, err +} + +func (g *GetAccountBalance) Build(r *common.Request) error { return g.Parse( r.GetVar(addressVar), r.GetQueryParam(blockHeightQuery), diff --git a/engine/access/rest/request/get_account_balance_test.go b/engine/access/rest/http/request/get_account_balance_test.go similarity index 100% rename from engine/access/rest/request/get_account_balance_test.go rename to engine/access/rest/http/request/get_account_balance_test.go diff --git a/engine/access/rest/request/get_account_key.go b/engine/access/rest/http/request/get_account_key.go similarity index 66% rename from engine/access/rest/request/get_account_key.go rename to engine/access/rest/http/request/get_account_key.go index 2d6466e19bc..91826671f51 100644 --- a/engine/access/rest/request/get_account_key.go +++ b/engine/access/rest/http/request/get_account_key.go @@ -3,6 +3,7 @@ package request import ( "fmt" + "github.com/onflow/flow-go/engine/access/rest/common" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/model/flow" ) @@ -15,7 +16,17 @@ type GetAccountKey struct { Height uint64 } -func (g *GetAccountKey) Build(r *Request) error { +// GetAccountKeyRequest extracts necessary variables and query parameters from the provided request, +// builds a GetAccountKey instance, and validates it. +// +// No errors are expected during normal operation. +func GetAccountKeyRequest(r *common.Request) (GetAccountKey, error) { + var req GetAccountKey + err := req.Build(r) + return req, err +} + +func (g *GetAccountKey) Build(r *common.Request) error { return g.Parse( r.GetVar(addressVar), r.GetVar(indexVar), diff --git a/engine/access/rest/request/get_account_key_test.go b/engine/access/rest/http/request/get_account_key_test.go similarity index 100% rename from engine/access/rest/request/get_account_key_test.go rename to engine/access/rest/http/request/get_account_key_test.go diff --git a/engine/access/rest/request/get_account_keys.go b/engine/access/rest/http/request/get_account_keys.go similarity index 58% rename from engine/access/rest/request/get_account_keys.go rename to engine/access/rest/http/request/get_account_keys.go index 6580135648f..689d9f3d765 100644 --- a/engine/access/rest/request/get_account_keys.go +++ b/engine/access/rest/http/request/get_account_keys.go @@ -1,6 +1,7 @@ package request import ( + "github.com/onflow/flow-go/engine/access/rest/common" "github.com/onflow/flow-go/model/flow" ) @@ -9,7 +10,17 @@ type GetAccountKeys struct { Height uint64 } -func (g *GetAccountKeys) Build(r *Request) error { +// GetAccountKeysRequest extracts necessary variables and query parameters from the provided request, +// builds a GetAccountKeys instance, and validates it. +// +// No errors are expected during normal operation. +func GetAccountKeysRequest(r *common.Request) (GetAccountKeys, error) { + var req GetAccountKeys + err := req.Build(r) + return req, err +} + +func (g *GetAccountKeys) Build(r *common.Request) error { return g.Parse( r.GetVar(addressVar), r.GetQueryParam(blockHeightQuery), diff --git a/engine/access/rest/request/get_account_keys_test.go b/engine/access/rest/http/request/get_account_keys_test.go similarity index 100% rename from engine/access/rest/request/get_account_keys_test.go rename to engine/access/rest/http/request/get_account_keys_test.go diff --git a/engine/access/rest/request/get_account_test.go b/engine/access/rest/http/request/get_account_test.go similarity index 100% rename from engine/access/rest/request/get_account_test.go rename to engine/access/rest/http/request/get_account_test.go diff --git a/engine/access/rest/request/get_block.go b/engine/access/rest/http/request/get_block.go similarity index 72% rename from engine/access/rest/request/get_block.go rename to engine/access/rest/http/request/get_block.go index 4a4a1cd319d..fd74b0e4be0 100644 --- a/engine/access/rest/request/get_block.go +++ b/engine/access/rest/http/request/get_block.go @@ -3,6 +3,7 @@ package request import ( "fmt" + "github.com/onflow/flow-go/engine/access/rest/common" "github.com/onflow/flow-go/model/flow" ) @@ -20,7 +21,17 @@ type GetBlock struct { SealedHeight bool } -func (g *GetBlock) Build(r *Request) error { +// GetBlockRequest extracts necessary query parameters from the provided request, +// builds a GetBlock instance, and validates it. +// +// No errors are expected during normal operation. +func GetBlockRequest(r *common.Request) (GetBlock, error) { + var req GetBlock + err := req.Build(r) + return req, err +} + +func (g *GetBlock) Build(r *common.Request) error { return g.Parse( r.GetQueryParams(heightQuery), r.GetQueryParam(startHeightQuery), @@ -94,7 +105,17 @@ type GetBlockByIDs struct { IDs []flow.Identifier } -func (g *GetBlockByIDs) Build(r *Request) error { +// GetBlockByIDsRequest extracts necessary variables from the provided request, +// builds a GetBlockByIDs instance, and validates it. +// +// No errors are expected during normal operation. +func GetBlockByIDsRequest(r *common.Request) (GetBlockByIDs, error) { + var req GetBlockByIDs + err := req.Build(r) + return req, err +} + +func (g *GetBlockByIDs) Build(r *common.Request) error { return g.Parse( r.GetVars(idParam), ) @@ -114,3 +135,13 @@ func (g *GetBlockByIDs) Parse(rawIds []string) error { type GetBlockPayload struct { GetByIDRequest } + +// GetBlockPayloadRequest extracts necessary variables from the provided request, +// builds a GetBlockPayload instance, and validates it. +// +// No errors are expected during normal operation. +func GetBlockPayloadRequest(r *common.Request) (GetBlockPayload, error) { + var req GetBlockPayload + err := req.Build(r) + return req, err +} diff --git a/engine/access/rest/request/get_block_test.go b/engine/access/rest/http/request/get_block_test.go similarity index 100% rename from engine/access/rest/request/get_block_test.go rename to engine/access/rest/http/request/get_block_test.go diff --git a/engine/access/rest/http/request/get_collection.go b/engine/access/rest/http/request/get_collection.go new file mode 100644 index 00000000000..f7af68a6dcf --- /dev/null +++ b/engine/access/rest/http/request/get_collection.go @@ -0,0 +1,29 @@ +package request + +import ( + "github.com/onflow/flow-go/engine/access/rest/common" +) + +const ExpandsTransactions = "transactions" + +type GetCollection struct { + GetByIDRequest + ExpandsTransactions bool +} + +// GetCollectionRequest extracts necessary variables from the provided request, +// builds a GetCollection instance, and validates it. +// +// No errors are expected during normal operation. +func GetCollectionRequest(r *common.Request) (GetCollection, error) { + var req GetCollection + err := req.Build(r) + return req, err +} + +func (g *GetCollection) Build(r *common.Request) error { + err := g.GetByIDRequest.Build(r) + g.ExpandsTransactions = r.Expands(ExpandsTransactions) + + return err +} diff --git a/engine/access/rest/request/get_events.go b/engine/access/rest/http/request/get_events.go similarity index 84% rename from engine/access/rest/request/get_events.go rename to engine/access/rest/http/request/get_events.go index b9adcbe0f19..39f2ba9faef 100644 --- a/engine/access/rest/request/get_events.go +++ b/engine/access/rest/http/request/get_events.go @@ -3,6 +3,7 @@ package request import ( "fmt" + "github.com/onflow/flow-go/engine/access/rest/common" "github.com/onflow/flow-go/model/flow" ) @@ -17,7 +18,17 @@ type GetEvents struct { BlockIDs []flow.Identifier } -func (g *GetEvents) Build(r *Request) error { +// GetEventsRequest extracts necessary variables from the provided request, +// builds a GetEvents instance, and validates it. +// +// No errors are expected during normal operation. +func GetEventsRequest(r *common.Request) (GetEvents, error) { + var req GetEvents + err := req.Build(r) + return req, err +} + +func (g *GetEvents) Build(r *common.Request) error { return g.Parse( r.GetQueryParam(eventTypeQuery), r.GetQueryParam(startHeightQuery), diff --git a/engine/access/rest/request/get_events_test.go b/engine/access/rest/http/request/get_events_test.go similarity index 100% rename from engine/access/rest/request/get_events_test.go rename to engine/access/rest/http/request/get_events_test.go diff --git a/engine/access/rest/http/request/get_execution_result.go b/engine/access/rest/http/request/get_execution_result.go new file mode 100644 index 00000000000..cdf216766c1 --- /dev/null +++ b/engine/access/rest/http/request/get_execution_result.go @@ -0,0 +1,59 @@ +package request + +import ( + "fmt" + + "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/model/flow" +) + +const idQuery = "id" + +type GetExecutionResultByBlockIDs struct { + BlockIDs []flow.Identifier +} + +// GetExecutionResultByBlockIDsRequest extracts necessary variables from the provided request, +// builds a GetExecutionResultByBlockIDs instance, and validates it. +// +// No errors are expected during normal operation. +func GetExecutionResultByBlockIDsRequest(r *common.Request) (GetExecutionResultByBlockIDs, error) { + var req GetExecutionResultByBlockIDs + err := req.Build(r) + return req, err +} + +func (g *GetExecutionResultByBlockIDs) Build(r *common.Request) error { + return g.Parse( + r.GetQueryParams(blockIDQuery), + ) +} + +func (g *GetExecutionResultByBlockIDs) Parse(rawIDs []string) error { + var ids IDs + err := ids.Parse(rawIDs) + if err != nil { + return err + } + g.BlockIDs = ids.Flow() + + if len(g.BlockIDs) == 0 { + return fmt.Errorf("no block IDs provided") + } + + return nil +} + +type GetExecutionResult struct { + GetByIDRequest +} + +// GetExecutionResultRequest extracts necessary variables from the provided request, +// builds a GetExecutionResult instance, and validates it. +// +// No errors are expected during normal operation. +func GetExecutionResultRequest(r *common.Request) (GetExecutionResult, error) { + var req GetExecutionResult + err := req.Build(r) + return req, err +} diff --git a/engine/access/rest/request/get_script.go b/engine/access/rest/http/request/get_script.go similarity index 70% rename from engine/access/rest/request/get_script.go rename to engine/access/rest/http/request/get_script.go index 3e4abc29be7..de8da72cac1 100644 --- a/engine/access/rest/request/get_script.go +++ b/engine/access/rest/http/request/get_script.go @@ -4,6 +4,7 @@ import ( "fmt" "io" + "github.com/onflow/flow-go/engine/access/rest/common" "github.com/onflow/flow-go/model/flow" ) @@ -15,7 +16,17 @@ type GetScript struct { Script Script } -func (g *GetScript) Build(r *Request) error { +// GetScriptRequest extracts necessary variables from the provided request, +// builds a GetScript instance, and validates it. +// +// No errors are expected during normal operation. +func GetScriptRequest(r *common.Request) (GetScript, error) { + var req GetScript + err := req.Build(r) + return req, err +} + +func (g *GetScript) Build(r *common.Request) error { return g.Parse( r.GetQueryParam(blockHeightQuery), r.GetQueryParam(blockIDQuery), diff --git a/engine/access/rest/request/get_script_test.go b/engine/access/rest/http/request/get_script_test.go similarity index 100% rename from engine/access/rest/request/get_script_test.go rename to engine/access/rest/http/request/get_script_test.go diff --git a/engine/access/rest/request/get_transaction.go b/engine/access/rest/http/request/get_transaction.go similarity index 50% rename from engine/access/rest/request/get_transaction.go rename to engine/access/rest/http/request/get_transaction.go index e2748f2ef14..359570cd71d 100644 --- a/engine/access/rest/request/get_transaction.go +++ b/engine/access/rest/http/request/get_transaction.go @@ -1,6 +1,9 @@ package request -import "github.com/onflow/flow-go/model/flow" +import ( + "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/model/flow" +) const resultExpandable = "result" const blockIDQueryParam = "block_id" @@ -11,7 +14,7 @@ type TransactionOptionals struct { CollectionID flow.Identifier } -func (t *TransactionOptionals) Parse(r *Request) error { +func (t *TransactionOptionals) Parse(r *common.Request) error { var blockId ID err := blockId.Parse(r.GetQueryParam(blockIDQueryParam)) if err != nil { @@ -35,7 +38,17 @@ type GetTransaction struct { ExpandsResult bool } -func (g *GetTransaction) Build(r *Request) error { +// GetTransactionRequest extracts necessary variables from the provided request, +// builds a GetTransaction instance, and validates it. +// +// No errors are expected during normal operation. +func GetTransactionRequest(r *common.Request) (GetTransaction, error) { + var req GetTransaction + err := req.Build(r) + return req, err +} + +func (g *GetTransaction) Build(r *common.Request) error { err := g.TransactionOptionals.Parse(r) if err != nil { return err @@ -52,7 +65,17 @@ type GetTransactionResult struct { TransactionOptionals } -func (g *GetTransactionResult) Build(r *Request) error { +// GetTransactionResultRequest extracts necessary variables from the provided request, +// builds a GetTransactionResult instance, and validates it. +// +// No errors are expected during normal operation. +func GetTransactionResultRequest(r *common.Request) (GetTransactionResult, error) { + var req GetTransactionResult + err := req.Build(r) + return req, err +} + +func (g *GetTransactionResult) Build(r *common.Request) error { err := g.TransactionOptionals.Parse(r) if err != nil { return err diff --git a/engine/access/rest/request/height.go b/engine/access/rest/http/request/height.go similarity index 100% rename from engine/access/rest/request/height.go rename to engine/access/rest/http/request/height.go diff --git a/engine/access/rest/request/height_test.go b/engine/access/rest/http/request/height_test.go similarity index 100% rename from engine/access/rest/request/height_test.go rename to engine/access/rest/http/request/height_test.go diff --git a/engine/access/rest/request/helpers.go b/engine/access/rest/http/request/helpers.go similarity index 93% rename from engine/access/rest/request/helpers.go rename to engine/access/rest/http/request/helpers.go index 33d5246c674..5591cc6df9b 100644 --- a/engine/access/rest/request/helpers.go +++ b/engine/access/rest/http/request/helpers.go @@ -7,6 +7,7 @@ import ( "io" "strings" + "github.com/onflow/flow-go/engine/access/rest/common" "github.com/onflow/flow-go/model/flow" ) @@ -52,7 +53,7 @@ type GetByIDRequest struct { ID flow.Identifier } -func (g *GetByIDRequest) Build(r *Request) error { +func (g *GetByIDRequest) Build(r *common.Request) error { return g.Parse( r.GetVar(idQuery), ) diff --git a/engine/access/rest/request/helpers_test.go b/engine/access/rest/http/request/helpers_test.go similarity index 100% rename from engine/access/rest/request/helpers_test.go rename to engine/access/rest/http/request/helpers_test.go diff --git a/engine/access/rest/request/id.go b/engine/access/rest/http/request/id.go similarity index 100% rename from engine/access/rest/request/id.go rename to engine/access/rest/http/request/id.go diff --git a/engine/access/rest/request/id_test.go b/engine/access/rest/http/request/id_test.go similarity index 100% rename from engine/access/rest/request/id_test.go rename to engine/access/rest/http/request/id_test.go diff --git a/engine/access/rest/request/proposal_key.go b/engine/access/rest/http/request/proposal_key.go similarity index 92% rename from engine/access/rest/request/proposal_key.go rename to engine/access/rest/http/request/proposal_key.go index 5d38fa27e99..1bc792022ac 100644 --- a/engine/access/rest/request/proposal_key.go +++ b/engine/access/rest/http/request/proposal_key.go @@ -3,7 +3,7 @@ package request import ( "fmt" - "github.com/onflow/flow-go/engine/access/rest/models" + "github.com/onflow/flow-go/engine/access/rest/http/models" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/model/flow" ) diff --git a/engine/access/rest/request/script.go b/engine/access/rest/http/request/script.go similarity index 100% rename from engine/access/rest/request/script.go rename to engine/access/rest/http/request/script.go diff --git a/engine/access/rest/request/script_test.go b/engine/access/rest/http/request/script_test.go similarity index 100% rename from engine/access/rest/request/script_test.go rename to engine/access/rest/http/request/script_test.go diff --git a/engine/access/rest/request/signature_test.go b/engine/access/rest/http/request/signature_test.go similarity index 97% rename from engine/access/rest/request/signature_test.go rename to engine/access/rest/http/request/signature_test.go index 1f1bc4e9c9c..a8219f34bbc 100644 --- a/engine/access/rest/request/signature_test.go +++ b/engine/access/rest/http/request/signature_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/onflow/flow-go/engine/access/rest/models" + "github.com/onflow/flow-go/engine/access/rest/http/models" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/model/flow" ) diff --git a/engine/access/rest/request/signatures.go b/engine/access/rest/http/request/signatures.go similarity index 96% rename from engine/access/rest/request/signatures.go rename to engine/access/rest/http/request/signatures.go index 7d4121a6a47..e333be3781b 100644 --- a/engine/access/rest/request/signatures.go +++ b/engine/access/rest/http/request/signatures.go @@ -3,7 +3,7 @@ package request import ( "fmt" - "github.com/onflow/flow-go/engine/access/rest/models" + "github.com/onflow/flow-go/engine/access/rest/http/models" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/model/flow" ) diff --git a/engine/access/rest/request/transaction.go b/engine/access/rest/http/request/transaction.go similarity index 98% rename from engine/access/rest/request/transaction.go rename to engine/access/rest/http/request/transaction.go index 8c15ab98389..614d78f1e07 100644 --- a/engine/access/rest/request/transaction.go +++ b/engine/access/rest/http/request/transaction.go @@ -4,7 +4,7 @@ import ( "fmt" "io" - "github.com/onflow/flow-go/engine/access/rest/models" + "github.com/onflow/flow-go/engine/access/rest/http/models" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/engine/common/rpc/convert" "github.com/onflow/flow-go/model/flow" diff --git a/engine/access/rest/request/transaction_test.go b/engine/access/rest/http/request/transaction_test.go similarity index 100% rename from engine/access/rest/request/transaction_test.go rename to engine/access/rest/http/request/transaction_test.go diff --git a/engine/access/rest/routes/account_balance.go b/engine/access/rest/http/routes/account_balance.go similarity index 64% rename from engine/access/rest/routes/account_balance.go rename to engine/access/rest/http/routes/account_balance.go index 82936beddda..3d0ebf50667 100644 --- a/engine/access/rest/routes/account_balance.go +++ b/engine/access/rest/http/routes/account_balance.go @@ -4,15 +4,16 @@ import ( "fmt" "github.com/onflow/flow-go/access" - "github.com/onflow/flow-go/engine/access/rest/models" - "github.com/onflow/flow-go/engine/access/rest/request" + "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/engine/access/rest/http/models" + "github.com/onflow/flow-go/engine/access/rest/http/request" ) // GetAccountBalance handler retrieves an account balance by address and block height and returns the response -func GetAccountBalance(r *request.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { - req, err := r.GetAccountBalanceRequest() +func GetAccountBalance(r *common.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { + req, err := request.GetAccountBalanceRequest(r) if err != nil { - return nil, models.NewBadRequestError(err) + return nil, common.NewBadRequestError(err) } // In case we receive special height values 'final' and 'sealed', @@ -23,7 +24,7 @@ func GetAccountBalance(r *request.Request, backend access.API, _ models.LinkGene header, _, err := backend.GetLatestBlockHeader(r.Context(), isSealed) if err != nil { err := fmt.Errorf("block with height: %d does not exist", req.Height) - return nil, models.NewNotFoundError(err.Error(), err) + return nil, common.NewNotFoundError(err.Error(), err) } req.Height = header.Height } @@ -31,7 +32,7 @@ func GetAccountBalance(r *request.Request, backend access.API, _ models.LinkGene balance, err := backend.GetAccountBalanceAtBlockHeight(r.Context(), req.Address, req.Height) if err != nil { err = fmt.Errorf("failed to get account balance, reason: %w", err) - return nil, models.NewNotFoundError(err.Error(), err) + return nil, common.NewNotFoundError(err.Error(), err) } var response models.AccountBalance diff --git a/engine/access/rest/routes/account_balance_test.go b/engine/access/rest/http/routes/account_balance_test.go similarity index 88% rename from engine/access/rest/routes/account_balance_test.go rename to engine/access/rest/http/routes/account_balance_test.go index 7b47fc76391..df541547aae 100644 --- a/engine/access/rest/routes/account_balance_test.go +++ b/engine/access/rest/http/routes/account_balance_test.go @@ -1,4 +1,4 @@ -package routes +package routes_test import ( "fmt" @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/onflow/flow-go/access/mock" + "github.com/onflow/flow-go/engine/access/rest/router" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/utils/unittest" ) @@ -30,7 +31,7 @@ func TestGetAccountBalance(t *testing.T) { var height uint64 = 100 block := unittest.BlockHeaderFixture(unittest.WithHeaderHeight(height)) - req := getAccountBalanceRequest(t, account, sealedHeightQueryParam) + req := getAccountBalanceRequest(t, account, router.SealedHeightQueryParam) backend.Mock. On("GetLatestBlockHeader", mocktestify.Anything, true). @@ -42,7 +43,7 @@ func TestGetAccountBalance(t *testing.T) { expected := expectedAccountBalanceResponse(account) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) @@ -51,7 +52,7 @@ func TestGetAccountBalance(t *testing.T) { var height uint64 = 100 block := unittest.BlockHeaderFixture(unittest.WithHeaderHeight(height)) - req := getAccountBalanceRequest(t, account, finalHeightQueryParam) + req := getAccountBalanceRequest(t, account, router.FinalHeightQueryParam) backend.Mock. On("GetLatestBlockHeader", mocktestify.Anything, false). @@ -63,7 +64,7 @@ func TestGetAccountBalance(t *testing.T) { expected := expectedAccountBalanceResponse(account) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) @@ -78,7 +79,7 @@ func TestGetAccountBalance(t *testing.T) { expected := expectedAccountBalanceResponse(account) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) @@ -93,7 +94,7 @@ func TestGetAccountBalance(t *testing.T) { for i, test := range tests { req, _ := http.NewRequest("GET", test.url, nil) - rr := executeRequest(req, backend) + rr := router.ExecuteRequest(req, backend) assert.Equal(t, http.StatusBadRequest, rr.Code) assert.JSONEq(t, test.out, rr.Body.String(), fmt.Sprintf("test #%d failed: %v", i, test)) @@ -127,9 +128,9 @@ func getAccountBalanceRequest(t *testing.T, account *flow.Account, height string func expectedAccountBalanceResponse(account *flow.Account) string { return fmt.Sprintf(` - { - "balance":"%d" - }`, + { + "balance":"%d" + }`, account.Balance, ) } diff --git a/engine/access/rest/routes/account_keys.go b/engine/access/rest/http/routes/account_keys.go similarity index 68% rename from engine/access/rest/routes/account_keys.go rename to engine/access/rest/http/routes/account_keys.go index c77655aba68..fa4e429c20d 100644 --- a/engine/access/rest/routes/account_keys.go +++ b/engine/access/rest/http/routes/account_keys.go @@ -4,15 +4,17 @@ import ( "fmt" "github.com/onflow/flow-go/access" - "github.com/onflow/flow-go/engine/access/rest/models" - "github.com/onflow/flow-go/engine/access/rest/request" + "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/engine/access/rest/http/request" + + "github.com/onflow/flow-go/engine/access/rest/http/models" ) // GetAccountKeyByIndex handler retrieves an account key by address and index and returns the response -func GetAccountKeyByIndex(r *request.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { - req, err := r.GetAccountKeyRequest() +func GetAccountKeyByIndex(r *common.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { + req, err := request.GetAccountKeyRequest(r) if err != nil { - return nil, models.NewBadRequestError(err) + return nil, common.NewBadRequestError(err) } // In case we receive special height values 'final' and 'sealed', @@ -22,7 +24,7 @@ func GetAccountKeyByIndex(r *request.Request, backend access.API, _ models.LinkG header, _, err := backend.GetLatestBlockHeader(r.Context(), isSealed) if err != nil { err := fmt.Errorf("block with height: %d does not exist", req.Height) - return nil, models.NewNotFoundError(err.Error(), err) + return nil, common.NewNotFoundError(err.Error(), err) } req.Height = header.Height } @@ -30,7 +32,7 @@ func GetAccountKeyByIndex(r *request.Request, backend access.API, _ models.LinkG accountKey, err := backend.GetAccountKeyAtBlockHeight(r.Context(), req.Address, req.Index, req.Height) if err != nil { err = fmt.Errorf("failed to get account key with index: %d, reason: %w", req.Index, err) - return nil, models.NewNotFoundError(err.Error(), err) + return nil, common.NewNotFoundError(err.Error(), err) } var response models.AccountPublicKey @@ -39,10 +41,10 @@ func GetAccountKeyByIndex(r *request.Request, backend access.API, _ models.LinkG } // GetAccountKeys handler retrieves an account keys by address and returns the response -func GetAccountKeys(r *request.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { - req, err := r.GetAccountKeysRequest() +func GetAccountKeys(r *common.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { + req, err := request.GetAccountKeysRequest(r) if err != nil { - return nil, models.NewBadRequestError(err) + return nil, common.NewBadRequestError(err) } // In case we receive special height values 'final' and 'sealed', @@ -53,7 +55,7 @@ func GetAccountKeys(r *request.Request, backend access.API, _ models.LinkGenerat header, _, err := backend.GetLatestBlockHeader(r.Context(), isSealed) if err != nil { err := fmt.Errorf("block with height: %d does not exist", req.Height) - return nil, models.NewNotFoundError(err.Error(), err) + return nil, common.NewNotFoundError(err.Error(), err) } req.Height = header.Height } @@ -61,7 +63,7 @@ func GetAccountKeys(r *request.Request, backend access.API, _ models.LinkGenerat accountKeys, err := backend.GetAccountKeysAtBlockHeight(r.Context(), req.Address, req.Height) if err != nil { err = fmt.Errorf("failed to get account keys, reason: %w", err) - return nil, models.NewNotFoundError(err.Error(), err) + return nil, common.NewNotFoundError(err.Error(), err) } var response models.AccountPublicKeys diff --git a/engine/access/rest/routes/account_keys_test.go b/engine/access/rest/http/routes/account_keys_test.go similarity index 85% rename from engine/access/rest/routes/account_keys_test.go rename to engine/access/rest/http/routes/account_keys_test.go index ecffbf4f3ca..6ad11bc89fc 100644 --- a/engine/access/rest/routes/account_keys_test.go +++ b/engine/access/rest/http/routes/account_keys_test.go @@ -1,4 +1,4 @@ -package routes +package routes_test import ( "fmt" @@ -15,6 +15,7 @@ import ( "github.com/onflow/crypto/hash" "github.com/onflow/flow-go/access/mock" + "github.com/onflow/flow-go/engine/access/rest/router" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/utils/unittest" ) @@ -38,7 +39,7 @@ func TestGetAccountKeyByIndex(t *testing.T) { var keyIndex uint32 = 0 keyByIndex := findAccountKeyByIndex(account.Keys, keyIndex) - req := getAccountKeyByIndexRequest(t, account, "0", sealedHeightQueryParam) + req := getAccountKeyByIndexRequest(t, account, "0", router.SealedHeightQueryParam) backend.Mock. On("GetLatestBlockHeader", mocktestify.Anything, true). @@ -50,7 +51,7 @@ func TestGetAccountKeyByIndex(t *testing.T) { expected := expectedAccountKeyResponse(account) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) @@ -61,7 +62,7 @@ func TestGetAccountKeyByIndex(t *testing.T) { var keyIndex uint32 = 0 keyByIndex := findAccountKeyByIndex(account.Keys, keyIndex) - req := getAccountKeyByIndexRequest(t, account, "0", finalHeightQueryParam) + req := getAccountKeyByIndexRequest(t, account, "0", router.FinalHeightQueryParam) backend.Mock. On("GetLatestBlockHeader", mocktestify.Anything, false). @@ -73,7 +74,7 @@ func TestGetAccountKeyByIndex(t *testing.T) { expected := expectedAccountKeyResponse(account) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) @@ -83,7 +84,7 @@ func TestGetAccountKeyByIndex(t *testing.T) { index := "2" block := unittest.BlockHeaderFixture(unittest.WithHeaderHeight(height)) - req := getAccountKeyByIndexRequest(t, account, index, sealedHeightQueryParam) + req := getAccountKeyByIndexRequest(t, account, index, router.SealedHeightQueryParam) backend.Mock. On("GetLatestBlockHeader", mocktestify.Anything, true). @@ -97,13 +98,13 @@ func TestGetAccountKeyByIndex(t *testing.T) { statusCode := 404 expected := fmt.Sprintf(` - { - "code": %d, - "message": "failed to get account key with index: %s, reason: failed to get account key with index: %s" - } + { + "code": %d, + "message": "failed to get account key with index: %s, reason: failed to get account key with index: %s" + } `, statusCode, index, index) - assertResponse(t, req, statusCode, expected, backend) + router.AssertResponse(t, req, statusCode, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) @@ -113,7 +114,7 @@ func TestGetAccountKeyByIndex(t *testing.T) { index := "2" block := unittest.BlockHeaderFixture(unittest.WithHeaderHeight(height)) - req := getAccountKeyByIndexRequest(t, account, index, finalHeightQueryParam) + req := getAccountKeyByIndexRequest(t, account, index, router.FinalHeightQueryParam) backend.Mock. On("GetLatestBlockHeader", mocktestify.Anything, false). @@ -127,13 +128,13 @@ func TestGetAccountKeyByIndex(t *testing.T) { statusCode := 404 expected := fmt.Sprintf(` - { - "code": %d, - "message": "failed to get account key with index: %s, reason: failed to get account key with index: %s" - } + { + "code": %d, + "message": "failed to get account key with index: %s, reason: failed to get account key with index: %s" + } `, statusCode, index, index) - assertResponse(t, req, statusCode, expected, backend) + router.AssertResponse(t, req, statusCode, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) @@ -151,7 +152,7 @@ func TestGetAccountKeyByIndex(t *testing.T) { expected := expectedAccountKeyResponse(account) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) @@ -160,7 +161,7 @@ func TestGetAccountKeyByIndex(t *testing.T) { account := accountFixture(t) const finalHeight uint64 = math.MaxUint64 - 2 - req := getAccountKeyByIndexRequest(t, account, "0", finalHeightQueryParam) + req := getAccountKeyByIndexRequest(t, account, "0", router.FinalHeightQueryParam) err := fmt.Errorf("block with height: %d does not exist", finalHeight) backend.Mock. @@ -175,7 +176,7 @@ func TestGetAccountKeyByIndex(t *testing.T) { } `, statusCode, finalHeight) - assertResponse(t, req, statusCode, expected, backend) + router.AssertResponse(t, req, statusCode, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) @@ -214,7 +215,7 @@ func TestGetAccountKeyByIndex(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { req, _ := http.NewRequest("GET", test.url, nil) - rr := executeRequest(req, backend) + rr := router.ExecuteRequest(req, backend) assert.Equal(t, http.StatusBadRequest, rr.Code) assert.JSONEq(t, test.out, rr.Body.String()) }) @@ -236,7 +237,7 @@ func TestGetAccountKeys(t *testing.T) { var height uint64 = 100 block := unittest.BlockHeaderFixture(unittest.WithHeaderHeight(height)) - req := getAccountKeysRequest(t, account, sealedHeightQueryParam) + req := getAccountKeysRequest(t, account, router.SealedHeightQueryParam) backend.Mock. On("GetLatestBlockHeader", mocktestify.Anything, true). @@ -248,7 +249,7 @@ func TestGetAccountKeys(t *testing.T) { expected := expectedAccountKeysResponse(account) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) @@ -257,7 +258,7 @@ func TestGetAccountKeys(t *testing.T) { var height uint64 = 100 block := unittest.BlockHeaderFixture(unittest.WithHeaderHeight(height)) - req := getAccountKeysRequest(t, account, finalHeightQueryParam) + req := getAccountKeysRequest(t, account, router.FinalHeightQueryParam) backend.Mock. On("GetLatestBlockHeader", mocktestify.Anything, false). @@ -269,7 +270,7 @@ func TestGetAccountKeys(t *testing.T) { expected := expectedAccountKeysResponse(account) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) @@ -284,7 +285,7 @@ func TestGetAccountKeys(t *testing.T) { expected := expectedAccountKeysResponse(account) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) @@ -293,7 +294,7 @@ func TestGetAccountKeys(t *testing.T) { account := accountWithKeysFixture(t) const finalHeight uint64 = math.MaxUint64 - 2 - req := getAccountKeysRequest(t, account, finalHeightQueryParam) + req := getAccountKeysRequest(t, account, router.FinalHeightQueryParam) err := fmt.Errorf("block with height: %d does not exist", finalHeight) backend.Mock. @@ -308,7 +309,7 @@ func TestGetAccountKeys(t *testing.T) { } `, statusCode, finalHeight) - assertResponse(t, req, statusCode, expected, backend) + router.AssertResponse(t, req, statusCode, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) @@ -336,7 +337,7 @@ func TestGetAccountKeys(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { req, _ := http.NewRequest("GET", test.url, nil) - rr := executeRequest(req, backend) + rr := router.ExecuteRequest(req, backend) assert.Equal(t, http.StatusBadRequest, rr.Code) assert.JSONEq(t, test.out, rr.Body.String()) }) @@ -406,23 +407,23 @@ func getAccountKeysRequest( func expectedAccountKeyResponse(account *flow.Account) string { return fmt.Sprintf(` - { - "index":"0", - "public_key":"%s", - "signing_algorithm":"ECDSA_P256", - "hashing_algorithm":"SHA3_256", - "sequence_number":"0", - "weight":"1000", - "revoked":false - }`, + { + "index":"0", + "public_key":"%s", + "signing_algorithm":"ECDSA_P256", + "hashing_algorithm":"SHA3_256", + "sequence_number":"0", + "weight":"1000", + "revoked":false + }`, account.Keys[0].PublicKey.String(), ) } func expectedAccountKeysResponse(account *flow.Account) string { return fmt.Sprintf(` - { - "keys":[ + { + "keys":[ { "index":"0", "public_key":"%s", @@ -442,7 +443,7 @@ func expectedAccountKeysResponse(account *flow.Account) string { "revoked":false } ] - }`, + }`, account.Keys[0].PublicKey.String(), account.Keys[1].PublicKey.String(), ) diff --git a/engine/access/rest/routes/accounts.go b/engine/access/rest/http/routes/accounts.go similarity index 67% rename from engine/access/rest/routes/accounts.go rename to engine/access/rest/http/routes/accounts.go index 972c2ba68ac..a27eaa248c5 100644 --- a/engine/access/rest/routes/accounts.go +++ b/engine/access/rest/http/routes/accounts.go @@ -2,15 +2,16 @@ package routes import ( "github.com/onflow/flow-go/access" - "github.com/onflow/flow-go/engine/access/rest/models" - "github.com/onflow/flow-go/engine/access/rest/request" + "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/engine/access/rest/http/models" + "github.com/onflow/flow-go/engine/access/rest/http/request" ) // GetAccount handler retrieves account by address and returns the response -func GetAccount(r *request.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { - req, err := r.GetAccountRequest() +func GetAccount(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { + req, err := request.GetAccountRequest(r) if err != nil { - return nil, models.NewBadRequestError(err) + return nil, common.NewBadRequestError(err) } // in case we receive special height values 'final' and 'sealed', fetch that height and overwrite request with it diff --git a/engine/access/rest/routes/accounts_test.go b/engine/access/rest/http/routes/accounts_test.go similarity index 83% rename from engine/access/rest/routes/accounts_test.go rename to engine/access/rest/http/routes/accounts_test.go index feb9e77eeae..983f13c3448 100644 --- a/engine/access/rest/routes/accounts_test.go +++ b/engine/access/rest/http/routes/accounts_test.go @@ -1,4 +1,4 @@ -package routes +package routes_test import ( "fmt" @@ -12,7 +12,8 @@ import ( "github.com/stretchr/testify/require" "github.com/onflow/flow-go/access/mock" - "github.com/onflow/flow-go/engine/access/rest/middleware" + "github.com/onflow/flow-go/engine/access/rest/common/middleware" + "github.com/onflow/flow-go/engine/access/rest/router" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/utils/unittest" ) @@ -49,7 +50,7 @@ func TestAccessGetAccount(t *testing.T) { var height uint64 = 100 block := unittest.BlockHeaderFixture(unittest.WithHeaderHeight(height)) - req := getAccountRequest(t, account, sealedHeightQueryParam, expandableFieldKeys, expandableFieldContracts) + req := getAccountRequest(t, account, router.SealedHeightQueryParam, expandableFieldKeys, expandableFieldContracts) backend.Mock. On("GetLatestBlockHeader", mocktestify.Anything, true). @@ -61,7 +62,7 @@ func TestAccessGetAccount(t *testing.T) { expected := expectedExpandedResponse(account) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) @@ -71,7 +72,7 @@ func TestAccessGetAccount(t *testing.T) { block := unittest.BlockHeaderFixture(unittest.WithHeaderHeight(height)) account := accountFixture(t) - req := getAccountRequest(t, account, finalHeightQueryParam, expandableFieldKeys, expandableFieldContracts) + req := getAccountRequest(t, account, router.FinalHeightQueryParam, expandableFieldKeys, expandableFieldContracts) backend.Mock. On("GetLatestBlockHeader", mocktestify.Anything, false). Return(block, flow.BlockStatusFinalized, nil) @@ -81,7 +82,7 @@ func TestAccessGetAccount(t *testing.T) { expected := expectedExpandedResponse(account) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) @@ -96,7 +97,7 @@ func TestAccessGetAccount(t *testing.T) { expected := expectedExpandedResponse(account) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) @@ -111,7 +112,7 @@ func TestAccessGetAccount(t *testing.T) { expected := expectedCondensedResponse(account) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) @@ -126,7 +127,7 @@ func TestAccessGetAccount(t *testing.T) { for i, test := range tests { req, _ := http.NewRequest("GET", test.url, nil) - rr := executeRequest(req, backend) + rr := router.ExecuteRequest(req, backend) assert.Equal(t, http.StatusBadRequest, rr.Code) assert.JSONEq(t, test.out, rr.Body.String(), fmt.Sprintf("test #%d failed: %v", i, test)) @@ -149,9 +150,9 @@ func expectedExpandedResponse(account *flow.Account) string { "revoked":false } ], - "_links":{"_self":"/v1/accounts/%s" }, - "_expandable": {}, - "contracts": {"contract1":"Y29udHJhY3Qx", "contract2":"Y29udHJhY3Qy"} + "_links":{"_self":"/v1/accounts/%s" }, + "_expandable": {}, + "contracts": {"contract1":"Y29udHJhY3Qx", "contract2":"Y29udHJhY3Qy"} }`, account.Address, account.Keys[0].PublicKey.String(), account.Address) } @@ -159,8 +160,8 @@ func expectedCondensedResponse(account *flow.Account) string { return fmt.Sprintf(`{ "address":"%s", "balance":"100", - "_links":{"_self":"/v1/accounts/%s" }, - "_expandable":{"contracts":"contracts", "keys":"keys"} + "_links":{"_self":"/v1/accounts/%s" }, + "_expandable":{"contracts":"contracts", "keys":"keys"} }`, account.Address, account.Address) } diff --git a/engine/access/rest/routes/blocks.go b/engine/access/rest/http/routes/blocks.go similarity index 81% rename from engine/access/rest/routes/blocks.go rename to engine/access/rest/http/routes/blocks.go index c26f14dd8bf..f3995d2a5a5 100644 --- a/engine/access/rest/routes/blocks.go +++ b/engine/access/rest/http/routes/blocks.go @@ -9,16 +9,17 @@ import ( "google.golang.org/grpc/status" "github.com/onflow/flow-go/access" - "github.com/onflow/flow-go/engine/access/rest/models" - "github.com/onflow/flow-go/engine/access/rest/request" + "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/engine/access/rest/http/models" + "github.com/onflow/flow-go/engine/access/rest/http/request" "github.com/onflow/flow-go/model/flow" ) // GetBlocksByIDs gets blocks by provided ID or list of IDs. -func GetBlocksByIDs(r *request.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { - req, err := r.GetBlockByIDsRequest() +func GetBlocksByIDs(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { + req, err := request.GetBlockByIDsRequest(r) if err != nil { - return nil, models.NewBadRequestError(err) + return nil, common.NewBadRequestError(err) } blocks := make([]*models.Block, len(req.IDs)) @@ -35,10 +36,10 @@ func GetBlocksByIDs(r *request.Request, backend access.API, link models.LinkGene } // GetBlocksByHeight gets blocks by height. -func GetBlocksByHeight(r *request.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { - req, err := r.GetBlockRequest() +func GetBlocksByHeight(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { + req, err := request.GetBlockRequest(r) if err != nil { - return nil, models.NewBadRequestError(err) + return nil, common.NewBadRequestError(err) } if req.FinalHeight || req.SealedHeight { @@ -74,7 +75,7 @@ func GetBlocksByHeight(r *request.Request, backend access.API, link models.LinkG req.EndHeight = latest.Header.Height // overwrite special value height with fetched if req.StartHeight > req.EndHeight { - return nil, models.NewBadRequestError(fmt.Errorf("start height must be less than or equal to end height")) + return nil, common.NewBadRequestError(fmt.Errorf("start height must be less than or equal to end height")) } } @@ -92,10 +93,10 @@ func GetBlocksByHeight(r *request.Request, backend access.API, link models.LinkG } // GetBlockPayloadByID gets block payload by ID -func GetBlockPayloadByID(r *request.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { - req, err := r.GetBlockPayloadRequest() +func GetBlockPayloadByID(r *common.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { + req, err := request.GetBlockPayloadRequest(r) if err != nil { - return nil, models.NewBadRequestError(err) + return nil, common.NewBadRequestError(err) } blkProvider := NewBlockProvider(backend, forID(&req.ID)) @@ -113,7 +114,7 @@ func GetBlockPayloadByID(r *request.Request, backend access.API, _ models.LinkGe return payload, nil } -func getBlock(option blockProviderOption, req *request.Request, backend access.API, link models.LinkGenerator) (*models.Block, error) { +func getBlock(option blockProviderOption, req *common.Request, backend access.API, link models.LinkGenerator) (*models.Block, error) { // lookup block blkProvider := NewBlockProvider(backend, option) blk, blockStatus, err := blkProvider.getBlock(req.Context()) @@ -196,7 +197,7 @@ func (blkProvider *blockProvider) getBlock(ctx context.Context) (*flow.Block, fl if blkProvider.id != nil { blk, _, err := blkProvider.backend.GetBlockByID(ctx, *blkProvider.id) if err != nil { // unfortunately backend returns internal error status if not found - return nil, flow.BlockStatusUnknown, models.NewNotFoundError( + return nil, flow.BlockStatusUnknown, common.NewNotFoundError( fmt.Sprintf("error looking up block with ID %s", blkProvider.id.String()), err, ) } @@ -207,14 +208,14 @@ func (blkProvider *blockProvider) getBlock(ctx context.Context) (*flow.Block, fl blk, status, err := blkProvider.backend.GetLatestBlock(ctx, blkProvider.sealed) if err != nil { // cannot be a 'not found' error since final and sealed block should always be found - return nil, flow.BlockStatusUnknown, models.NewRestError(http.StatusInternalServerError, "block lookup failed", err) + return nil, flow.BlockStatusUnknown, common.NewRestError(http.StatusInternalServerError, "block lookup failed", err) } return blk, status, nil } blk, status, err := blkProvider.backend.GetBlockByHeight(ctx, blkProvider.height) if err != nil { // unfortunately backend returns internal error status if not found - return nil, flow.BlockStatusUnknown, models.NewNotFoundError( + return nil, flow.BlockStatusUnknown, common.NewNotFoundError( fmt.Sprintf("error looking up block at height %d", blkProvider.height), err, ) } diff --git a/engine/access/rest/routes/blocks_test.go b/engine/access/rest/http/routes/blocks_test.go similarity index 96% rename from engine/access/rest/routes/blocks_test.go rename to engine/access/rest/http/routes/blocks_test.go index 94962e87bb6..44ff77584e6 100644 --- a/engine/access/rest/routes/blocks_test.go +++ b/engine/access/rest/http/routes/blocks_test.go @@ -1,4 +1,4 @@ -package routes +package routes_test import ( "fmt" @@ -8,16 +8,16 @@ import ( "testing" "time" - "github.com/onflow/flow-go/engine/access/rest/request" - "github.com/onflow/flow-go/engine/access/rest/util" - mocks "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "github.com/onflow/flow-go/access/mock" - "github.com/onflow/flow-go/engine/access/rest/middleware" + "github.com/onflow/flow-go/engine/access/rest/common/middleware" + "github.com/onflow/flow-go/engine/access/rest/http/request" + "github.com/onflow/flow-go/engine/access/rest/router" + "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/utils/unittest" ) @@ -169,7 +169,7 @@ func TestAccessGetBlocks(t *testing.T) { testVectors := prepareTestVectors(t, blockIDs, heights, blocks, executionResults, blkCnt) for _, tv := range testVectors { - rr := executeRequest(tv.request, backend) + rr := router.ExecuteRequest(tv.request, backend) require.Equal(t, tv.expectedStatus, rr.Code, "failed test %s: incorrect response code", tv.description) actualResp := rr.Body.String() require.JSONEq(t, tv.expectedResponse, actualResp, "Failed: %s: incorrect response body", tv.description) @@ -185,13 +185,13 @@ func requestURL(t *testing.T, ids []string, start string, end string, expandResp } if start != "" { - q.Add(startHeightQueryParam, start) - q.Add(endHeightQueryParam, end) + q.Add(router.StartHeightQueryParam, start) + q.Add(router.EndHeightQueryParam, end) } if len(heights) > 0 { heightsStr := strings.Join(heights, ",") - q.Add(heightQueryParam, heightsStr) + q.Add(router.HeightQueryParam, heightsStr) } if len(selectedFields) > 0 { @@ -201,8 +201,8 @@ func requestURL(t *testing.T, ids []string, start string, end string, expandResp if expandResponse { var expands []string - expands = append(expands, ExpandableFieldPayload) - expands = append(expands, ExpandableExecutionResult) + expands = append(expands, router.ExpandableFieldPayload) + expands = append(expands, router.ExpandableExecutionResult) expandsStr := strings.Join(expands, ",") q.Add(middleware.ExpandQueryParam, expandsStr) } diff --git a/engine/access/rest/routes/collections.go b/engine/access/rest/http/routes/collections.go similarity index 68% rename from engine/access/rest/routes/collections.go rename to engine/access/rest/http/routes/collections.go index 47b6150f480..84157cd68ae 100644 --- a/engine/access/rest/routes/collections.go +++ b/engine/access/rest/http/routes/collections.go @@ -2,16 +2,17 @@ package routes import ( "github.com/onflow/flow-go/access" - "github.com/onflow/flow-go/engine/access/rest/models" - "github.com/onflow/flow-go/engine/access/rest/request" + "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/engine/access/rest/http/models" + "github.com/onflow/flow-go/engine/access/rest/http/request" "github.com/onflow/flow-go/model/flow" ) // GetCollectionByID retrieves a collection by ID and builds a response -func GetCollectionByID(r *request.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { - req, err := r.GetCollectionRequest() +func GetCollectionByID(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { + req, err := request.GetCollectionRequest(r) if err != nil { - return nil, models.NewBadRequestError(err) + return nil, common.NewBadRequestError(err) } collection, err := backend.GetCollectionByID(r.Context(), req.ID) diff --git a/engine/access/rest/routes/collections_test.go b/engine/access/rest/http/routes/collections_test.go similarity index 91% rename from engine/access/rest/routes/collections_test.go rename to engine/access/rest/http/routes/collections_test.go index d0c5684f4ed..ad083eba1d6 100644 --- a/engine/access/rest/routes/collections_test.go +++ b/engine/access/rest/http/routes/collections_test.go @@ -1,4 +1,4 @@ -package routes +package routes_test import ( "encoding/json" @@ -7,15 +7,14 @@ import ( "strings" "testing" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - - "github.com/onflow/flow-go/model/flow" - "github.com/stretchr/testify/assert" mocks "github.com/stretchr/testify/mock" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" "github.com/onflow/flow-go/access/mock" + "github.com/onflow/flow-go/engine/access/rest/router" + "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/utils/unittest" ) @@ -52,17 +51,17 @@ func TestGetCollections(t *testing.T) { transactionsStr := fmt.Sprintf("[%s]", strings.Join(txs, ",")) expected := fmt.Sprintf(`{ - "id":"%s", + "id":"%s", "_links": { "_self": "/v1/collections/%s" }, - "_expandable": { - "transactions": %s - } + "_expandable": { + "transactions": %s + } }`, col.ID(), col.ID(), transactionsStr) req := getCollectionReq(col.ID().String(), false) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocks.AssertExpectationsForObjects(t, backend) } }) @@ -87,7 +86,7 @@ func TestGetCollections(t *testing.T) { Once() req := getCollectionReq(col.ID().String(), true) - rr := executeRequest(req, backend) + rr := router.ExecuteRequest(req, backend) assert.Equal(t, http.StatusOK, rr.Code) // really hacky but we can't build whole response since it's really complex @@ -145,7 +144,7 @@ func TestGetCollections(t *testing.T) { Return(test.mockValue, test.mockErr) } req := getCollectionReq(test.id, false) - assertResponse(t, req, test.status, test.response, backend) + router.AssertResponse(t, req, test.status, test.response, backend) } }) } diff --git a/engine/access/rest/routes/events.go b/engine/access/rest/http/routes/events.go similarity index 78% rename from engine/access/rest/routes/events.go rename to engine/access/rest/http/routes/events.go index 59e04439bf8..038a4a98aeb 100644 --- a/engine/access/rest/routes/events.go +++ b/engine/access/rest/http/routes/events.go @@ -6,18 +6,20 @@ import ( entitiesproto "github.com/onflow/flow/protobuf/go/flow/entities" "github.com/onflow/flow-go/access" - "github.com/onflow/flow-go/engine/access/rest/models" - "github.com/onflow/flow-go/engine/access/rest/request" + "github.com/onflow/flow-go/engine/access/rest/common" + + "github.com/onflow/flow-go/engine/access/rest/http/models" + "github.com/onflow/flow-go/engine/access/rest/http/request" ) const BlockQueryParam = "block_ids" const EventTypeQuery = "type" // GetEvents for the provided block range or list of block IDs filtered by type. -func GetEvents(r *request.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { - req, err := r.GetEventsRequest() +func GetEvents(r *common.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { + req, err := request.GetEventsRequest(r) if err != nil { - return nil, models.NewBadRequestError(err) + return nil, common.NewBadRequestError(err) } // if the request has block IDs provided then return events for block IDs @@ -47,7 +49,7 @@ func GetEvents(r *request.Request, backend access.API, _ models.LinkGenerator) ( req.EndHeight = latest.Height // special check after we resolve special height value if req.StartHeight > req.EndHeight { - return nil, models.NewBadRequestError(fmt.Errorf("current retrieved end height value is lower than start height")) + return nil, common.NewBadRequestError(fmt.Errorf("current retrieved end height value is lower than start height")) } } diff --git a/engine/access/rest/routes/events_test.go b/engine/access/rest/http/routes/events_test.go similarity index 95% rename from engine/access/rest/routes/events_test.go rename to engine/access/rest/http/routes/events_test.go index 93b58afda6d..dcaa1e01268 100644 --- a/engine/access/rest/routes/events_test.go +++ b/engine/access/rest/http/routes/events_test.go @@ -1,4 +1,4 @@ -package routes +package routes_test import ( "encoding/json" @@ -11,16 +11,17 @@ import ( mocks "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "github.com/onflow/flow/protobuf/go/flow/entities" - "github.com/onflow/flow-go/access/mock" + "github.com/onflow/flow-go/engine/access/rest/http/routes" + "github.com/onflow/flow-go/engine/access/rest/router" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/utils/unittest" + + "github.com/onflow/flow/protobuf/go/flow/entities" ) func TestGetEvents(t *testing.T) { @@ -127,7 +128,7 @@ func TestGetEvents(t *testing.T) { for _, test := range testVectors { t.Run(test.description, func(t *testing.T) { - assertResponse(t, test.request, test.expectedStatus, test.expectedResponse, backend) + router.AssertResponse(t, test.request, test.expectedStatus, test.expectedResponse, backend) }) } @@ -138,15 +139,15 @@ func getEventReq(t *testing.T, eventType string, start string, end string, block q := u.Query() if len(blockIDs) > 0 { - q.Add(BlockQueryParam, strings.Join(blockIDs, ",")) + q.Add(routes.BlockQueryParam, strings.Join(blockIDs, ",")) } if start != "" && end != "" { - q.Add(startHeightQueryParam, start) - q.Add(endHeightQueryParam, end) + q.Add(router.StartHeightQueryParam, start) + q.Add(router.EndHeightQueryParam, end) } - q.Add(EventTypeQuery, eventType) + q.Add(routes.EventTypeQuery, eventType) u.RawQuery = q.Encode() diff --git a/engine/access/rest/routes/execution_result.go b/engine/access/rest/http/routes/execution_result.go similarity index 59% rename from engine/access/rest/routes/execution_result.go rename to engine/access/rest/http/routes/execution_result.go index b999665b26b..b1c32ac4912 100644 --- a/engine/access/rest/routes/execution_result.go +++ b/engine/access/rest/http/routes/execution_result.go @@ -4,15 +4,17 @@ import ( "fmt" "github.com/onflow/flow-go/access" - "github.com/onflow/flow-go/engine/access/rest/models" - "github.com/onflow/flow-go/engine/access/rest/request" + "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/engine/access/rest/http/request" + + "github.com/onflow/flow-go/engine/access/rest/http/models" ) // GetExecutionResultsByBlockIDs gets Execution Result payload by block IDs. -func GetExecutionResultsByBlockIDs(r *request.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { - req, err := r.GetExecutionResultByBlockIDsRequest() +func GetExecutionResultsByBlockIDs(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { + req, err := request.GetExecutionResultByBlockIDsRequest(r) if err != nil { - return nil, models.NewBadRequestError(err) + return nil, common.NewBadRequestError(err) } // for each block ID we retrieve execution result @@ -35,10 +37,10 @@ func GetExecutionResultsByBlockIDs(r *request.Request, backend access.API, link } // GetExecutionResultByID gets execution result by the ID. -func GetExecutionResultByID(r *request.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { - req, err := r.GetExecutionResultRequest() +func GetExecutionResultByID(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { + req, err := request.GetExecutionResultRequest(r) if err != nil { - return nil, models.NewBadRequestError(err) + return nil, common.NewBadRequestError(err) } res, err := backend.GetExecutionResultByID(r.Context(), req.ID) @@ -48,7 +50,7 @@ func GetExecutionResultByID(r *request.Request, backend access.API, link models. if res == nil { err := fmt.Errorf("execution result with ID: %s not found", req.ID.String()) - return nil, models.NewNotFoundError(err.Error(), err) + return nil, common.NewNotFoundError(err.Error(), err) } var response models.ExecutionResult diff --git a/engine/access/rest/routes/execution_result_test.go b/engine/access/rest/http/routes/execution_result_test.go similarity index 87% rename from engine/access/rest/routes/execution_result_test.go rename to engine/access/rest/http/routes/execution_result_test.go index ba74974af1a..f38d5a6c78f 100644 --- a/engine/access/rest/routes/execution_result_test.go +++ b/engine/access/rest/http/routes/execution_result_test.go @@ -1,4 +1,4 @@ -package routes +package routes_test import ( "fmt" @@ -7,12 +7,12 @@ import ( "strings" "testing" + mocks "github.com/stretchr/testify/mock" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - mocks "github.com/stretchr/testify/mock" - "github.com/onflow/flow-go/access/mock" + "github.com/onflow/flow-go/engine/access/rest/router" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/utils/unittest" @@ -48,7 +48,7 @@ func TestGetResultByID(t *testing.T) { req := getResultByIDReq(id.String(), nil) expected := executionResultExpectedStr(result) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocks.AssertExpectationsForObjects(t, backend) }) @@ -61,7 +61,7 @@ func TestGetResultByID(t *testing.T) { Once() req := getResultByIDReq(id.String(), nil) - assertResponse(t, req, http.StatusNotFound, `{"code":404,"message":"Flow resource not found: block not found"}`, backend) + router.AssertResponse(t, req, http.StatusNotFound, `{"code":404,"message":"Flow resource not found: block not found"}`, backend) mocks.AssertExpectationsForObjects(t, backend) }) } @@ -81,7 +81,7 @@ func TestGetResultBlockID(t *testing.T) { req := getResultByIDReq("", []string{blockID.String()}) expected := fmt.Sprintf(`[%s]`, executionResultExpectedStr(result)) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocks.AssertExpectationsForObjects(t, backend) }) @@ -94,7 +94,7 @@ func TestGetResultBlockID(t *testing.T) { Once() req := getResultByIDReq("", []string{blockID.String()}) - assertResponse(t, req, http.StatusNotFound, `{"code":404,"message":"Flow resource not found: block not found"}`, backend) + router.AssertResponse(t, req, http.StatusNotFound, `{"code":404,"message":"Flow resource not found: block not found"}`, backend) mocks.AssertExpectationsForObjects(t, backend) }) } @@ -119,8 +119,8 @@ func executionResultExpectedStr(result *flow.ExecutionResult) string { "id": "%s", "block_id": "%s", "events": [], - "chunks": %s, - "previous_result_id": "%s", + "chunks": %s, + "previous_result_id": "%s", "_links": { "_self": "/v1/execution_results/%s" } diff --git a/engine/access/rest/routes/network.go b/engine/access/rest/http/routes/network.go similarity index 55% rename from engine/access/rest/routes/network.go rename to engine/access/rest/http/routes/network.go index 82abcbb6d49..c363a38a7a6 100644 --- a/engine/access/rest/routes/network.go +++ b/engine/access/rest/http/routes/network.go @@ -2,12 +2,12 @@ package routes import ( "github.com/onflow/flow-go/access" - "github.com/onflow/flow-go/engine/access/rest/models" - "github.com/onflow/flow-go/engine/access/rest/request" + "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/engine/access/rest/http/models" ) // GetNetworkParameters returns network-wide parameters of the blockchain -func GetNetworkParameters(r *request.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { +func GetNetworkParameters(r *common.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { params := backend.GetNetworkParameters(r.Context()) var response models.NetworkParameters diff --git a/engine/access/rest/routes/network_test.go b/engine/access/rest/http/routes/network_test.go similarity index 89% rename from engine/access/rest/routes/network_test.go rename to engine/access/rest/http/routes/network_test.go index 00d0ca03944..effc6891356 100644 --- a/engine/access/rest/routes/network_test.go +++ b/engine/access/rest/http/routes/network_test.go @@ -1,4 +1,4 @@ -package routes +package routes_test import ( "fmt" @@ -11,6 +11,7 @@ import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/access/mock" + "github.com/onflow/flow-go/engine/access/rest/router" "github.com/onflow/flow-go/model/flow" ) @@ -38,7 +39,7 @@ func TestGetNetworkParameters(t *testing.T) { expected := networkParametersExpectedStr(flow.Mainnet) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) } diff --git a/engine/access/rest/routes/node_version_info.go b/engine/access/rest/http/routes/node_version_info.go similarity index 57% rename from engine/access/rest/routes/node_version_info.go rename to engine/access/rest/http/routes/node_version_info.go index 31e172bba9f..71b4aa08b43 100644 --- a/engine/access/rest/routes/node_version_info.go +++ b/engine/access/rest/http/routes/node_version_info.go @@ -2,12 +2,12 @@ package routes import ( "github.com/onflow/flow-go/access" - "github.com/onflow/flow-go/engine/access/rest/models" - "github.com/onflow/flow-go/engine/access/rest/request" + "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/engine/access/rest/http/models" ) // GetNodeVersionInfo returns node version information -func GetNodeVersionInfo(r *request.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { +func GetNodeVersionInfo(r *common.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { params, err := backend.GetNodeVersionInfo(r.Context()) if err != nil { return nil, err diff --git a/engine/access/rest/routes/node_version_info_test.go b/engine/access/rest/http/routes/node_version_info_test.go similarity index 88% rename from engine/access/rest/routes/node_version_info_test.go rename to engine/access/rest/http/routes/node_version_info_test.go index f08ada0289a..efbbc9f0c20 100644 --- a/engine/access/rest/routes/node_version_info_test.go +++ b/engine/access/rest/http/routes/node_version_info_test.go @@ -1,4 +1,4 @@ -package routes +package routes_test import ( "fmt" @@ -12,6 +12,7 @@ import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/access/mock" "github.com/onflow/flow-go/cmd/build" + "github.com/onflow/flow-go/engine/access/rest/router" "github.com/onflow/flow-go/utils/unittest" ) @@ -49,7 +50,7 @@ func TestGetNodeVersionInfo(t *testing.T) { expected := nodeVersionInfoExpectedStr(params) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) mocktestify.AssertExpectationsForObjects(t, backend) }) } @@ -67,10 +68,10 @@ func nodeVersionInfoExpectedStr(nodeVersionInfo *access.NodeVersionInfo) string "semver": "%s", "commit": "%s", "spork_id": "%s", - "protocol_version": "%d", - "spork_root_block_height": "%d", - "node_root_block_height": "%d", - %s + "protocol_version": "%d", + "spork_root_block_height": "%d", + "node_root_block_height": "%d", + %s }`, nodeVersionInfo.Semver, nodeVersionInfo.Commit, diff --git a/engine/access/rest/routes/scripts.go b/engine/access/rest/http/routes/scripts.go similarity index 70% rename from engine/access/rest/routes/scripts.go rename to engine/access/rest/http/routes/scripts.go index 8627470ab88..2c747ff8850 100644 --- a/engine/access/rest/routes/scripts.go +++ b/engine/access/rest/http/routes/scripts.go @@ -2,16 +2,17 @@ package routes import ( "github.com/onflow/flow-go/access" - "github.com/onflow/flow-go/engine/access/rest/models" - "github.com/onflow/flow-go/engine/access/rest/request" + "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/engine/access/rest/http/models" + "github.com/onflow/flow-go/engine/access/rest/http/request" "github.com/onflow/flow-go/model/flow" ) // ExecuteScript handler sends the script from the request to be executed. -func ExecuteScript(r *request.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { - req, err := r.GetScriptRequest() +func ExecuteScript(r *common.Request, backend access.API, _ models.LinkGenerator) (interface{}, error) { + req, err := request.GetScriptRequest(r) if err != nil { - return nil, models.NewBadRequestError(err) + return nil, common.NewBadRequestError(err) } if req.BlockID != flow.ZeroID { diff --git a/engine/access/rest/routes/scripts_test.go b/engine/access/rest/http/routes/scripts_test.go similarity index 90% rename from engine/access/rest/routes/scripts_test.go rename to engine/access/rest/http/routes/scripts_test.go index 8998e5c4147..8e08c5d21a6 100644 --- a/engine/access/rest/routes/scripts_test.go +++ b/engine/access/rest/http/routes/scripts_test.go @@ -1,4 +1,4 @@ -package routes +package routes_test import ( "bytes" @@ -14,6 +14,7 @@ import ( "google.golang.org/grpc/status" "github.com/onflow/flow-go/access/mock" + "github.com/onflow/flow-go/engine/access/rest/router" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/model/flow" ) @@ -51,8 +52,8 @@ func TestScripts(t *testing.T) { On("ExecuteScriptAtLatestBlock", mocks.Anything, validCode, [][]byte{validArgs}). Return([]byte("hello world"), nil) - req := scriptReq("", sealedHeightQueryParam, validBody) - assertOKResponse(t, req, fmt.Sprintf( + req := scriptReq("", router.SealedHeightQueryParam, validBody) + router.AssertOKResponse(t, req, fmt.Sprintf( "\"%s\"", base64.StdEncoding.EncodeToString([]byte(`hello world`)), ), backend) @@ -67,7 +68,7 @@ func TestScripts(t *testing.T) { Return([]byte("hello world"), nil) req := scriptReq("", fmt.Sprintf("%d", height), validBody) - assertOKResponse(t, req, fmt.Sprintf( + router.AssertOKResponse(t, req, fmt.Sprintf( "\"%s\"", base64.StdEncoding.EncodeToString([]byte(`hello world`)), ), backend) @@ -82,7 +83,7 @@ func TestScripts(t *testing.T) { Return([]byte("hello world"), nil) req := scriptReq(id.String(), "", validBody) - assertOKResponse(t, req, fmt.Sprintf( + router.AssertOKResponse(t, req, fmt.Sprintf( "\"%s\"", base64.StdEncoding.EncodeToString([]byte(`hello world`)), ), backend) @@ -95,7 +96,7 @@ func TestScripts(t *testing.T) { Return(nil, status.Error(codes.Internal, "internal server error")) req := scriptReq("", "1337", validBody) - assertResponse( + router.AssertResponse( t, req, http.StatusBadRequest, @@ -125,7 +126,7 @@ func TestScripts(t *testing.T) { for _, test := range tests { req := scriptReq(test.id, test.height, test.body) - assertResponse(t, req, http.StatusBadRequest, test.out, backend) + router.AssertResponse(t, req, http.StatusBadRequest, test.out, backend) } }) } diff --git a/engine/access/rest/routes/transactions.go b/engine/access/rest/http/routes/transactions.go similarity index 65% rename from engine/access/rest/routes/transactions.go rename to engine/access/rest/http/routes/transactions.go index e85eb116894..02afef949e8 100644 --- a/engine/access/rest/routes/transactions.go +++ b/engine/access/rest/http/routes/transactions.go @@ -4,15 +4,17 @@ import ( entitiesproto "github.com/onflow/flow/protobuf/go/flow/entities" "github.com/onflow/flow-go/access" - "github.com/onflow/flow-go/engine/access/rest/models" - "github.com/onflow/flow-go/engine/access/rest/request" + "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/engine/access/rest/http/request" + + "github.com/onflow/flow-go/engine/access/rest/http/models" ) // GetTransactionByID gets a transaction by requested ID. -func GetTransactionByID(r *request.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { - req, err := r.GetTransactionRequest() +func GetTransactionByID(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { + req, err := request.GetTransactionRequest(r) if err != nil { - return nil, models.NewBadRequestError(err) + return nil, common.NewBadRequestError(err) } tx, err := backend.GetTransaction(r.Context(), req.ID) @@ -41,10 +43,10 @@ func GetTransactionByID(r *request.Request, backend access.API, link models.Link } // GetTransactionResultByID retrieves transaction result by the transaction ID. -func GetTransactionResultByID(r *request.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { - req, err := r.GetTransactionResultRequest() +func GetTransactionResultByID(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { + req, err := request.GetTransactionResultRequest(r) if err != nil { - return nil, models.NewBadRequestError(err) + return nil, common.NewBadRequestError(err) } txr, err := backend.GetTransactionResult( @@ -64,10 +66,10 @@ func GetTransactionResultByID(r *request.Request, backend access.API, link model } // CreateTransaction creates a new transaction from provided payload. -func CreateTransaction(r *request.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { - req, err := r.CreateTransactionRequest() +func CreateTransaction(r *common.Request, backend access.API, link models.LinkGenerator) (interface{}, error) { + req, err := request.CreateTransactionRequest(r) if err != nil { - return nil, models.NewBadRequestError(err) + return nil, common.NewBadRequestError(err) } err = backend.SendTransaction(r.Context(), &req.Transaction) diff --git a/engine/access/rest/routes/transactions_test.go b/engine/access/rest/http/routes/transactions_test.go similarity index 92% rename from engine/access/rest/routes/transactions_test.go rename to engine/access/rest/http/routes/transactions_test.go index d97ca3dd890..e2deadd16e1 100644 --- a/engine/access/rest/routes/transactions_test.go +++ b/engine/access/rest/http/routes/transactions_test.go @@ -1,4 +1,4 @@ -package routes +package routes_test import ( "bytes" @@ -19,7 +19,8 @@ import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/access/mock" - "github.com/onflow/flow-go/engine/access/rest/models" + "github.com/onflow/flow-go/engine/access/rest/http/models" + "github.com/onflow/flow-go/engine/access/rest/router" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/onflow/flow-go/model/flow" "github.com/onflow/flow-go/utils/unittest" @@ -85,7 +86,7 @@ func TestGetTransactions(t *testing.T) { { "id":"%s", "script":"YWNjZXNzKGFsbCkgZnVuIG1haW4oKSB7fQ==", - "arguments": [], + "arguments": [], "reference_block_id":"%s", "gas_limit":"10", "payer":"8c5303eaa26202d6", @@ -97,7 +98,7 @@ func TestGetTransactions(t *testing.T) { "authorizers":[ "8c5303eaa26202d6" ], - "payload_signatures": [], + "payload_signatures": [], "envelope_signatures":[ { "address":"8c5303eaa26202d6", @@ -114,7 +115,7 @@ func TestGetTransactions(t *testing.T) { }`, tx.ID(), tx.ReferenceBlockID, util.ToBase64(tx.EnvelopeSignatures[0].Signature), tx.ID(), tx.ID()) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) }) t.Run("Get by ID with results", func(t *testing.T) { @@ -137,7 +138,7 @@ func TestGetTransactions(t *testing.T) { { "id":"%s", "script":"YWNjZXNzKGFsbCkgZnVuIG1haW4oKSB7fQ==", - "arguments": [], + "arguments": [], "reference_block_id":"%s", "gas_limit":"10", "payer":"8c5303eaa26202d6", @@ -149,7 +150,7 @@ func TestGetTransactions(t *testing.T) { "authorizers":[ "8c5303eaa26202d6" ], - "payload_signatures": [], + "payload_signatures": [], "envelope_signatures":[ { "address":"8c5303eaa26202d6", @@ -178,13 +179,13 @@ func TestGetTransactions(t *testing.T) { "_self": "/v1/transaction_results/%s" } }, - "_expandable": {}, + "_expandable": {}, "_links":{ "_self":"/v1/transactions/%s" } }`, tx.ID(), tx.ReferenceBlockID, util.ToBase64(tx.EnvelopeSignatures[0].Signature), tx.ReferenceBlockID, txr.CollectionID, tx.ID(), tx.ID(), tx.ID()) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) }) t.Run("get by ID Invalid", func(t *testing.T) { @@ -192,7 +193,7 @@ func TestGetTransactions(t *testing.T) { req := getTransactionReq("invalid", false, "", "") expected := `{"code":400, "message":"invalid ID format"}` - assertResponse(t, req, http.StatusBadRequest, expected, backend) + router.AssertResponse(t, req, http.StatusBadRequest, expected, backend) }) t.Run("get by ID non-existing", func(t *testing.T) { @@ -206,7 +207,7 @@ func TestGetTransactions(t *testing.T) { Return(nil, status.Error(codes.NotFound, "transaction not found")) expected := `{"code":404, "message":"Flow resource not found: transaction not found"}` - assertResponse(t, req, http.StatusNotFound, expected, backend) + router.AssertResponse(t, req, http.StatusNotFound, expected, backend) }) } @@ -255,7 +256,7 @@ func TestGetTransactionResult(t *testing.T) { On("GetTransactionResult", mocks.Anything, id, flow.ZeroID, flow.ZeroID, entities.EventEncodingVersion_JSON_CDC_V0). Return(txr, nil) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) }) t.Run("get by block ID", func(t *testing.T) { @@ -267,7 +268,7 @@ func TestGetTransactionResult(t *testing.T) { On("GetTransactionResult", mocks.Anything, id, bid, flow.ZeroID, entities.EventEncodingVersion_JSON_CDC_V0). Return(txr, nil) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) }) t.Run("get by collection ID", func(t *testing.T) { @@ -278,7 +279,7 @@ func TestGetTransactionResult(t *testing.T) { On("GetTransactionResult", mocks.Anything, id, flow.ZeroID, cid, entities.EventEncodingVersion_JSON_CDC_V0). Return(txr, nil) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) }) t.Run("get execution statuses", func(t *testing.T) { @@ -326,7 +327,7 @@ func TestGetTransactionResult(t *testing.T) { "_self": "/v1/transaction_results/%s" } }`, bid.String(), cid.String(), err, cases.Title(language.English).String(strings.ToLower(txResult.Status.String())), txResult.ErrorMessage, id.String()) - assertOKResponse(t, req, expectedResp, backend) + router.AssertOKResponse(t, req, expectedResp, backend) } }) @@ -336,7 +337,7 @@ func TestGetTransactionResult(t *testing.T) { req := getTransactionResultReq("invalid", "", "") expected := `{"code":400, "message":"invalid ID format"}` - assertResponse(t, req, http.StatusBadRequest, expected, backend) + router.AssertResponse(t, req, http.StatusBadRequest, expected, backend) }) } @@ -369,7 +370,7 @@ func TestCreateTransaction(t *testing.T) { "authorizers":[ "8c5303eaa26202d6" ], - "payload_signatures":[ + "payload_signatures":[ { "address":"8c5303eaa26202d6", "key_index":"1", @@ -391,7 +392,7 @@ func TestCreateTransaction(t *testing.T) { } }`, tx.ID(), tx.ReferenceBlockID, util.ToBase64(tx.PayloadSignatures[0].Signature), util.ToBase64(tx.EnvelopeSignatures[0].Signature), tx.ID(), tx.ID()) - assertOKResponse(t, req, expected, backend) + router.AssertOKResponse(t, req, expected, backend) }) t.Run("post invalid transaction", func(t *testing.T) { @@ -419,7 +420,7 @@ func TestCreateTransaction(t *testing.T) { testTx[test.inputField] = test.inputValue req := createTransactionReq(testTx) - assertResponse(t, req, http.StatusBadRequest, test.output, backend) + router.AssertResponse(t, req, http.StatusBadRequest, test.output, backend) } }) } diff --git a/engine/access/rest/request/get_collection.go b/engine/access/rest/request/get_collection.go deleted file mode 100644 index 151f7ddc6d5..00000000000 --- a/engine/access/rest/request/get_collection.go +++ /dev/null @@ -1,15 +0,0 @@ -package request - -const ExpandsTransactions = "transactions" - -type GetCollection struct { - GetByIDRequest - ExpandsTransactions bool -} - -func (g *GetCollection) Build(r *Request) error { - err := g.GetByIDRequest.Build(r) - g.ExpandsTransactions = r.Expands(ExpandsTransactions) - - return err -} diff --git a/engine/access/rest/request/get_execution_result.go b/engine/access/rest/request/get_execution_result.go deleted file mode 100644 index 4feda42a0b6..00000000000 --- a/engine/access/rest/request/get_execution_result.go +++ /dev/null @@ -1,38 +0,0 @@ -package request - -import ( - "fmt" - - "github.com/onflow/flow-go/model/flow" -) - -const idQuery = "id" - -type GetExecutionResultByBlockIDs struct { - BlockIDs []flow.Identifier -} - -func (g *GetExecutionResultByBlockIDs) Build(r *Request) error { - return g.Parse( - r.GetQueryParams(blockIDQuery), - ) -} - -func (g *GetExecutionResultByBlockIDs) Parse(rawIDs []string) error { - var ids IDs - err := ids.Parse(rawIDs) - if err != nil { - return err - } - g.BlockIDs = ids.Flow() - - if len(g.BlockIDs) == 0 { - return fmt.Errorf("no block IDs provided") - } - - return nil -} - -type GetExecutionResult struct { - GetByIDRequest -} diff --git a/engine/access/rest/router/http_routes.go b/engine/access/rest/router/http_routes.go new file mode 100644 index 00000000000..5032f591142 --- /dev/null +++ b/engine/access/rest/router/http_routes.go @@ -0,0 +1,102 @@ +package router + +import ( + "net/http" + + resthttp "github.com/onflow/flow-go/engine/access/rest/http" + "github.com/onflow/flow-go/engine/access/rest/http/routes" +) + +type route struct { + Name string + Method string + Pattern string + Handler resthttp.ApiHandlerFunc +} + +var Routes = []route{{ + Method: http.MethodGet, + Pattern: "/transactions/{id}", + Name: "getTransactionByID", + Handler: routes.GetTransactionByID, +}, { + Method: http.MethodPost, + Pattern: "/transactions", + Name: "createTransaction", + Handler: routes.CreateTransaction, +}, { + Method: http.MethodGet, + Pattern: "/transaction_results/{id}", + Name: "getTransactionResultByID", + Handler: routes.GetTransactionResultByID, +}, { + Method: http.MethodGet, + Pattern: "/blocks/{id}", + Name: "getBlocksByIDs", + Handler: routes.GetBlocksByIDs, +}, { + Method: http.MethodGet, + Pattern: "/blocks", + Name: "getBlocksByHeight", + Handler: routes.GetBlocksByHeight, +}, { + Method: http.MethodGet, + Pattern: "/blocks/{id}/payload", + Name: "getBlockPayloadByID", + Handler: routes.GetBlockPayloadByID, +}, { + Method: http.MethodGet, + Pattern: "/execution_results/{id}", + Name: "getExecutionResultByID", + Handler: routes.GetExecutionResultByID, +}, { + Method: http.MethodGet, + Pattern: "/execution_results", + Name: "getExecutionResultByBlockID", + Handler: routes.GetExecutionResultsByBlockIDs, +}, { + Method: http.MethodGet, + Pattern: "/collections/{id}", + Name: "getCollectionByID", + Handler: routes.GetCollectionByID, +}, { + Method: http.MethodPost, + Pattern: "/scripts", + Name: "executeScript", + Handler: routes.ExecuteScript, +}, { + Method: http.MethodGet, + Pattern: "/accounts/{address}", + Name: "getAccount", + Handler: routes.GetAccount, +}, { + Method: http.MethodGet, + Pattern: "/accounts/{address}/balance", + Name: "getAccountBalance", + Handler: routes.GetAccountBalance, +}, { + Method: http.MethodGet, + Pattern: "/accounts/{address}/keys/{index}", + Name: "getAccountKeyByIndex", + Handler: routes.GetAccountKeyByIndex, +}, { + Method: http.MethodGet, + Pattern: "/accounts/{address}/keys", + Name: "getAccountKeys", + Handler: routes.GetAccountKeys, +}, { + Method: http.MethodGet, + Pattern: "/events", + Name: "getEvents", + Handler: routes.GetEvents, +}, { + Method: http.MethodGet, + Pattern: "/network/parameters", + Name: "getNetworkParameters", + Handler: routes.GetNetworkParameters, +}, { + Method: http.MethodGet, + Pattern: "/node_version_info", + Name: "getNodeVersionInfo", + Handler: routes.GetNodeVersionInfo, +}} diff --git a/engine/access/rest/routes/router.go b/engine/access/rest/router/router.go similarity index 54% rename from engine/access/rest/routes/router.go rename to engine/access/rest/router/router.go index 90092c3c4c7..102f9797639 100644 --- a/engine/access/rest/routes/router.go +++ b/engine/access/rest/router/router.go @@ -1,8 +1,7 @@ -package routes +package router import ( "fmt" - "net/http" "regexp" "strings" @@ -10,8 +9,10 @@ import ( "github.com/rs/zerolog" "github.com/onflow/flow-go/access" - "github.com/onflow/flow-go/engine/access/rest/middleware" - "github.com/onflow/flow-go/engine/access/rest/models" + "github.com/onflow/flow-go/engine/access/rest/common/middleware" + "github.com/onflow/flow-go/engine/access/rest/http" + "github.com/onflow/flow-go/engine/access/rest/http/models" + legacyws "github.com/onflow/flow-go/engine/access/rest/websockets/legacy" "github.com/onflow/flow-go/engine/access/state_stream" "github.com/onflow/flow-go/engine/access/state_stream/backend" "github.com/onflow/flow-go/model/flow" @@ -53,7 +54,7 @@ func (b *RouterBuilder) AddRestRoutes( ) *RouterBuilder { linkGenerator := models.NewLinkGeneratorImpl(b.v1SubRouter) for _, r := range Routes { - h := NewHandler(b.logger, backend, r.Handler, linkGenerator, chain, maxRequestSize) + h := http.NewHandler(b.logger, backend, r.Handler, linkGenerator, chain, maxRequestSize) b.v1SubRouter. Methods(r.Method). Path(r.Pattern). @@ -63,16 +64,16 @@ func (b *RouterBuilder) AddRestRoutes( return b } -// AddWsRoutes adds WebSocket routes to the router. -func (b *RouterBuilder) AddWsRoutes( +// AddWsLegacyRoutes adds WebSocket routes to the router. +func (b *RouterBuilder) AddWsLegacyRoutes( stateStreamApi state_stream.API, chain flow.Chain, stateStreamConfig backend.Config, maxRequestSize int64, ) *RouterBuilder { - for _, r := range WSRoutes { - h := NewWSHandler(b.logger, stateStreamApi, r.Handler, chain, stateStreamConfig, maxRequestSize) + for _, r := range WSLegacyRoutes { + h := legacyws.NewWSHandler(b.logger, stateStreamApi, r.Handler, chain, stateStreamConfig, maxRequestSize) b.v1SubRouter. Methods(r.Method). Path(r.Pattern). @@ -87,114 +88,6 @@ func (b *RouterBuilder) Build() *mux.Router { return b.router } -type route struct { - Name string - Method string - Pattern string - Handler ApiHandlerFunc -} - -type wsroute struct { - Name string - Method string - Pattern string - Handler SubscribeHandlerFunc -} - -var Routes = []route{{ - Method: http.MethodGet, - Pattern: "/transactions/{id}", - Name: "getTransactionByID", - Handler: GetTransactionByID, -}, { - Method: http.MethodPost, - Pattern: "/transactions", - Name: "createTransaction", - Handler: CreateTransaction, -}, { - Method: http.MethodGet, - Pattern: "/transaction_results/{id}", - Name: "getTransactionResultByID", - Handler: GetTransactionResultByID, -}, { - Method: http.MethodGet, - Pattern: "/blocks/{id}", - Name: "getBlocksByIDs", - Handler: GetBlocksByIDs, -}, { - Method: http.MethodGet, - Pattern: "/blocks", - Name: "getBlocksByHeight", - Handler: GetBlocksByHeight, -}, { - Method: http.MethodGet, - Pattern: "/blocks/{id}/payload", - Name: "getBlockPayloadByID", - Handler: GetBlockPayloadByID, -}, { - Method: http.MethodGet, - Pattern: "/execution_results/{id}", - Name: "getExecutionResultByID", - Handler: GetExecutionResultByID, -}, { - Method: http.MethodGet, - Pattern: "/execution_results", - Name: "getExecutionResultByBlockID", - Handler: GetExecutionResultsByBlockIDs, -}, { - Method: http.MethodGet, - Pattern: "/collections/{id}", - Name: "getCollectionByID", - Handler: GetCollectionByID, -}, { - Method: http.MethodPost, - Pattern: "/scripts", - Name: "executeScript", - Handler: ExecuteScript, -}, { - Method: http.MethodGet, - Pattern: "/accounts/{address}", - Name: "getAccount", - Handler: GetAccount, -}, { - Method: http.MethodGet, - Pattern: "/accounts/{address}/balance", - Name: "getAccountBalance", - Handler: GetAccountBalance, -}, { - Method: http.MethodGet, - Pattern: "/accounts/{address}/keys/{index}", - Name: "getAccountKeyByIndex", - Handler: GetAccountKeyByIndex, -}, { - Method: http.MethodGet, - Pattern: "/accounts/{address}/keys", - Name: "getAccountKeys", - Handler: GetAccountKeys, -}, { - Method: http.MethodGet, - Pattern: "/events", - Name: "getEvents", - Handler: GetEvents, -}, { - Method: http.MethodGet, - Pattern: "/network/parameters", - Name: "getNetworkParameters", - Handler: GetNetworkParameters, -}, { - Method: http.MethodGet, - Pattern: "/node_version_info", - Name: "getNodeVersionInfo", - Handler: GetNodeVersionInfo, -}} - -var WSRoutes = []wsroute{{ - Method: http.MethodGet, - Pattern: "/subscribe_events", - Name: "subscribeEvents", - Handler: SubscribeEvents, -}} - var routeUrlMap = map[string]string{} var routeRE = regexp.MustCompile(`(?i)/v1/(\w+)(/(\w+))?(/(\w+))?(/(\w+))?`) @@ -202,7 +95,7 @@ func init() { for _, r := range Routes { routeUrlMap[r.Pattern] = r.Name } - for _, r := range WSRoutes { + for _, r := range WSLegacyRoutes { routeUrlMap[r.Pattern] = r.Name } } diff --git a/engine/access/rest/routes/router_test.go b/engine/access/rest/router/router_test.go similarity index 99% rename from engine/access/rest/routes/router_test.go rename to engine/access/rest/router/router_test.go index bcc4c20cc1f..36f0c0d003f 100644 --- a/engine/access/rest/routes/router_test.go +++ b/engine/access/rest/router/router_test.go @@ -1,4 +1,4 @@ -package routes +package router import ( "testing" diff --git a/engine/access/rest/routes/test_helpers.go b/engine/access/rest/router/router_test_helpers.go similarity index 63% rename from engine/access/rest/routes/test_helpers.go rename to engine/access/rest/router/router_test_helpers.go index 8053bf9d356..59a1d27ea4d 100644 --- a/engine/access/rest/routes/test_helpers.go +++ b/engine/access/rest/router/router_test_helpers.go @@ -1,4 +1,4 @@ -package routes +package router import ( "bufio" @@ -16,6 +16,7 @@ import ( "github.com/onflow/flow-go/access" "github.com/onflow/flow-go/access/mock" + "github.com/onflow/flow-go/engine/access/rest/common" "github.com/onflow/flow-go/engine/access/state_stream" "github.com/onflow/flow-go/engine/access/state_stream/backend" "github.com/onflow/flow-go/engine/access/subscription" @@ -27,16 +28,16 @@ import ( const ( ExpandableFieldPayload = "payload" ExpandableExecutionResult = "execution_result" - sealedHeightQueryParam = "sealed" - finalHeightQueryParam = "final" - startHeightQueryParam = "start_height" - endHeightQueryParam = "end_height" - heightQueryParam = "height" - startBlockIdQueryParam = "start_block_id" - eventTypesQueryParams = "event_types" - addressesQueryParams = "addresses" - contractsQueryParams = "contracts" - heartbeatIntervalQueryParam = "heartbeat_interval" + SealedHeightQueryParam = "sealed" + FinalHeightQueryParam = "final" + StartHeightQueryParam = "start_height" + EndHeightQueryParam = "end_height" + HeightQueryParam = "height" + StartBlockIdQueryParam = "start_block_id" + EventTypesQueryParams = "event_types" + AddressesQueryParams = "addresses" + ContractsQueryParams = "contracts" + HeartbeatIntervalQueryParam = "heartbeat_interval" ) // fakeNetConn implements a mocked ws connection that can be injected in testing logic. @@ -47,7 +48,7 @@ type fakeNetConn struct { var _ net.Conn = (*fakeNetConn)(nil) -// Close closes the fakeNetConn and signals its closure by closing the "closed" channel. +// Close closes the fakeNetConn and signals its closure by closing the "Closed" channel. func (c fakeNetConn) Close() error { select { case <-c.closed: @@ -82,51 +83,51 @@ func (a fakeAddr) String() string { return "str" } -// testHijackResponseRecorder is a custom ResponseRecorder that implements the http.Hijacker interface +// TestHijackResponseRecorder is a custom ResponseRecorder that implements the http.Hijacker interface // for testing WebSocket connections and hijacking. -type testHijackResponseRecorder struct { +type TestHijackResponseRecorder struct { *httptest.ResponseRecorder - closed chan struct{} - responseBuff *bytes.Buffer + Closed chan struct{} + ResponseBuff *bytes.Buffer } -var _ http.Hijacker = (*testHijackResponseRecorder)(nil) +var _ http.Hijacker = (*TestHijackResponseRecorder)(nil) // Hijack implements the http.Hijacker interface by returning a fakeNetConn and a bufio.ReadWriter // that simulate a hijacked connection. -func (w *testHijackResponseRecorder) Hijack() (net.Conn, *bufio.ReadWriter, error) { +func (w *TestHijackResponseRecorder) Hijack() (net.Conn, *bufio.ReadWriter, error) { br := bufio.NewReaderSize(strings.NewReader(""), subscription.DefaultSendBufferSize) bw := bufio.NewWriterSize(&bytes.Buffer{}, subscription.DefaultSendBufferSize) - w.responseBuff = bytes.NewBuffer(make([]byte, 0)) - w.closed = make(chan struct{}, 1) + w.ResponseBuff = bytes.NewBuffer(make([]byte, 0)) + w.Closed = make(chan struct{}, 1) - return fakeNetConn{w.responseBuff, w.closed}, bufio.NewReadWriter(br, bw), nil + return fakeNetConn{w.ResponseBuff, w.Closed}, bufio.NewReadWriter(br, bw), nil } -func (w *testHijackResponseRecorder) Close() error { +func (w *TestHijackResponseRecorder) Close() error { select { - case <-w.closed: + case <-w.Closed: default: - close(w.closed) + close(w.Closed) } return nil } -// newTestHijackResponseRecorder creates a new instance of testHijackResponseRecorder. -func newTestHijackResponseRecorder() *testHijackResponseRecorder { - return &testHijackResponseRecorder{ +// NewTestHijackResponseRecorder creates a new instance of TestHijackResponseRecorder. +func NewTestHijackResponseRecorder() *TestHijackResponseRecorder { + return &TestHijackResponseRecorder{ ResponseRecorder: httptest.NewRecorder(), } } -func executeRequest(req *http.Request, backend access.API) *httptest.ResponseRecorder { +func ExecuteRequest(req *http.Request, backend access.API) *httptest.ResponseRecorder { router := NewRouterBuilder( unittest.Logger(), metrics.NewNoopCollector(), ).AddRestRoutes( backend, flow.Testnet.Chain(), - DefaultMaxRequestSize, + common.DefaultMaxRequestSize, ).Build() rr := httptest.NewRecorder() @@ -134,7 +135,7 @@ func executeRequest(req *http.Request, backend access.API) *httptest.ResponseRec return rr } -func executeWsRequest(req *http.Request, stateStreamApi state_stream.API, responseRecorder *testHijackResponseRecorder, chain flow.Chain) { +func ExecuteWsRequest(req *http.Request, stateStreamApi state_stream.API, responseRecorder *TestHijackResponseRecorder, chain flow.Chain) { restCollector := metrics.NewNoopCollector() config := backend.Config{ @@ -143,18 +144,22 @@ func executeWsRequest(req *http.Request, stateStreamApi state_stream.API, respon HeartbeatInterval: subscription.DefaultHeartbeatInterval, } - router := NewRouterBuilder(unittest.Logger(), restCollector).AddWsRoutes( + router := NewRouterBuilder( + unittest.Logger(), + restCollector, + ).AddWsLegacyRoutes( stateStreamApi, - chain, config, DefaultMaxRequestSize).Build() + chain, config, common.DefaultMaxRequestSize, + ).Build() router.ServeHTTP(responseRecorder, req) } -func assertOKResponse(t *testing.T, req *http.Request, expectedRespBody string, backend *mock.API) { - assertResponse(t, req, http.StatusOK, expectedRespBody, backend) +func AssertOKResponse(t *testing.T, req *http.Request, expectedRespBody string, backend *mock.API) { + AssertResponse(t, req, http.StatusOK, expectedRespBody, backend) } -func assertResponse(t *testing.T, req *http.Request, status int, expectedRespBody string, backend *mock.API) { - rr := executeRequest(req, backend) +func AssertResponse(t *testing.T, req *http.Request, status int, expectedRespBody string, backend *mock.API) { + rr := ExecuteRequest(req, backend) actualResponseBody := rr.Body.String() require.JSONEq(t, expectedRespBody, diff --git a/engine/access/rest/router/ws_routes.go b/engine/access/rest/router/ws_routes.go new file mode 100644 index 00000000000..03c28fa27aa --- /dev/null +++ b/engine/access/rest/router/ws_routes.go @@ -0,0 +1,22 @@ +package router + +import ( + "net/http" + + "github.com/onflow/flow-go/engine/access/rest/websockets/legacy" + "github.com/onflow/flow-go/engine/access/rest/websockets/legacy/routes" +) + +type wsLegacyRoute struct { + Name string + Method string + Pattern string + Handler legacy.SubscribeHandlerFunc +} + +var WSLegacyRoutes = []wsLegacyRoute{{ + Method: http.MethodGet, + Pattern: "/subscribe_events", + Name: "subscribeEvents", + Handler: routes.SubscribeEvents, +}} diff --git a/engine/access/rest/server.go b/engine/access/rest/server.go index a33e2e24e58..d25044a60a5 100644 --- a/engine/access/rest/server.go +++ b/engine/access/rest/server.go @@ -8,7 +8,7 @@ import ( "github.com/rs/zerolog" "github.com/onflow/flow-go/access" - "github.com/onflow/flow-go/engine/access/rest/routes" + "github.com/onflow/flow-go/engine/access/rest/router" "github.com/onflow/flow-go/engine/access/state_stream" "github.com/onflow/flow-go/engine/access/state_stream/backend" "github.com/onflow/flow-go/model/flow" @@ -43,9 +43,9 @@ func NewServer(serverAPI access.API, stateStreamApi state_stream.API, stateStreamConfig backend.Config, ) (*http.Server, error) { - builder := routes.NewRouterBuilder(logger, restCollector).AddRestRoutes(serverAPI, chain, config.MaxRequestSize) + builder := router.NewRouterBuilder(logger, restCollector).AddRestRoutes(serverAPI, chain, config.MaxRequestSize) if stateStreamApi != nil { - builder.AddWsRoutes(stateStreamApi, chain, stateStreamConfig, config.MaxRequestSize) + builder.AddWsLegacyRoutes(stateStreamApi, chain, stateStreamConfig, config.MaxRequestSize) } c := cors.New(cors.Options{ diff --git a/engine/access/rest/util/select_filter_test.go b/engine/access/rest/util/select_filter_test.go index 4e2e769bce4..54d186e0e5e 100644 --- a/engine/access/rest/util/select_filter_test.go +++ b/engine/access/rest/util/select_filter_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "github.com/onflow/flow-go/engine/access/rest/models" + "github.com/onflow/flow-go/engine/access/rest/http/models" "github.com/onflow/flow-go/engine/access/rest/util" "github.com/stretchr/testify/require" diff --git a/engine/access/rest/request/subscribe_events.go b/engine/access/rest/websockets/legacy/request/subscribe_events.go similarity index 71% rename from engine/access/rest/request/subscribe_events.go rename to engine/access/rest/websockets/legacy/request/subscribe_events.go index 964edff641c..5b2574ccc82 100644 --- a/engine/access/rest/request/subscribe_events.go +++ b/engine/access/rest/websockets/legacy/request/subscribe_events.go @@ -4,9 +4,12 @@ import ( "fmt" "strconv" + "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/engine/access/rest/http/request" "github.com/onflow/flow-go/model/flow" ) +const startHeightQuery = "start_height" const startBlockIdQuery = "start_block_id" const eventTypesQuery = "event_types" const addressesQuery = "addresses" @@ -24,7 +27,17 @@ type SubscribeEvents struct { HeartbeatInterval uint64 } -func (g *SubscribeEvents) Build(r *Request) error { +// SubscribeEventsRequest extracts necessary variables from the provided request, +// builds a SubscribeEvents instance, and validates it. +// +// No errors are expected during normal operation. +func SubscribeEventsRequest(r *common.Request) (SubscribeEvents, error) { + var req SubscribeEvents + err := req.Build(r) + return req, err +} + +func (g *SubscribeEvents) Build(r *common.Request) error { return g.Parse( r.GetQueryParam(startBlockIdQuery), r.GetQueryParam(startHeightQuery), @@ -43,14 +56,14 @@ func (g *SubscribeEvents) Parse( rawContracts []string, rawHeartbeatInterval string, ) error { - var startBlockID ID + var startBlockID request.ID err := startBlockID.Parse(rawStartBlockID) if err != nil { return err } g.StartBlockID = startBlockID.Flow() - var height Height + var height request.Height err = height.Parse(rawStartHeight) if err != nil { return fmt.Errorf("invalid start height: %w", err) @@ -58,16 +71,16 @@ func (g *SubscribeEvents) Parse( g.StartHeight = height.Flow() // if both start_block_id and start_height are provided - if g.StartBlockID != flow.ZeroID && g.StartHeight != EmptyHeight { + if g.StartBlockID != flow.ZeroID && g.StartHeight != request.EmptyHeight { return fmt.Errorf("can only provide either block ID or start height") } // default to root block - if g.StartHeight == EmptyHeight { + if g.StartHeight == request.EmptyHeight { g.StartHeight = 0 } - var eventTypes EventTypes + var eventTypes request.EventTypes err = eventTypes.Parse(rawTypes) if err != nil { return err diff --git a/engine/access/rest/routes/subscribe_events.go b/engine/access/rest/websockets/legacy/routes/subscribe_events.go similarity index 53% rename from engine/access/rest/routes/subscribe_events.go rename to engine/access/rest/websockets/legacy/routes/subscribe_events.go index e1aca3bb316..9d159e7bdd3 100644 --- a/engine/access/rest/routes/subscribe_events.go +++ b/engine/access/rest/websockets/legacy/routes/subscribe_events.go @@ -3,8 +3,9 @@ package routes import ( "context" - "github.com/onflow/flow-go/engine/access/rest/models" - "github.com/onflow/flow-go/engine/access/rest/request" + "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/engine/access/rest/websockets/legacy" + "github.com/onflow/flow-go/engine/access/rest/websockets/legacy/request" "github.com/onflow/flow-go/engine/access/state_stream" "github.com/onflow/flow-go/engine/access/subscription" ) @@ -12,29 +13,29 @@ import ( // SubscribeEvents create websocket connection and write to it requested events. func SubscribeEvents( ctx context.Context, - request *request.Request, - wsController *WebsocketController, + r *common.Request, + wsController *legacy.WebsocketController, ) (subscription.Subscription, error) { - req, err := request.SubscribeEventsRequest() + req, err := request.SubscribeEventsRequest(r) if err != nil { - return nil, models.NewBadRequestError(err) + return nil, common.NewBadRequestError(err) } // Retrieve the filter parameters from the request, if provided filter, err := state_stream.NewEventFilter( - wsController.eventFilterConfig, - request.Chain, + wsController.EventFilterConfig, + r.Chain, req.EventTypes, req.Addresses, req.Contracts, ) if err != nil { - return nil, models.NewBadRequestError(err) + return nil, common.NewBadRequestError(err) } // Check if heartbeat interval was passed via request if req.HeartbeatInterval > 0 { - wsController.heartbeatInterval = req.HeartbeatInterval + wsController.HeartbeatInterval = req.HeartbeatInterval } - return wsController.api.SubscribeEvents(ctx, req.StartBlockID, req.StartHeight, filter), nil + return wsController.Api.SubscribeEvents(ctx, req.StartBlockID, req.StartHeight, filter), nil } diff --git a/engine/access/rest/routes/subscribe_events_test.go b/engine/access/rest/websockets/legacy/routes/subscribe_events_test.go similarity index 89% rename from engine/access/rest/routes/subscribe_events_test.go rename to engine/access/rest/websockets/legacy/routes/subscribe_events_test.go index 6eb56032abf..c4353cecae2 100644 --- a/engine/access/rest/routes/subscribe_events_test.go +++ b/engine/access/rest/websockets/legacy/routes/subscribe_events_test.go @@ -1,4 +1,4 @@ -package routes +package routes_test import ( "crypto/rand" @@ -20,7 +20,8 @@ import ( "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" - "github.com/onflow/flow-go/engine/access/rest/request" + "github.com/onflow/flow-go/engine/access/rest/http/request" + "github.com/onflow/flow-go/engine/access/rest/router" "github.com/onflow/flow-go/engine/access/state_stream" "github.com/onflow/flow-go/engine/access/state_stream/backend" mockstatestream "github.com/onflow/flow-go/engine/access/state_stream/mock" @@ -245,13 +246,13 @@ func (s *SubscribeEventsSuite) TestSubscribeEvents() { req, err := getSubscribeEventsRequest(s.T(), test.startBlockID, test.startHeight, test.eventTypes, test.addresses, test.contracts, test.heartbeatInterval, test.headers) require.NoError(s.T(), err) - respRecorder := newTestHijackResponseRecorder() + respRecorder := router.NewTestHijackResponseRecorder() // closing the connection after 1 second go func() { time.Sleep(1 * time.Second) respRecorder.Close() }() - executeWsRequest(req, stateStreamBackend, respRecorder, chainID.Chain()) + router.ExecuteWsRequest(req, stateStreamBackend, respRecorder, chainID.Chain()) requireResponse(s.T(), respRecorder, expectedEventsResponses) }) } @@ -262,8 +263,8 @@ func (s *SubscribeEventsSuite) TestSubscribeEventsHandlesErrors() { stateStreamBackend := mockstatestream.NewAPI(s.T()) req, err := getSubscribeEventsRequest(s.T(), s.blocks[0].ID(), s.blocks[0].Header.Height, nil, nil, nil, 1, nil) require.NoError(s.T(), err) - respRecorder := newTestHijackResponseRecorder() - executeWsRequest(req, stateStreamBackend, respRecorder, chainID.Chain()) + respRecorder := router.NewTestHijackResponseRecorder() + router.ExecuteWsRequest(req, stateStreamBackend, respRecorder, chainID.Chain()) requireError(s.T(), respRecorder, "can only provide either block ID or start height") }) @@ -287,8 +288,8 @@ func (s *SubscribeEventsSuite) TestSubscribeEventsHandlesErrors() { req, err := getSubscribeEventsRequest(s.T(), invalidBlock.ID(), request.EmptyHeight, nil, nil, nil, 1, nil) require.NoError(s.T(), err) - respRecorder := newTestHijackResponseRecorder() - executeWsRequest(req, stateStreamBackend, respRecorder, chainID.Chain()) + respRecorder := router.NewTestHijackResponseRecorder() + router.ExecuteWsRequest(req, stateStreamBackend, respRecorder, chainID.Chain()) requireError(s.T(), respRecorder, "stream encountered an error: subscription error") }) @@ -296,8 +297,8 @@ func (s *SubscribeEventsSuite) TestSubscribeEventsHandlesErrors() { stateStreamBackend := mockstatestream.NewAPI(s.T()) req, err := getSubscribeEventsRequest(s.T(), s.blocks[0].ID(), request.EmptyHeight, []string{"foo"}, nil, nil, 1, nil) require.NoError(s.T(), err) - respRecorder := newTestHijackResponseRecorder() - executeWsRequest(req, stateStreamBackend, respRecorder, chainID.Chain()) + respRecorder := router.NewTestHijackResponseRecorder() + router.ExecuteWsRequest(req, stateStreamBackend, respRecorder, chainID.Chain()) requireError(s.T(), respRecorder, "invalid event type format") }) @@ -321,8 +322,8 @@ func (s *SubscribeEventsSuite) TestSubscribeEventsHandlesErrors() { req, err := getSubscribeEventsRequest(s.T(), s.blocks[0].ID(), request.EmptyHeight, nil, nil, nil, 1, nil) require.NoError(s.T(), err) - respRecorder := newTestHijackResponseRecorder() - executeWsRequest(req, stateStreamBackend, respRecorder, chainID.Chain()) + respRecorder := router.NewTestHijackResponseRecorder() + router.ExecuteWsRequest(req, stateStreamBackend, respRecorder, chainID.Chain()) requireError(s.T(), respRecorder, "subscription channel closed") }) } @@ -340,24 +341,24 @@ func getSubscribeEventsRequest(t *testing.T, q := u.Query() if startBlockId != flow.ZeroID { - q.Add(startBlockIdQueryParam, startBlockId.String()) + q.Add(router.StartBlockIdQueryParam, startBlockId.String()) } if startHeight != request.EmptyHeight { - q.Add(startHeightQueryParam, fmt.Sprintf("%d", startHeight)) + q.Add(router.StartHeightQueryParam, fmt.Sprintf("%d", startHeight)) } if len(eventTypes) > 0 { - q.Add(eventTypesQueryParams, strings.Join(eventTypes, ",")) + q.Add(router.EventTypesQueryParams, strings.Join(eventTypes, ",")) } if len(addresses) > 0 { - q.Add(addressesQueryParams, strings.Join(addresses, ",")) + q.Add(router.AddressesQueryParams, strings.Join(addresses, ",")) } if len(contracts) > 0 { - q.Add(contractsQueryParams, strings.Join(contracts, ",")) + q.Add(router.ContractsQueryParams, strings.Join(contracts, ",")) } - q.Add(heartbeatIntervalQueryParam, fmt.Sprintf("%d", heartbeatInterval)) + q.Add(router.HeartbeatIntervalQueryParam, fmt.Sprintf("%d", heartbeatInterval)) u.RawQuery = q.Encode() key, err := generateWebSocketKey() @@ -392,18 +393,18 @@ func generateWebSocketKey() (string, error) { return base64.StdEncoding.EncodeToString(keyBytes), nil } -func requireError(t *testing.T, recorder *testHijackResponseRecorder, expected string) { - <-recorder.closed - require.Contains(t, recorder.responseBuff.String(), expected) +func requireError(t *testing.T, recorder *router.TestHijackResponseRecorder, expected string) { + <-recorder.Closed + require.Contains(t, recorder.ResponseBuff.String(), expected) } // requireResponse validates that the response received from WebSocket communication matches the expected EventsResponse. // This function compares the BlockID, Events count, and individual event properties for each expected and actual // EventsResponse. It ensures that the response received from WebSocket matches the expected structure and content. -func requireResponse(t *testing.T, recorder *testHijackResponseRecorder, expected []*backend.EventsResponse) { - <-recorder.closed +func requireResponse(t *testing.T, recorder *router.TestHijackResponseRecorder, expected []*backend.EventsResponse) { + <-recorder.Closed // Convert the actual response from respRecorder to JSON bytes - actualJSON := recorder.responseBuff.Bytes() + actualJSON := recorder.ResponseBuff.Bytes() // Define a regular expression pattern to match JSON objects pattern := `\{"BlockID":".*?","Height":\d+,"Events":\[(\{.*?})*\],"BlockTimestamp":".*?"\}` matches := regexp.MustCompile(pattern).FindAll(actualJSON, -1) diff --git a/engine/access/rest/routes/websocket_handler.go b/engine/access/rest/websockets/legacy/websocket_handler.go similarity index 89% rename from engine/access/rest/routes/websocket_handler.go rename to engine/access/rest/websockets/legacy/websocket_handler.go index 5e680e6e3ed..7132314b16c 100644 --- a/engine/access/rest/routes/websocket_handler.go +++ b/engine/access/rest/websockets/legacy/websocket_handler.go @@ -1,4 +1,4 @@ -package routes +package legacy import ( "context" @@ -11,8 +11,7 @@ import ( "github.com/rs/zerolog" "go.uber.org/atomic" - "github.com/onflow/flow-go/engine/access/rest/models" - "github.com/onflow/flow-go/engine/access/rest/request" + "github.com/onflow/flow-go/engine/access/rest/common" "github.com/onflow/flow-go/engine/access/state_stream" "github.com/onflow/flow-go/engine/access/state_stream/backend" "github.com/onflow/flow-go/engine/access/subscription" @@ -36,12 +35,12 @@ const ( type WebsocketController struct { logger zerolog.Logger conn *websocket.Conn // the WebSocket connection for communication with the client - api state_stream.API // the state_stream.API instance for managing event subscriptions - eventFilterConfig state_stream.EventFilterConfig // the configuration for filtering events + Api state_stream.API // the state_stream.API instance for managing event subscriptions + EventFilterConfig state_stream.EventFilterConfig // the configuration for filtering events maxStreams int32 // the maximum number of streams allowed activeStreamCount *atomic.Int32 // the current number of active streams readChannel chan error // channel which notify closing connection by the client and provide errors to the client - heartbeatInterval uint64 // the interval to deliver heartbeat messages to client[IN BLOCKS] + HeartbeatInterval uint64 // the interval to deliver heartbeat messages to client[IN BLOCKS] } // SetWebsocketConf used to set read and write deadlines for WebSocket connections and establishes a Pong handler to @@ -50,11 +49,11 @@ type WebsocketController struct { func (wsController *WebsocketController) SetWebsocketConf() error { err := wsController.conn.SetWriteDeadline(time.Now().Add(writeWait)) // Set the initial write deadline for the first ping message if err != nil { - return models.NewRestError(http.StatusInternalServerError, "Set the initial write deadline error: ", err) + return common.NewRestError(http.StatusInternalServerError, "Set the initial write deadline error: ", err) } err = wsController.conn.SetReadDeadline(time.Now().Add(pongWait)) // Set the initial read deadline for the first pong message if err != nil { - return models.NewRestError(http.StatusInternalServerError, "Set the initial read deadline error: ", err) + return common.NewRestError(http.StatusInternalServerError, "Set the initial read deadline error: ", err) } // Establish a Pong handler wsController.conn.SetPongHandler(func(string) error { @@ -79,7 +78,7 @@ func (wsController *WebsocketController) SetWebsocketConf() error { // process are logged using the provided logger. func (wsController *WebsocketController) wsErrorHandler(err error) { // rest status type error should be returned with status and user message provided - var statusErr models.StatusError + var statusErr common.StatusError var wsCode int var wsMsg string @@ -135,12 +134,12 @@ func (wsController *WebsocketController) writeEvents(sub subscription.Subscripti return } err := fmt.Errorf("subscription channel closed, no error occurred") - wsController.wsErrorHandler(models.NewRestError(http.StatusRequestTimeout, "subscription channel closed", err)) + wsController.wsErrorHandler(common.NewRestError(http.StatusRequestTimeout, "subscription channel closed", err)) return } err := wsController.conn.SetWriteDeadline(time.Now().Add(writeWait)) if err != nil { - wsController.wsErrorHandler(models.NewRestError(http.StatusInternalServerError, "failed to set the initial write deadline: ", err)) + wsController.wsErrorHandler(common.NewRestError(http.StatusInternalServerError, "failed to set the initial write deadline: ", err)) return } @@ -154,7 +153,7 @@ func (wsController *WebsocketController) writeEvents(sub subscription.Subscripti // message will be emitted. if len(resp.Events) == 0 { blocksSinceLastMessage++ - if blocksSinceLastMessage < wsController.heartbeatInterval { + if blocksSinceLastMessage < wsController.HeartbeatInterval { continue } blocksSinceLastMessage = 0 @@ -181,7 +180,7 @@ func (wsController *WebsocketController) writeEvents(sub subscription.Subscripti case <-ticker.C: err := wsController.conn.SetWriteDeadline(time.Now().Add(writeWait)) if err != nil { - wsController.wsErrorHandler(models.NewRestError(http.StatusInternalServerError, "failed to set the initial write deadline: ", err)) + wsController.wsErrorHandler(common.NewRestError(http.StatusInternalServerError, "failed to set the initial write deadline: ", err)) return } if err := wsController.conn.WriteMessage(websocket.PingMessage, nil); err != nil { @@ -228,14 +227,14 @@ func (wsController *WebsocketController) read() { // SubscribeHandlerFunc is a function that contains endpoint handling logic for subscribes, fetches necessary resources type SubscribeHandlerFunc func( ctx context.Context, - request *request.Request, + request *common.Request, wsController *WebsocketController, ) (subscription.Subscription, error) // WSHandler is websocket handler implementing custom websocket handler function and allows easier handling of errors and // responses as it wraps functionality for handling error and responses outside of endpoint handling. type WSHandler struct { - *HttpHandler + *common.HttpHandler subscribeFunc SubscribeHandlerFunc api state_stream.API @@ -262,7 +261,7 @@ func NewWSHandler( maxStreams: int32(stateStreamConfig.MaxGlobalStreams), defaultHeartbeatInterval: stateStreamConfig.HeartbeatInterval, activeStreamCount: atomic.NewInt32(0), - HttpHandler: NewHttpHandler(logger, chain, maxRequestSize), + HttpHandler: common.NewHttpHandler(logger, chain, maxRequestSize), } return handler @@ -272,9 +271,9 @@ func NewWSHandler( // such as logging, error handling, request decorators func (h *WSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // create a logger - logger := h.Logger.With().Str("subscribe_url", r.URL.String()).Logger() + logger := h.HttpHandler.Logger.With().Str("subscribe_url", r.URL.String()).Logger() - err := h.VerifyRequest(w, r) + err := h.HttpHandler.VerifyRequest(w, r) if err != nil { // VerifyRequest sets the response error before returning return @@ -289,7 +288,7 @@ func (h *WSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } conn, err := upgrader.Upgrade(w, r, nil) if err != nil { - h.errorHandler(w, models.NewRestError(http.StatusInternalServerError, "webSocket upgrade error: ", err), logger) + h.HttpHandler.ErrorHandler(w, common.NewRestError(http.StatusInternalServerError, "webSocket upgrade error: ", err), logger) return } defer conn.Close() @@ -297,12 +296,12 @@ func (h *WSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { wsController := &WebsocketController{ logger: logger, conn: conn, - api: h.api, - eventFilterConfig: h.eventFilterConfig, + Api: h.api, + EventFilterConfig: h.eventFilterConfig, maxStreams: h.maxStreams, activeStreamCount: h.activeStreamCount, readChannel: make(chan error), - heartbeatInterval: h.defaultHeartbeatInterval, // set default heartbeat interval from state stream config + HeartbeatInterval: h.defaultHeartbeatInterval, // set default heartbeat interval from state stream config } err = wsController.SetWebsocketConf() @@ -313,7 +312,7 @@ func (h *WSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { if wsController.activeStreamCount.Load() >= wsController.maxStreams { err := fmt.Errorf("maximum number of streams reached") - wsController.wsErrorHandler(models.NewRestError(http.StatusServiceUnavailable, err.Error(), err)) + wsController.wsErrorHandler(common.NewRestError(http.StatusServiceUnavailable, err.Error(), err)) return } wsController.activeStreamCount.Add(1) @@ -324,7 +323,7 @@ func (h *WSHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - sub, err := h.subscribeFunc(ctx, request.Decorate(r, h.HttpHandler.Chain), wsController) + sub, err := h.subscribeFunc(ctx, common.Decorate(r, h.HttpHandler.Chain), wsController) if err != nil { wsController.wsErrorHandler(err) return diff --git a/engine/access/rest_api_test.go b/engine/access/rest_api_test.go index 2f28c8bda48..64dab073c1d 100644 --- a/engine/access/rest_api_test.go +++ b/engine/access/rest_api_test.go @@ -21,8 +21,9 @@ import ( accessmock "github.com/onflow/flow-go/engine/access/mock" "github.com/onflow/flow-go/engine/access/rest" - "github.com/onflow/flow-go/engine/access/rest/request" - "github.com/onflow/flow-go/engine/access/rest/routes" + "github.com/onflow/flow-go/engine/access/rest/common" + "github.com/onflow/flow-go/engine/access/rest/http/request" + "github.com/onflow/flow-go/engine/access/rest/router" "github.com/onflow/flow-go/engine/access/rpc" "github.com/onflow/flow-go/engine/access/rpc/backend" statestreambackend "github.com/onflow/flow-go/engine/access/state_stream/backend" @@ -424,7 +425,7 @@ func (suite *RestAPITestSuite) TestRequestSizeRestriction() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() // make a request of size larger than the max permitted size - requestBytes := make([]byte, routes.DefaultMaxRequestSize+1) + requestBytes := make([]byte, common.DefaultMaxRequestSize+1) script := restclient.ScriptsBody{ Script: string(requestBytes), } @@ -451,13 +452,13 @@ func assertError(t *testing.T, resp *http.Response, err error, expectedCode int, func optionsForBlockByID() *restclient.BlocksApiBlocksIdGetOpts { return &restclient.BlocksApiBlocksIdGetOpts{ - Expand: optional.NewInterface([]string{routes.ExpandableFieldPayload}), + Expand: optional.NewInterface([]string{router.ExpandableFieldPayload}), Select_: optional.NewInterface([]string{"header.id"}), } } func optionsForBlockByStartEndHeight(startHeight, endHeight uint64) *restclient.BlocksApiBlocksGetOpts { return &restclient.BlocksApiBlocksGetOpts{ - Expand: optional.NewInterface([]string{routes.ExpandableFieldPayload}), + Expand: optional.NewInterface([]string{router.ExpandableFieldPayload}), Select_: optional.NewInterface([]string{"header.id", "header.height"}), StartHeight: optional.NewInterface(startHeight), EndHeight: optional.NewInterface(endHeight), @@ -466,7 +467,7 @@ func optionsForBlockByStartEndHeight(startHeight, endHeight uint64) *restclient. func optionsForBlockByHeights(heights []uint64) *restclient.BlocksApiBlocksGetOpts { return &restclient.BlocksApiBlocksGetOpts{ - Expand: optional.NewInterface([]string{routes.ExpandableFieldPayload}), + Expand: optional.NewInterface([]string{router.ExpandableFieldPayload}), Select_: optional.NewInterface([]string{"header.id", "header.height"}), Height: optional.NewInterface(heights), } @@ -474,7 +475,7 @@ func optionsForBlockByHeights(heights []uint64) *restclient.BlocksApiBlocksGetOp func optionsForFinalizedBlock(finalOrSealed string) *restclient.BlocksApiBlocksGetOpts { return &restclient.BlocksApiBlocksGetOpts{ - Expand: optional.NewInterface([]string{routes.ExpandableFieldPayload}), + Expand: optional.NewInterface([]string{router.ExpandableFieldPayload}), Select_: optional.NewInterface([]string{"header.id", "header.height"}), Height: optional.NewInterface(finalOrSealed), } diff --git a/integration/tests/access/cohort3/rest_state_stream_test.go b/integration/tests/access/cohort3/rest_state_stream_test.go index 6e22e7d0390..4526c96e83e 100644 --- a/integration/tests/access/cohort3/rest_state_stream_test.go +++ b/integration/tests/access/cohort3/rest_state_stream_test.go @@ -15,7 +15,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" - "github.com/onflow/flow-go/engine/access/rest/request" + "github.com/onflow/flow-go/engine/access/rest/http/request" "github.com/onflow/flow-go/engine/access/state_stream/backend" "github.com/onflow/flow-go/engine/common/rpc/convert" "github.com/onflow/flow-go/integration/testnet"