Elegant way to check if multiple strings are empty
Asked Answered
M

3

5

How can I check if multiple strings are empty in an elegant way? This is how I currently do it:

//if one required field is empty, close the connection
    if (registerRequest.Email == "") ||
        (registerRequest.PhoneNumber == "")||
        (registerRequest.NachName =="") ||
        (registerRequest.VorName =="") ||
        (registerRequest.Password =="") ||
        (registerRequest.VerificationId ==""){

        //Could not proceed
        w.WriteHeader(UNABLE_TO_PROCEED)
        w.Write([]byte("Unable to register account."))
        return

    }
Mccourt answered 12/1, 2018 at 12:58 Comment(2)
I'd also suggest using http.StatusBadRequest instead of a custom variable/constant UNABLE_TO_PROCEED -- 1. it's standard, so much more readable (anyone reading your code will know what it does), 2. your variable violates two Go idioms: Don't use _ in variable names, and don't use all caps.Jackinthepulpit
An alternative way could be to add a metod for registerRequest to check if any one of the mandatory fields is empty.Inellineloquent
C
12

Note: You may use the solution below if you keep the "is-valid" condition in your handler, and also if you separate your condition into another function or method.

You can create a simple helper function, which has a variadic parameter, and you can call it with any number of string values:

func containsEmpty(ss ...string) bool {
    for _, s := range ss {
        if s == "" {
            return true
        }
    }
    return false
}

Example using it:

if containsEmpty("one", "two", "") {
    fmt.Println("One is empty!")
} else {
    fmt.Println("All is non-empty.")
}

if containsEmpty("one", "two", "three") {
    fmt.Println("One is empty!")
} else {
    fmt.Println("All is non-empty.")
}

Output of the above (try it on the Go Playground):

One is empty!
All is non-empty.

Your example would look like this:

if containsEmpty(registerRequest.Email,
    registerRequest.PhoneNumber,
    registerRequest.NachName,
    registerRequest.VorName,
    registerRequest.Password,
    registerRequest.VerificationId) {

    // One of the listed strings is empty
}

Also registerRequest is a kinda long name, it could be shortened to like r. If you can't or don't want to rename it in the surrounding code and if you want to shorten the condition, you could also do something like this:

If registerRequest is a pointer (or interface), you could also write:

if r := registerRequest; containsEmpty(r.Email,
    r.PhoneNumber,
    r.NachName,
    r.VorName,
    r.Password,
    r.VerificationId) {

    // One of the listed strings is empty
}

Actually you can do this even if registerRequest is not a pointer, but then the struct will be copied. If registerRequest is a struct, then you can take its address to avoid having to copy it like this:

if r := &registerRequest; containsEmpty(r.Email,
    r.PhoneNumber,
    r.NachName,
    r.VorName,
    r.Password,
    r.VerificationId) {

    // One of the listed strings is empty
}
Crepuscule answered 12/1, 2018 at 13:16 Comment(3)
Terrible name hasZero, correct name should be isNotEmpty (talks.golang.org/2014/names.slide#2) and registerRequest should be r, but rename it in whole function do not make alias in if.Shipworm
@Shipworm isNotEmpty would be a good name for a collection to check if its size is greater than 0. hasZero() tells if the list of passed values has a zero value (the value being equal to the zero value of its type). About registerRequest: I agree.Crepuscule
@Shipworm Although I agree that in case of string values, containsEmpty() would be more intuitive. Updated the answer.Crepuscule
C
5

As Mario Santini mentioned in comment, a way to increase testability, encapsulate this logic, and decouple it from your handler method (which judging by the number of fields looks like it is at risk of changing at a different rate than your handler) could be to put this logic in a function:

func validRequest(registerRequest ?) bool {
   return registerRequest.Email == "" ||
        registerRequest.PhoneNumber == "" ||
        registerRequest.NachName == "" ||
        registerRequest.VorName == "" ||
        registerRequest.Password == "" ||
        registerRequest.VerificationId == ""
}

This now supports very focused, table driven tests, that can exercise what it means to be a valid request independent of any method involving writing headers.

It allows you to verify the valid/invalid path of your enclosing function, but to have very focused tests here. It also allows you to change what it means to be a valid request and verify it independent of your enclosing function.

Cabezon answered 12/1, 2018 at 13:18 Comment(0)
W
1

You can use a switch:

switch "" {
case registerRequest.Email,
registerRequest.NachName,
registerRequest.Password,
registerRequest.PhoneNumber,
registerRequest.VerificationId,
registerRequest.VorName:
   w.WriteHeader(UNABLE_TO_PROCEED)
   w.Write([]byte("Unable to register account."))
   return
}

https://golang.org/ref/spec#Switch_statements

W answered 7/6, 2021 at 15:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.