Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: separate validation, response and business logic #1301

Open
wants to merge 5 commits into
base: staging
Choose a base branch
from

Conversation

LuccaBitfly
Copy link
Contributor

@LuccaBitfly LuccaBitfly commented Jan 29, 2025

Adds a pattern for splitting the HTTP logic from the business logic in the API handler funcs. Adds a few example test cases. Changes the test workflow to include these tests.

Copy link
Contributor

@sasha-bitfly sasha-bitfly left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LuccaBitfly

Linter job fails:


Check failure on line 100 in backend/pkg/api/handlers/input_validation.go
printf: non-constant format string in call to
github.com/gobitfly/beaconchain/pkg/api/handlers.newBadRequestErr 


Check failure on line 156 in backend/pkg/api/handlers/input_validation.go
unnecessary leading newline (whitespace)

@LuccaBitfly LuccaBitfly force-pushed the BEDS-94/abstract-handle-test branch 10 times, most recently from ee1c378 to 35649cc Compare February 5, 2025 14:23
@LuccaBitfly LuccaBitfly force-pushed the BEDS-94/abstract-handle-test branch from 35649cc to def1b01 Compare February 7, 2025 10:13
@LuccaBitfly LuccaBitfly force-pushed the BEDS-94/abstract-handle-test branch from def1b01 to f58c2e6 Compare February 7, 2025 10:17
@LuccaBitfly LuccaBitfly force-pushed the BEDS-94/abstract-handle-test branch 2 times, most recently from 714ef42 to 500906e Compare February 7, 2025 11:18
Copy link

cloudflare-workers-and-pages bot commented Feb 7, 2025

Deploying beaconchain with  Cloudflare Pages  Cloudflare Pages

Latest commit: 500906e
Status: ✅  Deploy successful!
Preview URL: https://3d82629b.beaconchain.pages.dev
Branch Preview URL: https://beds-94-abstract-handle-test.beaconchain.pages.dev

View logs

Copy link
Contributor

@remoterami remoterami left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I got it right, handlers/public.go can be removed entirely once your suggestion is applied to all functions, right? That would be so great

Comment on lines +63 to +65
type Checker[T any] interface {
Check(params map[string]string, payload io.ReadCloser) (T, error)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imo it's worth re-thinking naming for the interface and method name here, Check(er) is a bit vague. It's only supposed to be used in the context of input validation, right? Maybe InputValidator and Validate() or so

Comment on lines -147 to -149
if contentType := r.Header.Get("Content-Type"); !reJsonContentType.MatchString(contentType) {
v.add("request body", "'Content-Type' header must be 'application/json'")
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't this check be kept somehow? Maybe move it to middleware, like if there is a body present it should be application/json


bodyBytes, err := io.ReadAll(r.Body)
r.Body = io.NopCloser(bytes.NewReader(bodyBytes)) // unconsume body for error logging
func (v *validationError) checkBody(data interface{}, requestBody io.ReadCloser) error { // <- should be checkBody after refactoring
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func (v *validationError) checkBody(data interface{}, requestBody io.ReadCloser) error { // <- should be checkBody after refactoring
func (v *validationError) checkBody(data interface{}, requestBody io.ReadCloser) error {

@@ -560,3 +561,28 @@ func (v *validationError) checkTimestamps(r *http.Request, chartLimits ChartTime
return afterTs, beforeTs
}
}

func (v *validationError) checkDashboardId(id string) interface{} {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks essentially like the same as https://github.com/gobitfly/beaconchain/blob/staging/backend/pkg/api/handlers/handler_service.go#L85-L109 to me, what's the reason for this? Would be cool if it was possible to merge them

"github.com/gobitfly/beaconchain/pkg/api/types"
)

// PublicPostValidatorDashboardGroups godoc
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check: I think doc generation doesn't work anymore since the method name changed

}

func (h *HandlerService) PostValidatorDashboardGroups(ctx context.Context, input inputPostValidatorDashboardGroups) (*types.ApiDataResponse[types.VDBPostCreateGroupData], error) {
dataAccessor := h.getDataAccessor(ctx)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This step will exist in virtually every business logic func, right? Could you think of a clean way to also inject this via handler_service.Handle(), I think that would be cool

Comment on lines +69 to +71
func stringAsBody(s string) io.ReadCloser {
return io.NopCloser(strings.NewReader(s))
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this will be used in other unit test files, too. Maybe such helpers should be placed in a new/existing common file (prob same for handlerTestSetup())

return ctx, NewHandlerService(da, da, nil, false)
}

func TestPostValidatorDashboardGroups(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the split of tests into input validation and business logic: Maybe both could be grouped under one test method which is responsible for the entire api call, and then either use subsubtests or just do input first and business logic after.

What do you think? Collapsing entire units at once could be nice dev qol

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants