How to upgrade the Go SDK from v1 to v2

This guide will help you navigate through changes included in version 2 of the Account Protect Go SDK for a successful upgrade.

Version 2 is generated from the Account Protect OpenAPI Specification, which changes the client, event, and response types throughout the SDK.

Overview of changes

  • Update the module path from github.com/datadome/fraud-sdk-go-package to github.com/datadome/fraud-sdk-go-package/v2.
  • Replace the Event interface and the Client.Validate and Client.Collect methods with one dedicated type per operation, such as ValidateLogin and CollectCustom.
  • Replace the per-event builders with functional options passed to per-operation constructors, such as NewValidateLogin(account, status, opts...).
  • Validate the payload at construction time and fail on missing required fields, instead of accepting it silently.
  • Replace Validate, ValidateWithRequestMetadata, Collect, and CollectWithRequestMetadata with a PerformOperation(ctx, client, request, requestMetadata) method on each operation, which requires an explicit context.Context.
  • Return a Go error from collect calls, instead of an ErrorResponsePayload with a Status field. Validate calls still fail open and return an allow action.
  • Rename ResponsePayload, SuccessResponsePayload, and ErrorResponsePayload to Response, ResponseLogin, and Error, remove the Status field, and uppercase the ResponseAction constants: Allow becomes ALLOW, Deny becomes DENY, Review becomes REVIEW, and Challenge becomes CHALLENGE.
  • Rename LoginStatus to LoginPayloadStatus, and its Failed and Succeeded constants to LoginPayloadStatusFailed and LoginPayloadStatusSucceeded.
  • Add support for the feedback endpoint with NewFeedback.

Migration steps

Step 1: Upgrade to the latest package version

go get github.com/datadome/fraud-sdk-go-package/v2
go mod tidy

Step 2: Update the client instantiation

Update the import path. The client's package alias and the NewClient signature stay the same:

dd "github.com/datadome/fraud-sdk-go-package/v2"

client, err := dd.NewClient(
    "FRAUD_API_KEY",
    dd.ClientWithEndpoint("account-api.datadome.co"),
    dd.ClientWithTimeout(1500),
)
dd "github.com/datadome/fraud-sdk-go-package"

client, err := dd.NewClient(
    "FRAUD_API_KEY",
    dd.ClientWithEndpoint("account-api.datadome.co"),
    dd.ClientWithTimeout(1500),
)

Step 3: Add the addOpt helper

Every …PayloadWithX functional option now returns an (option, error) pair instead of just an option, because payload validation happens as options are applied. Add the helper below to your code and wrap each option call with it:

// addOpt appends an option to opts. If err is non-nil, the option is skipped and
// the error is logged.
func addOpt[T any](opts []T, opt T, err error) []T {
    if err != nil {
        log.Printf("option error: %v", err)
        return opts
    }
    return append(opts, opt)
}

Step 4: Update event submission and payload construction

Replace client.Validate/client.Collect and the New<Event>Event constructors with the dedicated operation for your event. The table below maps every event to its v2 operations:

Eventv1 constructorv2 validate operationv2 collect operation
LoginNewLoginEventNewValidateLoginNewCollectLogin
RegistrationNewRegistrationEventNewValidateRegistrationNewCollectRegistration
Account updateNewAccountUpdateEventNewValidateAccountUpdateNewCollectAccountUpdate
Password updateNewPasswordUpdateEventNewValidatePasswordUpdateNewCollectPasswordUpdate
Custom eventNewCustomEventNewValidateCustomNewCollectCustom

The example below migrates a login event. Registration, account update, password update, and custom events follow the same pattern.

var opts []dd.LoginPayloadOption
userOpt, err := dd.LoginPayloadWithUser(user)
opts = addOpt(opts, userOpt, err)
authOpt, err := dd.LoginPayloadWithAuthentication(authentication)
opts = addOpt(opts, authOpt, err)
sessionOpt, err := dd.LoginPayloadWithSession(session)
opts = addOpt(opts, sessionOpt, err)

op, err := dd.NewValidateLogin(login, dd.LoginPayloadStatusSucceeded, opts...)
if err != nil {
    log.Printf("error creating validate login operation: %v\n", err)
    http.Error(w, "invalid request", http.StatusBadRequest)
    return
}
validate, err := op.PerformOperation(r.Context(), client, r, nil)
if err != nil {
    log.Printf("error during validation: %v\n", err)
}
if validate.Action == dd.ALLOW {
    w.WriteHeader(http.StatusOK)
    return
}
validate, err := client.Validate(r, dd.NewLoginEvent(
    login,
    dd.Succeeded,
    dd.LoginWithUser(user),
    dd.LoginWithAuthentication(authentication),
    dd.LoginWithSession(session),
))
if err != nil {
    log.Printf("error during validation: %v\n", err)
}
if validate.Action == dd.Allow {
    w.WriteHeader(http.StatusOK)
    return
}

For a failed login, PerformOperation on a collect operation requires a context.Context and returns only an error:

op, err := dd.NewCollectLogin(login, dd.LoginPayloadStatusFailed)
if err != nil {
    log.Printf("error creating collect login operation: %v\n", err)
} else if err := op.PerformOperation(r.Context(), client, r, nil); err != nil {
    log.Printf("error during collection: %v\n", err)
}
_, err := client.Collect(r, dd.NewLoginEvent(login, dd.Failed))
if err != nil {
    log.Printf("error during collection: %v\n", err)
}
🚧

Constructor argument order changed for two events

  • NewValidatePasswordUpdate(account, reason, status, user, opts...) takes user as its fourth argument, while NewPasswordUpdateEvent(account, user, reason, status, opts...) took it as its second.
  • NewValidateCustom(eventName, opts...) no longer takes account as a positional argument. Set it with the dd.CustomActionPayloadWithAccount(account) option instead.

Step 5: Update your models

This table maps the renamed types:

v1v2
dd.Addressdd.UserAllOfAddress
dd.Userdd.LoginPayloadAllOfUser, dd.RegistrationPayloadAllOfUser, dd.AccountUpdatePayloadAllOfUser, or dd.PasswordUpdatePayloadAllOfUser, depending on the event
dd.CustomEventUserdd.CustomActionPayloadAnyOf1AllOfUser
dd.Authenticationdd.LoginPayloadAllOfAuthentication, dd.RegistrationPayloadAllOfAuthentication, dd.AccountUpdatePayloadAllOfAuthentication, or dd.PasswordUpdatePayloadAllOfAuthentication, depending on the event

And the renamed or retyped fields on the user model:

v1v2
ID stringId *string for login, account update, and custom events; Id string (still required) for registration and password update
ExternalURLs *[]stringExternalUrls []string
PictureURLs *[]stringPictureUrls []string
Title *string (for example, "mr")Title dd.UserTitle (for example, dd.MR)

Step 6: Update your response and error handling

  • Replace dd.Allow, dd.Deny, dd.Review, and dd.Challenge with the uppercase dd.ALLOW, dd.DENY, dd.REVIEW, and dd.CHALLENGE constants.
  • Replace LoginStatus.Succeeded/.Failed with dd.LoginPayloadStatusSucceeded/dd.LoginPayloadStatusFailed. Each event has its own status type, following the same naming pattern.
  • Stop checking the response's Status field: it no longer exists. Validate operations still fail open and return an allow action on error; collect operations now return a Go error, including a new HTTPError type for API error responses.

Reference

Response actions

v1v2
dd.Allowdd.ALLOW
dd.Denydd.DENY
dd.Reviewdd.REVIEW
dd.Challengedd.CHALLENGE

Response types

v1v2
ResponsePayloadResponse
SuccessResponsePayloadResponseLogin
ErrorResponsePayloadError

Authentication constants

v1v2
dd.Passworddd.AuthenticationModePassword
dd.Googledd.AuthenticationSocialProviderGoogle
dd.Socialdd.AuthenticationTypeSocial

Did this page help you?