From 3a3e8289976db3c3a3452d1adf4a68693aa1db56 Mon Sep 17 00:00:00 2001 From: Adam Shannon Date: Mon, 5 Nov 2018 14:29:11 -0600 Subject: [PATCH] server: split endpoints.go into batches.go and files.go I've always had confusion between endpoints.go vs routing.go. This also brings the code layout to more similarity with Moov's other projects. --- server/batches.go | 167 ++++++++++++++++++++++++++++ server/endpoints.go | 265 -------------------------------------------- server/files.go | 239 +++++++++++++++++++++++++++++++++++++++ server/logging.go | 10 -- server/routing.go | 163 ++------------------------- 5 files changed, 416 insertions(+), 428 deletions(-) create mode 100644 server/batches.go delete mode 100644 server/endpoints.go create mode 100644 server/files.go diff --git a/server/batches.go b/server/batches.go new file mode 100644 index 000000000..23da88c7e --- /dev/null +++ b/server/batches.go @@ -0,0 +1,167 @@ +// Copyright 2018 The Moov Authors +// Use of this source code is governed by an Apache License +// license that can be found in the LICENSE file. + +package server + +import ( + "context" + "encoding/json" + "net/http" + + "github.com/moov-io/ach" + + "github.com/go-kit/kit/endpoint" + "github.com/gorilla/mux" +) + +type createBatchRequest struct { + FileID string + BatchHeader ach.BatchHeader +} + +type createBatchResponse struct { + ID string `json:"id"` + Err error `json:"error"` +} + +func (r createBatchResponse) error() error { return r.Err } + +func createBatchEndpoint(s Service) endpoint.Endpoint { + return func(_ context.Context, request interface{}) (interface{}, error) { + req := request.(createBatchRequest) + id, e := s.CreateBatch(req.FileID, &req.BatchHeader) + return createBatchResponse{ + ID: id, + Err: e, + }, nil + } +} + +func decodeCreateBatchRequest(_ context.Context, r *http.Request) (interface{}, error) { + var req createBatchRequest + vars := mux.Vars(r) + id, ok := vars["fileID"] + if !ok { + return nil, ErrBadRouting + } + req.FileID = id + req.BatchHeader = *ach.NewBatchHeader() + if e := json.NewDecoder(r.Body).Decode(&req.BatchHeader); e != nil { + return nil, e + } + return req, nil +} + +type getBatchesRequest struct { + fileID string +} + +type getBatchesResponse struct { + // TODO(adam): change this to JSON encode without wrapper {"batches": [..]} + // We don't wrap json objects in other responses, so why here? + Batches []ach.Batcher `json:"batches"` + Err error `json:"error"` +} + +func (r getBatchesResponse) count() int { return len(r.Batches) } + +func (r getBatchesResponse) error() error { return r.Err } + +func decodeGetBatchesRequest(_ context.Context, r *http.Request) (interface{}, error) { + var req getBatchesRequest + vars := mux.Vars(r) + id, ok := vars["fileID"] + if !ok { + return nil, ErrBadRouting + } + req.fileID = id + return req, nil +} + +func getBatchesEndpoint(s Service) endpoint.Endpoint { + return func(_ context.Context, request interface{}) (interface{}, error) { + req := request.(getBatchesRequest) + return getBatchesResponse{ + Batches: s.GetBatches(req.fileID), + Err: nil, + }, nil + } +} + +type getBatchRequest struct { + fileID string + batchID string +} + +type getBatchResponse struct { + Batch ach.Batcher `json:"batch"` + Err error `json:"error"` +} + +func (r getBatchResponse) error() error { return r.Err } + +func decodeGetBatchRequest(_ context.Context, r *http.Request) (interface{}, error) { + var req getBatchRequest + vars := mux.Vars(r) + fileID, ok := vars["fileID"] + if !ok { + return nil, ErrBadRouting + } + batchID, ok := vars["batchID"] + if !ok { + return nil, ErrBadRouting + } + + req.fileID = fileID + req.batchID = batchID + return req, nil +} + +func getBatchEndpoint(s Service) endpoint.Endpoint { + return func(_ context.Context, request interface{}) (interface{}, error) { + req := request.(getBatchRequest) + batch, e := s.GetBatch(req.fileID, req.batchID) + return getBatchResponse{ + Batch: batch, + Err: e, + }, nil + } +} + +type deleteBatchRequest struct { + fileID string + batchID string +} + +type deleteBatchResponse struct { + Err error `json:"error"` +} + +func (r deleteBatchResponse) error() error { return r.Err } + +func decodeDeleteBatchRequest(_ context.Context, r *http.Request) (interface{}, error) { + var req deleteBatchRequest + vars := mux.Vars(r) + fileID, ok := vars["fileID"] + if !ok { + return nil, ErrBadRouting + } + batchID, ok := vars["batchID"] + if !ok { + return nil, ErrBadRouting + } + + req.fileID = fileID + req.batchID = batchID + return req, nil +} + +func deleteBatchEndpoint(s Service) endpoint.Endpoint { + return func(_ context.Context, request interface{}) (interface{}, error) { + req := request.(deleteBatchRequest) + return deleteBatchResponse{ + Err: s.DeleteBatch(req.fileID, req.batchID), + }, nil + } +} diff --git a/server/endpoints.go b/server/endpoints.go deleted file mode 100644 index 3cd6cf938..000000000 --- a/server/endpoints.go +++ /dev/null @@ -1,265 +0,0 @@ -package server - -import ( - "context" - - "github.com/go-kit/kit/endpoint" - "github.com/moov-io/ach" -) - -type Endpoints struct { - CreateFileEndpoint endpoint.Endpoint - GetFileEndpoint endpoint.Endpoint - GetFilesEndpoint endpoint.Endpoint - DeleteFileEndpoint endpoint.Endpoint - GetFileContentsEndpoint endpoint.Endpoint - ValidateFileEndpoint endpoint.Endpoint - CreateBatchEndpoint endpoint.Endpoint - GetBatchesEndpoint endpoint.Endpoint - GetBatchEndpoint endpoint.Endpoint - DeleteBatchEndpoint endpoint.Endpoint -} - -func MakeServerEndpoints(s Service, r Repository) Endpoints { - return Endpoints{ - CreateFileEndpoint: MakeCreateFileEndpoint(s, r), - GetFileEndpoint: MakeGetFileEndpoint(s), - GetFilesEndpoint: MakeGetFilesEndpoint(s), - DeleteFileEndpoint: MakeDeleteFileEndpoint(s), - GetFileContentsEndpoint: MakeGetFileContentsEndpoint(s), - ValidateFileEndpoint: MakeValidateFileEndpoint(s), - CreateBatchEndpoint: MakeCreateBatchEndpoint(s), - GetBatchesEndpoint: MakeGetBatchesEndpoint(s), - GetBatchEndpoint: MakeGetBatchEndpoint(s), - DeleteBatchEndpoint: MakeDeleteBatchEndpoint(s), - } -} - -// MakeCreateFileEndpoint returns an endpoint via the passed service. -func MakeCreateFileEndpoint(s Service, r Repository) endpoint.Endpoint { - return func(_ context.Context, request interface{}) (interface{}, error) { - req := request.(createFileRequest) - - if req.File.ID == "" { - // No File ID, so create the file - id, e := s.CreateFile(&req.File.Header) - return createFileResponse{ - ID: id, - Err: e, - }, nil - } else { - return createFileResponse{ - ID: req.File.ID, - Err: r.StoreFile(req.File), - }, nil - } - } -} - -type createFileRequest struct { - File *ach.File -} - -type createFileResponse struct { - ID string `json:"id"` - Err error `json:"error"` -} - -func (r createFileResponse) error() error { return r.Err } - -func MakeGetFilesEndpoint(s Service) endpoint.Endpoint { - return func(_ context.Context, _ interface{}) (interface{}, error) { - return getFilesResponse{ - Files: s.GetFiles(), - Err: nil, - }, nil - } -} - -type getFilesRequest struct{} - -type getFilesResponse struct { - Files []*ach.File `json:"files"` - Err error `json:"error"` -} - -func (r getFilesResponse) count() int { return len(r.Files) } - -func (r getFilesResponse) error() error { return r.Err } - -// MakeGetFileEndpoint returns an endpoint via the passed service. -// Primarily useful in a server. -func MakeGetFileEndpoint(s Service) endpoint.Endpoint { - return func(_ context.Context, request interface{}) (interface{}, error) { - req := request.(getFileRequest) - f, e := s.GetFile(req.ID) - return getFileResponse{ - File: f, - Err: e, - }, nil - } -} - -type getFileRequest struct { - ID string -} - -type getFileResponse struct { - File *ach.File `json:"file"` - Err error `json:"error"` -} - -func (r getFileResponse) error() error { return r.Err } - -func MakeDeleteFileEndpoint(s Service) endpoint.Endpoint { - return func(_ context.Context, request interface{}) (interface{}, error) { - req := request.(deleteFileRequest) - return deleteFileResponse{ - Err: s.DeleteFile(req.ID), - }, nil - } -} - -type deleteFileRequest struct { - ID string -} - -type deleteFileResponse struct { - Err error `json:"err"` -} - -func (r deleteFileResponse) error() error { return r.Err } - -func MakeGetFileContentsEndpoint(s Service) endpoint.Endpoint { - return func(_ context.Context, request interface{}) (interface{}, error) { - req := request.(getFileContentsRequest) - r, err := s.GetFileContents(req.ID) - if err != nil { - return getFileContentsResponse{Err: err}, nil - } - return r, nil - } -} - -type getFileContentsRequest struct { - ID string -} - -type getFileContentsResponse struct { - Err error `json:"error"` -} - -func (v getFileContentsResponse) error() error { return v.Err } - -func MakeValidateFileEndpoint(s Service) endpoint.Endpoint { - return func(_ context.Context, request interface{}) (interface{}, error) { - req := request.(validateFileRequest) - return validateFileResponse{ - Err: s.ValidateFile(req.ID), - }, nil - } -} - -type validateFileRequest struct { - ID string -} - -type validateFileResponse struct { - Err error `json:"error"` -} - -func (v validateFileResponse) error() error { return v.Err } - -//** Batches ** // - -// MakeCreateBatchEndpoint returns an endpoint via the passed service. -func MakeCreateBatchEndpoint(s Service) endpoint.Endpoint { - return func(_ context.Context, request interface{}) (interface{}, error) { - req := request.(createBatchRequest) - id, e := s.CreateBatch(req.FileID, &req.BatchHeader) - return createBatchResponse{ - ID: id, - Err: e, - }, nil - } -} - -type createBatchRequest struct { - FileID string - BatchHeader ach.BatchHeader -} - -type createBatchResponse struct { - ID string `json:"id"` - Err error `json:"error"` -} - -func (r createBatchResponse) error() error { return r.Err } - -func MakeGetBatchesEndpoint(s Service) endpoint.Endpoint { - return func(_ context.Context, request interface{}) (interface{}, error) { - req := request.(getBatchesRequest) - return getBatchesResponse{ - Batches: s.GetBatches(req.fileID), - Err: nil, - }, nil - } -} - -type getBatchesRequest struct { - fileID string -} - -type getBatchesResponse struct { - // TODO(adam): change this to JSON encode without wrapper {"batches": [..]} - // We don't wrap json objects in other responses, so why here? - Batches []ach.Batcher `json:"batches"` - Err error `json:"error"` -} - -func (r getBatchesResponse) count() int { return len(r.Batches) } - -func (r getBatchesResponse) error() error { return r.Err } - -func MakeGetBatchEndpoint(s Service) endpoint.Endpoint { - return func(_ context.Context, request interface{}) (interface{}, error) { - req := request.(getBatchRequest) - batch, e := s.GetBatch(req.fileID, req.batchID) - return getBatchResponse{ - Batch: batch, - Err: e, - }, nil - } -} - -type getBatchRequest struct { - fileID string - batchID string -} - -type getBatchResponse struct { - Batch ach.Batcher `json:"batch"` - Err error `json:"error"` -} - -func (r getBatchResponse) error() error { return r.Err } - -func MakeDeleteBatchEndpoint(s Service) endpoint.Endpoint { - return func(_ context.Context, request interface{}) (interface{}, error) { - req := request.(deleteBatchRequest) - return deleteBatchResponse{ - Err: s.DeleteBatch(req.fileID, req.batchID), - }, nil - } -} - -type deleteBatchRequest struct { - fileID string - batchID string -} - -type deleteBatchResponse struct { - Err error `json:"error"` -} - -func (r deleteBatchResponse) error() error { return r.Err } diff --git a/server/files.go b/server/files.go new file mode 100644 index 000000000..9dc159a73 --- /dev/null +++ b/server/files.go @@ -0,0 +1,239 @@ +// Copyright 2018 The Moov Authors +// Use of this source code is governed by an Apache License +// license that can be found in the LICENSE file. + +package server + +import ( + "bytes" + "context" + "io" + "io/ioutil" + "net/http" + "strings" + + "github.com/moov-io/ach" + + "github.com/go-kit/kit/endpoint" + "github.com/go-kit/kit/metrics/prometheus" + "github.com/gorilla/mux" + stdprometheus "github.com/prometheus/client_golang/prometheus" +) + +var ( + filesCreated = prometheus.NewCounterFrom(stdprometheus.CounterOpts{ + Name: "ach_files_created", + Help: "The number of ACH files created", + }, []string{"destination", "origin"}) +) + +type createFileRequest struct { + File *ach.File +} + +type createFileResponse struct { + ID string `json:"id"` + Err error `json:"error"` +} + +func (r createFileResponse) error() error { return r.Err } + +func createFileEndpoint(s Service, r Repository) endpoint.Endpoint { + return func(_ context.Context, request interface{}) (interface{}, error) { + req := request.(createFileRequest) + + // record a metric for files created + if req.File != nil && req.File.Header.ImmediateDestination != "" && req.File.Header.ImmediateOrigin != "" { + filesCreated.With("destination", req.File.Header.ImmediateDestination, "origin", req.File.Header.ImmediateOrigin).Add(1) + } + + if req.File.ID == "" { + // No File ID, so create the file + id, e := s.CreateFile(&req.File.Header) + return createFileResponse{ + ID: id, + Err: e, + }, nil + } else { + return createFileResponse{ + ID: req.File.ID, + Err: r.StoreFile(req.File), + }, nil + } + } +} + +func decodeCreateFileRequest(_ context.Context, request *http.Request) (interface{}, error) { + var r io.Reader + var req createFileRequest + + // Sets default values + req.File = &ach.File{ + Header: ach.NewFileHeader(), + } + + bs, err := ioutil.ReadAll(request.Body) + if err != nil { + return nil, err + } + + h := request.Header.Get("Content-Type") + if strings.Contains(h, "application/json") { + // Read body as ACH file in JSON + f, err := ach.FileFromJson(bs) + if err != nil { + return nil, err + } + req.File = f + } else { + // Attempt parsing body as an ACH File + r = bytes.NewReader(bs) + f, err := ach.NewReader(r).Read() + if err != nil { + return nil, err + } + req.File = &f + } + return req, nil +} + +type getFilesRequest struct{} + +type getFilesResponse struct { + Files []*ach.File `json:"files"` + Err error `json:"error"` +} + +func (r getFilesResponse) count() int { return len(r.Files) } + +func (r getFilesResponse) error() error { return r.Err } + +func getFilesEndpoint(s Service) endpoint.Endpoint { + return func(_ context.Context, _ interface{}) (interface{}, error) { + return getFilesResponse{ + Files: s.GetFiles(), + Err: nil, + }, nil + } +} + +func decodeGetFilesRequest(_ context.Context, r *http.Request) (interface{}, error) { + return getFilesRequest{}, nil +} + +type getFileRequest struct { + ID string +} + +type getFileResponse struct { + File *ach.File `json:"file"` + Err error `json:"error"` +} + +func (r getFileResponse) error() error { return r.Err } + +func getFileEndpoint(s Service) endpoint.Endpoint { + return func(_ context.Context, request interface{}) (interface{}, error) { + req := request.(getFileRequest) + f, e := s.GetFile(req.ID) + return getFileResponse{ + File: f, + Err: e, + }, nil + } +} + +func decodeGetFileRequest(_ context.Context, r *http.Request) (interface{}, error) { + vars := mux.Vars(r) + id, ok := vars["id"] + if !ok { + return nil, ErrBadRouting + } + return getFileRequest{ID: id}, nil +} + +type deleteFileRequest struct { + ID string +} + +type deleteFileResponse struct { + Err error `json:"err"` +} + +func (r deleteFileResponse) error() error { return r.Err } + +func deleteFileEndpoint(s Service) endpoint.Endpoint { + return func(_ context.Context, request interface{}) (interface{}, error) { + req := request.(deleteFileRequest) + return deleteFileResponse{ + Err: s.DeleteFile(req.ID), + }, nil + } +} + +func decodeDeleteFileRequest(_ context.Context, r *http.Request) (interface{}, error) { + vars := mux.Vars(r) + id, ok := vars["id"] + if !ok { + return nil, ErrBadRouting + } + return deleteFileRequest{ID: id}, nil +} + +type getFileContentsRequest struct { + ID string +} + +type getFileContentsResponse struct { + Err error `json:"error"` +} + +func (v getFileContentsResponse) error() error { return v.Err } + +func getFileContentsEndpoint(s Service) endpoint.Endpoint { + return func(_ context.Context, request interface{}) (interface{}, error) { + req := request.(getFileContentsRequest) + r, err := s.GetFileContents(req.ID) + if err != nil { + return getFileContentsResponse{Err: err}, nil + } + return r, nil + } +} + +func decodeGetFileContentsRequest(_ context.Context, r *http.Request) (interface{}, error) { + vars := mux.Vars(r) + id, ok := vars["id"] + if !ok { + return nil, ErrBadRouting + } + return getFileContentsRequest{ID: id}, nil +} + +type validateFileRequest struct { + ID string +} + +type validateFileResponse struct { + Err error `json:"error"` +} + +func (v validateFileResponse) error() error { return v.Err } + +func validateFileEndpoint(s Service) endpoint.Endpoint { + return func(_ context.Context, request interface{}) (interface{}, error) { + req := request.(validateFileRequest) + return validateFileResponse{ + Err: s.ValidateFile(req.ID), + }, nil + } +} + +func decodeValidateFileRequest(_ context.Context, r *http.Request) (interface{}, error) { + vars := mux.Vars(r) + id, ok := vars["id"] + if !ok { + return nil, ErrBadRouting + } + return validateFileRequest{ID: id}, nil +} diff --git a/server/logging.go b/server/logging.go index 51d800641..58a868e0b 100644 --- a/server/logging.go +++ b/server/logging.go @@ -8,15 +8,6 @@ import ( "github.com/moov-io/ach" "github.com/go-kit/kit/log" - "github.com/go-kit/kit/metrics/prometheus" - stdprometheus "github.com/prometheus/client_golang/prometheus" -) - -var ( - filesCreated = prometheus.NewCounterFrom(stdprometheus.CounterOpts{ - Name: "ach_files_created", - Help: "The number of ACH files created", - }, []string{"destination", "origin"}) ) // Middleware describes a service (as opposed to endpoint) middleware. @@ -71,7 +62,6 @@ func (mw loggingMiddleware) CreateFile(f *ach.FileHeader) (id string, err error) // TODO(adam): figure out if we care to fix this mw.logger.Log("method", "CreateFile", "id", f.ID, "took", t, "err", err) }() - filesCreated.With("destination", f.ImmediateDestination, "origin", f.ImmediateOrigin).Add(1) return mw.next.CreateFile(f) } diff --git a/server/routing.go b/server/routing.go index f75d6f722..154f2dbd9 100644 --- a/server/routing.go +++ b/server/routing.go @@ -1,17 +1,12 @@ package server import ( - "bytes" "context" "encoding/json" "fmt" "io" - "io/ioutil" "net/http" "strconv" - "strings" - - "github.com/moov-io/ach" "github.com/go-kit/kit/endpoint" "github.com/go-kit/kit/log" @@ -101,7 +96,6 @@ func preflightHandler(options []httptransport.ServerOption) http.Handler { func MakeHTTPHandler(s Service, repo Repository, logger log.Logger) http.Handler { r := mux.NewRouter() - e := MakeServerEndpoints(s, repo) options := []httptransport.ServerOption{ httptransport.ServerErrorLogger(logger), httptransport.ServerErrorEncoder(encodeError), @@ -116,61 +110,61 @@ func MakeHTTPHandler(s Service, repo Repository, logger log.Logger) http.Handler w.Write([]byte("PONG")) }) r.Methods("GET").Path("/files").Handler(httptransport.NewServer( - e.GetFilesEndpoint, + getFilesEndpoint(s), decodeGetFilesRequest, encodeResponse, options..., )) r.Methods("POST").Path("/files/create").Handler(httptransport.NewServer( - e.CreateFileEndpoint, + createFileEndpoint(s, repo), decodeCreateFileRequest, encodeResponse, options..., )) r.Methods("GET").Path("/files/{id}").Handler(httptransport.NewServer( - e.GetFileEndpoint, + getFileEndpoint(s), decodeGetFileRequest, encodeResponse, options..., )) r.Methods("GET").Path("/files/{id}/contents").Handler(httptransport.NewServer( - e.GetFileContentsEndpoint, + getFileContentsEndpoint(s), decodeGetFileContentsRequest, encodeTextResponse, options..., )) r.Methods("GET").Path("/files/{id}/validate").Handler(httptransport.NewServer( - e.ValidateFileEndpoint, + validateFileEndpoint(s), decodeValidateFileRequest, encodeResponse, options..., )) r.Methods("DELETE").Path("/files/{id}").Handler(httptransport.NewServer( - e.DeleteFileEndpoint, + deleteFileEndpoint(s), decodeDeleteFileRequest, encodeResponse, options..., )) r.Methods("POST").Path("/files/{fileID}/batches").Handler(httptransport.NewServer( - e.CreateBatchEndpoint, + createBatchEndpoint(s), decodeCreateBatchRequest, encodeResponse, options..., )) r.Methods("GET").Path("/files/{fileID}/batches").Handler(httptransport.NewServer( - e.GetBatchesEndpoint, + getBatchesEndpoint(s), decodeGetBatchesRequest, encodeResponse, options..., )) r.Methods("GET").Path("/files/{fileID}/batches/{batchID}").Handler(httptransport.NewServer( - e.GetBatchEndpoint, + getBatchEndpoint(s), decodeGetBatchRequest, encodeResponse, options..., )) r.Methods("DELETE").Path("/files/{fileID}/batches/{batchID}").Handler(httptransport.NewServer( - e.DeleteBatchEndpoint, + deleteBatchEndpoint(s), decodeDeleteBatchRequest, encodeResponse, options..., @@ -178,143 +172,6 @@ func MakeHTTPHandler(s Service, repo Repository, logger log.Logger) http.Handler return r } -//** FILES ** // -func decodeCreateFileRequest(_ context.Context, request *http.Request) (interface{}, error) { - var r io.Reader - var req createFileRequest - - // Sets default values - req.File = &ach.File{ - Header: ach.NewFileHeader(), - } - - bs, err := ioutil.ReadAll(request.Body) - if err != nil { - return nil, err - } - - h := request.Header.Get("Content-Type") - if strings.Contains(h, "application/json") { - // Read body as ACH file in JSON - f, err := ach.FileFromJson(bs) - if err != nil { - return nil, err - } - req.File = f - } else { - // Attempt parsing body as an ACH File - r = bytes.NewReader(bs) - f, err := ach.NewReader(r).Read() - if err != nil { - return nil, err - } - req.File = &f - } - return req, nil -} - -func decodeGetFileRequest(_ context.Context, r *http.Request) (interface{}, error) { - vars := mux.Vars(r) - id, ok := vars["id"] - if !ok { - return nil, ErrBadRouting - } - return getFileRequest{ID: id}, nil -} - -func decodeDeleteFileRequest(_ context.Context, r *http.Request) (interface{}, error) { - vars := mux.Vars(r) - id, ok := vars["id"] - if !ok { - return nil, ErrBadRouting - } - return deleteFileRequest{ID: id}, nil -} - -func decodeGetFilesRequest(_ context.Context, r *http.Request) (interface{}, error) { - return getFilesRequest{}, nil -} - -func decodeGetFileContentsRequest(_ context.Context, r *http.Request) (interface{}, error) { - vars := mux.Vars(r) - id, ok := vars["id"] - if !ok { - return nil, ErrBadRouting - } - return getFileContentsRequest{ID: id}, nil -} - -func decodeValidateFileRequest(_ context.Context, r *http.Request) (interface{}, error) { - vars := mux.Vars(r) - id, ok := vars["id"] - if !ok { - return nil, ErrBadRouting - } - return validateFileRequest{ID: id}, nil -} - -//** BATCHES **// - -func decodeCreateBatchRequest(_ context.Context, r *http.Request) (interface{}, error) { - var req createBatchRequest - vars := mux.Vars(r) - id, ok := vars["fileID"] - if !ok { - return nil, ErrBadRouting - } - req.FileID = id - req.BatchHeader = *ach.NewBatchHeader() - if e := json.NewDecoder(r.Body).Decode(&req.BatchHeader); e != nil { - return nil, e - } - return req, nil -} - -func decodeGetBatchesRequest(_ context.Context, r *http.Request) (interface{}, error) { - var req getBatchesRequest - vars := mux.Vars(r) - id, ok := vars["fileID"] - if !ok { - return nil, ErrBadRouting - } - req.fileID = id - return req, nil -} - -func decodeGetBatchRequest(_ context.Context, r *http.Request) (interface{}, error) { - var req getBatchRequest - vars := mux.Vars(r) - fileID, ok := vars["fileID"] - if !ok { - return nil, ErrBadRouting - } - batchID, ok := vars["batchID"] - if !ok { - return nil, ErrBadRouting - } - - req.fileID = fileID - req.batchID = batchID - return req, nil -} - -func decodeDeleteBatchRequest(_ context.Context, r *http.Request) (interface{}, error) { - var req deleteBatchRequest - vars := mux.Vars(r) - fileID, ok := vars["fileID"] - if !ok { - return nil, ErrBadRouting - } - batchID, ok := vars["batchID"] - if !ok { - return nil, ErrBadRouting - } - - req.fileID = fileID - req.batchID = batchID - return req, nil -} - // errorer is implemented by all concrete response types that may contain // errors. There are a few well-known values which are used to change the // HTTP response code without needing to trigger an endpoint (transport-level)