Repository: Nerzal/gocloak
Pull request #66 (2019-05-24 19:36:21)

Refactoring
1. Return list of pointers to the objects instead of pointer to a list of the objects
Change return types of several function to return `[]*<type>` instead of `*[]<type>`.
Fix unit tests.
Also the `CreateUser` function now returns `string` instead of `*string`.

2. Using Resty `SetError` method to get the Keycloak's error message
Add a hellep `IsObjectAlreadyExists` to verify that an error is ObjectAlreadyExists

3. Remove omitempty for all bool parameters

4. Using v3 suffix to support go.mod semantic versions
Update README.md with an information how to install and use versions 2 and 3

4. Fix bump_version tool
In case of increasing major version the minor and patch versions keeps the old values,
and the same thing happens with increasing minor version, the patch version keeps the old value.

codecov[bot]: # [Codecov](https://codecov.io/gh/Nerzal/gocloak/pull/66?src=pr&el=h1) Report
> Merging [#66](https://codecov.io/gh/Nerzal/gocloak/pull/66?src=pr&el=desc) into [master](https://codecov.io/gh/Nerzal/gocloak/commit/fb4aaeaf652bedc27b1f7aaa1d10045adf848634?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `91.11%`.

[![Impacted file tree graph](https://codecov.io/gh/Nerzal/gocloak/pull/66/graphs/tree.svg?width=650&token=gB52LSVNIV&height=150&src=pr)](https://codecov.io/gh/Nerzal/gocloak/pull/66?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##           master      #66   +/-   ##
=======================================
  Coverage   76.51%   76.51%           
=======================================
  Files           3        3           
  Lines         562      562           
=======================================
  Hits          430      430           
  Misses         90       90           
  Partials       42       42
```


| [Impacted Files](https://codecov.io/gh/Nerzal/gocloak/pull/66?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [client.go](https://codecov.io/gh/Nerzal/gocloak/pull/66/diff?src=pr&el=tree#diff-Y2xpZW50Lmdv) | `76.95% <91.11%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/Nerzal/gocloak/pull/66?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Nerzal/gocloak/pull/66?src=pr&el=footer). Last update [fb4aaea...a15efb4](https://codecov.io/gh/Nerzal/gocloak/pull/66?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

SVilgelm: I think It's ready to be merged, but lets merge other PR before this and make a branch v2

Patch:
diff --git a/README.md b/README.md
index 42fe92b..931c6bb 100644
--- a/README.md
+++ b/README.md
@@ -34,6 +34,25 @@ https://gopkg.in/nerzal/gocloak.v1
 
 ## Usage
 
+### Importing
+
+Since the version 3 you need to import the gocloak library using v3 suffix:
+
+```go
+	import "github.com/Nerzal/gocloak/v3"
+```
+
+#### Version 2:
+
+```go
+	go get gopkg.in/nerzal/gocloak@v2.1.0
+```
+
+```go
+	import "github.com/Nerzal/gocloak"
+```
+
+
 ### Create New User
 ```go
 	client := gocloak.NewClient("https://mycool.keycloak.instance")
@@ -96,7 +115,7 @@ type GoCloak interface {
 	SetPassword(token string, userID string, realm string, password string, temporary bool) error
 	ExecuteActionsEmail(token string, realm string, params ExecuteActionsEmail) error
 
-	CreateUser(token string, realm string, user User) (*string, error)
+	CreateUser(token string, realm string, user User) (string, error)
 	CreateGroup(accessToken string, realm string, group Group) error
 	CreateClientRole(accessToken string, realm string, clientID string, role Role) error
 	CreateClient(accessToken string, realm string, clientID Client) error
@@ -121,26 +140,26 @@ type GoCloak interface {
 	GetKeyStoreConfig(accessToken string, realm string) (*KeyStoreConfig, error)
 	GetUserByID(accessToken string, realm string, userID string) (*User, error)
 	GetUserCount(accessToken string, realm string) (int, error)
-	GetUsers(accessToken string, realm string, params GetUsersParams) (*[]User, error)
-	GetUserGroups(accessToken string, realm string, userID string) (*[]UserGroup, error)
-	GetComponents(accessToken string, realm string) (*[]Component, error)
-	GetGroups(accessToken string, realm string, params GetGroupsParams) (*[]Group, error)
+	GetUsers(accessToken string, realm string, params GetUsersParams) ([]*User, error)
+	GetUserGroups(accessToken string, realm string, userID string) ([]*UserGroup, error)
+	GetComponents(accessToken string, realm string) ([]*Component, error)
+	GetGroups(accessToken string, realm string, params GetGroupsParams) ([]*Group, error)
 	GetGroup(accessToken string, realm, groupID string) (*Group, error)
 	GetRoleMappingByGroupID(accessToken string, realm string, groupID string) (*MappingsRepresentation, error)
 	GetRoleMappingByUserID(accessToken string, realm string, userID string) (*MappingsRepresentation, error)
-	GetClientRoles(accessToken string, realm string, clientID string) (*[]Role, error)
+	GetClientRoles(accessToken string, realm string, clientID string) ([]*Role, error)
 	GetClientRole(token string, realm string, clientID string, roleName string) (*Role, error)
-	GetClients(accessToken string, realm string, params GetClientsParams) (*[]Client, error)
-	GetUsersByRoleName(token string, realm string, roleName string) (*[]User, error)
+	GetClients(accessToken string, realm string, params GetClientsParams) ([]*Client, error)
+	GetUsersByRoleName(token string, realm string, roleName string) ([]*User, error)
 	UserAttributeContains(attributes map[string][]string, attribute string, value string) bool
 
 	// *** Realm Roles ***
 
 	CreateRealmRole(token string, realm string, role Role) error
 	GetRealmRole(token string, realm string, roleName string) (*Role, error)
-	GetRealmRoles(accessToken string, realm string) (*[]Role, error)
-	GetRealmRolesByUserID(accessToken string, realm string, userID string) (*[]Role, error)
-	GetRealmRolesByGroupID(accessToken string, realm string, groupID string) (*[]Role, error)
+	GetRealmRoles(accessToken string, realm string) ([]*Role, error)
+	GetRealmRolesByUserID(accessToken string, realm string, userID string) ([]*Role, error)
+	GetRealmRolesByGroupID(accessToken string, realm string, groupID string) ([]*Role, error)
 	UpdateRealmRole(token string, realm string, roleName string, role Role) error
 	DeleteRealmRole(token string, realm string, roleName string) error
 	AddRealmRoleToUser(token string, realm string, userID string, roles []Role) error
@@ -154,10 +173,10 @@ type GoCloak interface {
 	CreateRealm(token string, realm RealmRepresentation) error
 	DeleteRealm(token string, realm string) error
 
-	GetClientUserSessions(token, realm, clientID string) (*[]UserSessionRepresentation, error)
-	GetClientOfflineSessions(token, realm, clientID string) (*[]UserSessionRepresentation, error)
-	GetUserSessions(token, realm, userID string) (*[]UserSessionRepresentation, error)
-	GetUserOfflineSessionsForClient(token, realm, userID, clientID string) (*[]UserSessionRepresentation, error)
+	GetClientUserSessions(token, realm, clientID string) ([]*UserSessionRepresentation, error)
+	GetClientOfflineSessions(token, realm, clientID string) ([]*UserSessionRepresentation, error)
+	GetUserSessions(token, realm, userID string) ([]*UserSessionRepresentation, error)
+	GetUserOfflineSessionsForClient(token, realm, userID, clientID string) ([]*UserSessionRepresentation, error)
 }
 ```
 
diff --git a/client.go b/client.go
index ec5aa52..0f3cadd 100644
--- a/client.go
+++ b/client.go
@@ -3,10 +3,11 @@ package gocloak
 import (
 	"encoding/base64"
 	"errors"
+	"fmt"
 	"strings"
 	"time"
 
-	"github.com/Nerzal/gocloak/pkg/jwx"
+	"github.com/Nerzal/gocloak/v3/pkg/jwx"
 	"github.com/dgrijalva/jwt-go"
 	"gopkg.in/resty.v1"
 )
@@ -35,14 +36,19 @@ func makeURL(path ...string) string {
 	return strings.Join(path, urlSeparator)
 }
 
+func (client *gocloak) getRequest() *resty.Request {
+	var err HTTPErrorResponse
+	return client.restyClient.R().SetError(&err)
+}
+
 func (client *gocloak) getRequestWithBearerAuth(token string) *resty.Request {
-	return client.restyClient.R().
+	return client.getRequest().
 		SetAuthToken(token).
 		SetHeader("Content-Type", "application/json")
 }
 
 func (client *gocloak) getRequestWithBasicAuth(clientID string, clientSecret string) *resty.Request {
-	req := client.restyClient.R().
+	req := client.getRequest().
 		SetHeader("Content-Type", "application/x-www-form-urlencoded")
 	// Public client doesn't require Basic Auth
 	if len(clientID) > 0 && len(clientSecret) > 0 {
@@ -58,10 +64,17 @@ func checkForError(resp *resty.Response, err error) error {
 	}
 
 	if resp.IsError() {
+		var msg string
+		e := resp.Error().(*HTTPErrorResponse)
+		if len(e.ErrorMessage) > 0 {
+			msg = fmt.Sprintf("%s: %s", resp.Status(), e.ErrorMessage)
+		} else {
+			msg = resp.Status()
+		}
 		if resp.StatusCode() == 409 {
-			return &ObjectAlreadyExists{}
+			return &ObjectAlreadyExists{ErrorMessage: msg}
 		}
-		return errors.New(resp.Status())
+		return errors.New(msg)
 	}
 	return nil
 }
@@ -136,7 +149,7 @@ func (client *gocloak) GetUserInfo(accessToken string, realm string) (*UserInfo,
 
 func (client *gocloak) getNewCerts(realm string) (*CertResponse, error) {
 	var result CertResponse
-	resp, err := client.restyClient.R().
+	resp, err := client.getRequest().
 		SetResult(&result).
 		Get(client.getRealmURL(realm, openIDConnect, "certs"))
 
@@ -168,7 +181,7 @@ func (client *gocloak) GetCerts(realm string) (*CertResponse, error) {
 // GetIssuer gets the issuer of the given realm
 func (client *gocloak) GetIssuer(realm string) (*IssuerResponse, error) {
 	var result IssuerResponse
-	resp, err := client.restyClient.R().
+	resp, err := client.getRequest().
 		SetResult(&result).
 		Get(client.getRealmURL(realm))
 
@@ -239,7 +252,7 @@ func (client *gocloak) GetToken(realm string, options TokenOptions) (*JWT, error
 	if len(options.ClientSecret) > 0 {
 		req = client.getRequestWithBasicAuth(options.ClientID, options.ClientSecret)
 	} else {
-		req = client.restyClient.R()
+		req = client.getRequest()
 	}
 	resp, err := req.SetFormData(options.FormData()).
 		SetResult(&token).
@@ -487,8 +500,8 @@ func (client *gocloak) GetClientSecret(token string, realm string, clientID stri
 }
 
 // GetClientOfflineSessions returns offline sessions associated with the client
-func (client *gocloak) GetClientOfflineSessions(token, realm, clientID string) (*[]UserSessionRepresentation, error) {
-	var res []UserSessionRepresentation
+func (client *gocloak) GetClientOfflineSessions(token, realm, clientID string) ([]*UserSessionRepresentation, error) {
+	var res []*UserSessionRepresentation
 	resp, err := client.getRequestWithBearerAuth(token).
 		SetResult(&res).
 		Get(client.getAdminRealmURL(realm, "clients", clientID, "offline-sessions"))
@@ -496,12 +509,12 @@ func (client *gocloak) GetClientOfflineSessions(token, realm, clientID string) (
 	if err := checkForError(resp, err); err != nil {
 		return nil, err
 	}
-	return &res, nil
+	return res, nil
 }
 
 // GetClientUserSessions returns user sessions associated with the client
-func (client *gocloak) GetClientUserSessions(token, realm, clientID string) (*[]UserSessionRepresentation, error) {
-	var res []UserSessionRepresentation
+func (client *gocloak) GetClientUserSessions(token, realm, clientID string) ([]*UserSessionRepresentation, error) {
+	var res []*UserSessionRepresentation
 	resp, err := client.getRequestWithBearerAuth(token).
 		SetResult(&res).
 		Get(client.getAdminRealmURL(realm, "clients", clientID, "user-sessions"))
@@ -509,7 +522,7 @@ func (client *gocloak) GetClientUserSessions(token, realm, clientID string) (*[]
 	if err := checkForError(resp, err); err != nil {
 		return nil, err
 	}
-	return &res, nil
+	return res, nil
 }
 
 // GetKeyStoreConfig get keystoreconfig of the realm
@@ -527,8 +540,8 @@ func (client *gocloak) GetKeyStoreConfig(token string, realm string) (*KeyStoreC
 }
 
 // GetComponents get all components in realm
-func (client *gocloak) GetComponents(token string, realm string) (*[]Component, error) {
-	var result []Component
+func (client *gocloak) GetComponents(token string, realm string) ([]*Component, error) {
+	var result []*Component
 	resp, err := client.getRequestWithBearerAuth(token).
 		SetResult(&result).
 		Get(client.getAdminRealmURL(realm, "components"))
@@ -537,7 +550,7 @@ func (client *gocloak) GetComponents(token string, realm string) (*[]Component,
 		return nil, err
 	}
 
-	return &result, nil
+	return result, nil
 }
 
 func (client *gocloak) getRoleMappings(token string, realm string, path string, objectID string) (*MappingsRepresentation, error) {
@@ -578,8 +591,8 @@ func (client *gocloak) GetGroup(token string, realm string, groupID string) (*Gr
 }
 
 // GetGroups get all groups in realm
-func (client *gocloak) GetGroups(token string, realm string, params GetGroupsParams) (*[]Group, error) {
-	var result []Group
+func (client *gocloak) GetGroups(token string, realm string, params GetGroupsParams) ([]*Group, error) {
+	var result []*Group
 	queryParams, err := GetQueryParams(params)
 	if err != nil {
 		return nil, err
@@ -594,12 +607,12 @@ func (client *gocloak) GetGroups(token string, realm string, params GetGroupsPar
 		return nil, err
 	}
 
-	return &result, nil
+	return result, nil
 }
 
 // GetClientRoles get all roles for the given client in realm
-func (client *gocloak) GetClientRoles(token string, realm string, clientID string) (*[]Role, error) {
-	var result []Role
+func (client *gocloak) GetClientRoles(token string, realm string, clientID string) ([]*Role, error) {
+	var result []*Role
 	resp, err := client.getRequestWithBearerAuth(token).
 		SetResult(&result).
 		Get(client.getAdminRealmURL(realm, "clients", clientID, "roles"))
@@ -608,7 +621,7 @@ func (client *gocloak) GetClientRoles(token string, realm string, clientID strin
 		return nil, err
 	}
 
-	return &result, nil
+	return result, nil
 }
 
 // GetClientRole get a role for the given client in a realm by role name
@@ -626,8 +639,8 @@ func (client *gocloak) GetClientRole(token string, realm string, clientID string
 }
 
 // GetClients gets all clients in realm
-func (client *gocloak) GetClients(token string, realm string, params GetClientsParams) (*[]Client, error) {
-	var result []Client
+func (client *gocloak) GetClients(token string, realm string, params GetClientsParams) ([]*Client, error) {
+	var result []*Client
 	queryParams, err := GetQueryParams(params)
 	if err != nil {
 		return nil, err
@@ -641,7 +654,7 @@ func (client *gocloak) GetClients(token string, realm string, params GetClientsP
 		return nil, err
 	}
 
-	return &result, nil
+	return result, nil
 }
 
 // UserAttributeContains checks if the given attribute value is set
@@ -684,8 +697,8 @@ func (client *gocloak) GetRealmRole(token string, realm string, roleName string)
 }
 
 // GetRealmRoles get all roles of the given realm.
-func (client *gocloak) GetRealmRoles(token string, realm string) (*[]Role, error) {
-	var result []Role
+func (client *gocloak) GetRealmRoles(token string, realm string) ([]*Role, error) {
+	var result []*Role
 	resp, err := client.getRequestWithBearerAuth(token).
 		SetResult(&result).
 		Get(client.getAdminRealmURL(realm, "roles"))
@@ -694,12 +707,12 @@ func (client *gocloak) GetRealmRoles(token string, realm string) (*[]Role, error
 		return nil, err
 	}
 
-	return &result, nil
+	return result, nil
 }
 
 // GetRealmRolesByUserID returns all roles assigned to the given user
-func (client *gocloak) GetRealmRolesByUserID(token string, realm string, userID string) (*[]Role, error) {
-	var result []Role
+func (client *gocloak) GetRealmRolesByUserID(token string, realm string, userID string) ([]*Role, error) {
+	var result []*Role
 	resp, err := client.getRequestWithBearerAuth(token).
 		SetResult(&result).
 		Get(client.getAdminRealmURL(realm, "users", userID, "role-mappings", "realm"))
@@ -708,12 +721,12 @@ func (client *gocloak) GetRealmRolesByUserID(token string, realm string, userID
 		return nil, err
 	}
 
-	return &result, nil
+	return result, nil
 }
 
 // GetRealmRolesByGroupID returns all roles assigned to the given group
-func (client *gocloak) GetRealmRolesByGroupID(token string, realm string, groupID string) (*[]Role, error) {
-	var result []Role
+func (client *gocloak) GetRealmRolesByGroupID(token string, realm string, groupID string) ([]*Role, error) {
+	var result []*Role
 	resp, err := client.getRequestWithBearerAuth(token).
 		Get(client.getAdminRealmURL(realm, "groups", groupID, "role-mappings", "realm"))
 
@@ -721,7 +734,7 @@ func (client *gocloak) GetRealmRolesByGroupID(token string, realm string, groupI
 		return nil, err
 	}
 
-	return &result, nil
+	return result, nil
 }
 
 // UpdateRealmRole updates a role in a realm
@@ -814,20 +827,20 @@ func (client *gocloak) DeleteRealm(token string, realm string) error {
 // -----
 
 // CreateUser creates the given user in the given realm and returns it's userID
-func (client *gocloak) CreateUser(token string, realm string, user User) (*string, error) {
+func (client *gocloak) CreateUser(token string, realm string, user User) (string, error) {
 	resp, err := client.getRequestWithBearerAuth(token).
 		SetBody(user).
 		Post(client.getAdminRealmURL(realm, "users"))
 
 	if err := checkForError(resp, err); err != nil {
-		return nil, err
+		return "", err
 	}
 
 	userPath := resp.Header().Get("Location")
 	splittedPath := strings.Split(userPath, urlSeparator)
 	userID := splittedPath[len(splittedPath)-1]
 
-	return &userID, nil
+	return userID, nil
 }
 
 // DeleteUser delete a given user
@@ -871,8 +884,8 @@ func (client *gocloak) GetUserCount(token string, realm string) (int, error) {
 }
 
 // GetUserGroups get all groups for user
-func (client *gocloak) GetUserGroups(token string, realm string, userID string) (*[]UserGroup, error) {
-	var result []UserGroup
+func (client *gocloak) GetUserGroups(token string, realm string, userID string) ([]*UserGroup, error) {
+	var result []*UserGroup
 	resp, err := client.getRequestWithBearerAuth(token).
 		SetResult(&result).
 		Get(client.getAdminRealmURL(realm, "users", userID, "groups"))
@@ -881,12 +894,12 @@ func (client *gocloak) GetUserGroups(token string, realm string, userID string)
 		return nil, err
 	}
 
-	return &result, nil
+	return result, nil
 }
 
 // GetUsers get all users in realm
-func (client *gocloak) GetUsers(token string, realm string, params GetUsersParams) (*[]User, error) {
-	var result []User
+func (client *gocloak) GetUsers(token string, realm string, params GetUsersParams) ([]*User, error) {
+	var result []*User
 	queryParams, err := GetQueryParams(params)
 	if err != nil {
 		return nil, err
@@ -901,12 +914,12 @@ func (client *gocloak) GetUsers(token string, realm string, params GetUsersParam
 		return nil, err
 	}
 
-	return &result, nil
+	return result, nil
 }
 
 // GetUsersByRoleName returns all users have a given role
-func (client *gocloak) GetUsersByRoleName(token string, realm string, roleName string) (*[]User, error) {
-	var result []User
+func (client *gocloak) GetUsersByRoleName(token string, realm string, roleName string) ([]*User, error) {
+	var result []*User
 	resp, err := client.getRequestWithBearerAuth(token).
 		SetResult(&result).
 		Get(client.getAdminRealmURL(realm, "roles", roleName, "users"))
@@ -915,7 +928,7 @@ func (client *gocloak) GetUsersByRoleName(token string, realm string, roleName s
 		return nil, err
 	}
 
-	return &result, nil
+	return result, nil
 }
 
 // SetPassword sets a new password for the user with the given id. Needs elevated privileges
@@ -954,8 +967,8 @@ func (client *gocloak) DeleteUserFromGroup(token string, realm string, userID st
 }
 
 // GetUserSessions returns user sessions associated with the user
-func (client *gocloak) GetUserSessions(token, realm, userID string) (*[]UserSessionRepresentation, error) {
-	var res []UserSessionRepresentation
+func (client *gocloak) GetUserSessions(token, realm, userID string) ([]*UserSessionRepresentation, error) {
+	var res []*UserSessionRepresentation
 	resp, err := client.getRequestWithBearerAuth(token).
 		SetResult(&res).
 		Get(client.getAdminRealmURL(realm, "users", userID, "sessions"))
@@ -963,12 +976,12 @@ func (client *gocloak) GetUserSessions(token, realm, userID string) (*[]UserSess
 	if err := checkForError(resp, err); err != nil {
 		return nil, err
 	}
-	return &res, nil
+	return res, nil
 }
 
 // GetUserOfflineSessionsForClient returns offline sessions associated with the user and client
-func (client *gocloak) GetUserOfflineSessionsForClient(token, realm, userID, clientID string) (*[]UserSessionRepresentation, error) {
-	var res []UserSessionRepresentation
+func (client *gocloak) GetUserOfflineSessionsForClient(token, realm, userID, clientID string) ([]*UserSessionRepresentation, error) {
+	var res []*UserSessionRepresentation
 	resp, err := client.getRequestWithBearerAuth(token).
 		SetResult(&res).
 		Get(client.getAdminRealmURL(realm, "users", userID, "offline-sessions", clientID))
@@ -976,5 +989,5 @@ func (client *gocloak) GetUserOfflineSessionsForClient(token, realm, userID, cli
 	if err := checkForError(resp, err); err != nil {
 		return nil, err
 	}
-	return &res, nil
+	return res, nil
 }
diff --git a/errors.go b/errors.go
index 2c9d867..6250a2c 100644
--- a/errors.go
+++ b/errors.go
@@ -1,8 +1,21 @@
 package gocloak
 
 // ObjectAlreadyExists is used when keycloak answers with 409
-type ObjectAlreadyExists struct{}
+type ObjectAlreadyExists struct {
+	ErrorMessage string
+}
+
+func (e *ObjectAlreadyExists) Error() string {
+	return e.ErrorMessage
+}
+
+// IsObjectAlreadyExists is a helper to verify tht the err is ObjectAlreadyExists
+func IsObjectAlreadyExists(err error) bool {
+	_, ok := err.(*ObjectAlreadyExists)
+	return ok
+}
 
-func (o *ObjectAlreadyExists) Error() string {
-	return "Conflict: Object already exists"
+// HTTPErrorResponse is a model of an error response
+type HTTPErrorResponse struct {
+	ErrorMessage string `json:"errorMessage,omitempty"`
 }
diff --git a/go.mod b/go.mod
index 36ed81d..0b4bf35 100644
--- a/go.mod
+++ b/go.mod
@@ -1,4 +1,4 @@
-module github.com/Nerzal/gocloak
+module github.com/Nerzal/gocloak/v3
 
 require (
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
diff --git a/gocloak.go b/gocloak.go
index eada3a2..4d34104 100644
--- a/gocloak.go
+++ b/gocloak.go
@@ -80,9 +80,9 @@ type GoCloak interface {
 	// GetKeyStoreConfig gets the keyStoreConfig
 	GetKeyStoreConfig(accessToken string, realm string) (*KeyStoreConfig, error)
 	// GetComponents gets components of the given realm
-	GetComponents(accessToken string, realm string) (*[]Component, error)
+	GetComponents(accessToken string, realm string) ([]*Component, error)
 	// GetGroups gets all groups of the given realm
-	GetGroups(accessToken string, realm string, params GetGroupsParams) (*[]Group, error)
+	GetGroups(accessToken string, realm string, params GetGroupsParams) ([]*Group, error)
 	// GetGroup gets the given group
 	GetGroup(accessToken string, realm, groupID string) (*Group, error)
 	// GetRoleMappingByGroupID gets the rolemapping for the given group id
@@ -90,15 +90,15 @@ type GoCloak interface {
 	// GetRoleMappingByUserID gets the rolemapping for the given user id
 	GetRoleMappingByUserID(accessToken string, realm string, userID string) (*MappingsRepresentation, error)
 	// GetClientRoles gets roles for the given client
-	GetClientRoles(accessToken string, realm string, clientID string) (*[]Role, error)
+	GetClientRoles(accessToken string, realm string, clientID string) ([]*Role, error)
 	// GetClientRole get a role for the given client in a realm by role name
 	GetClientRole(token string, realm string, clientID string, roleName string) (*Role, error)
 	// GetClients gets the clients in the realm
-	GetClients(accessToken string, realm string, params GetClientsParams) (*[]Client, error)
+	GetClients(accessToken string, realm string, params GetClientsParams) ([]*Client, error)
 	// GetClientOfflineSessions returns offline sessions associated with the client
-	GetClientOfflineSessions(token, realm, clientID string) (*[]UserSessionRepresentation, error)
+	GetClientOfflineSessions(token, realm, clientID string) ([]*UserSessionRepresentation, error)
 	// GetClientUserSessions returns user sessions associated with the client
-	GetClientUserSessions(token, realm, clientID string) (*[]UserSessionRepresentation, error)
+	GetClientUserSessions(token, realm, clientID string) ([]*UserSessionRepresentation, error)
 
 	// UserAttributeContains checks if the given attribute has the given value
 	UserAttributeContains(attributes map[string][]string, attribute string, value string) bool
@@ -110,11 +110,11 @@ type GoCloak interface {
 	// GetRealmRole returns a role from a realm by role's name
 	GetRealmRole(token string, realm string, roleName string) (*Role, error)
 	// GetRealmRoles get all roles of the given realm. It's an alias for the GetRoles function
-	GetRealmRoles(accessToken string, realm string) (*[]Role, error)
+	GetRealmRoles(accessToken string, realm string) ([]*Role, error)
 	// GetRealmRolesByUserID returns all roles assigned to the given user
-	GetRealmRolesByUserID(accessToken string, realm string, userID string) (*[]Role, error)
+	GetRealmRolesByUserID(accessToken string, realm string, userID string) ([]*Role, error)
 	// GetRealmRolesByGroupID returns all roles assigned to the given group
-	GetRealmRolesByGroupID(accessToken string, realm string, groupID string) (*[]Role, error)
+	GetRealmRolesByGroupID(accessToken string, realm string, groupID string) ([]*Role, error)
 	// UpdateRealmRole updates a role in a realm
 	UpdateRealmRole(token string, realm string, roleName string, role Role) error
 	// DeleteRealmRole deletes a role in a realm by role's name
@@ -139,7 +139,7 @@ type GoCloak interface {
 
 	// *** Users ***
 	// CreateUser creates a new user
-	CreateUser(token string, realm string, user User) (*string, error)
+	CreateUser(token string, realm string, user User) (string, error)
 	// DeleteUser deletes the given user
 	DeleteUser(accessToken string, realm, userID string) error
 	// GetUserByID gets the user with the given id
@@ -147,11 +147,11 @@ type GoCloak interface {
 	// GetUser count returns the userCount of the given realm
 	GetUserCount(accessToken string, realm string) (int, error)
 	// GetUsers gets all users of the given realm
-	GetUsers(accessToken string, realm string, params GetUsersParams) (*[]User, error)
+	GetUsers(accessToken string, realm string, params GetUsersParams) ([]*User, error)
 	// GetUserGroups gets the groups of the given user
-	GetUserGroups(accessToken string, realm string, userID string) (*[]UserGroup, error)
+	GetUserGroups(accessToken string, realm string, userID string) ([]*UserGroup, error)
 	// GetUsersByRoleName returns all users have a given role
-	GetUsersByRoleName(token string, realm string, roleName string) (*[]User, error)
+	GetUsersByRoleName(token string, realm string, roleName string) ([]*User, error)
 	// SetPassword sets a new password for the user with the given id. Needs elevated privileges
 	SetPassword(token string, userID string, realm string, password string, temporary bool) error
 	// UpdateUser updates the given user
@@ -161,7 +161,7 @@ type GoCloak interface {
 	// DeleteUserFromGroup deletes given user from given group
 	DeleteUserFromGroup(token string, realm string, userID string, groupID string) error
 	// GetUserSessions returns user sessions associated with the user
-	GetUserSessions(token, realm, userID string) (*[]UserSessionRepresentation, error)
+	GetUserSessions(token, realm, userID string) ([]*UserSessionRepresentation, error)
 	// GetUserOfflineSessionsForClient returns offline sessions associated with the user and client
-	GetUserOfflineSessionsForClient(token, realm, userID, clientID string) (*[]UserSessionRepresentation, error)
+	GetUserOfflineSessionsForClient(token, realm, userID, clientID string) ([]*UserSessionRepresentation, error)
 }
diff --git a/models.go b/models.go
index 1effab8..da5d187 100644
--- a/models.go
+++ b/models.go
@@ -66,7 +66,7 @@ type RetrospecTokenResult struct {
 	Nbf         int               `json:"nbf,omitempty"`
 	Iat         int               `json:"iat,omitempty"`
 	Aud         string            `json:"aud,omitempty"`
-	Active      bool              `json:"active,omitempty"`
+	Active      bool              `json:"active"`
 	AuthTime    int               `json:"auth_time,omitempty"`
 	Jti         string            `json:"jti,omitempty"`
 	Type        string            `json:"typ,omitempty"`
@@ -77,9 +77,9 @@ type User struct {
 	ID                         string              `json:"id,omitempty"`
 	CreatedTimestamp           int64               `json:"createdTimestamp,omitempty"`
 	Username                   string              `json:"username,omitempty"`
-	Enabled                    bool                `json:"enabled,omitempty"`
-	Totp                       bool                `json:"totp,omitempty"`
-	EmailVerified              bool                `json:"emailVerified,omitempty"`
+	Enabled                    bool                `json:"enabled"`
+	Totp                       bool                `json:"totp"`
+	EmailVerified              bool                `json:"emailVerified"`
 	FirstName                  string              `json:"firstName,omitempty"`
 	LastName                   string              `json:"lastName,omitempty"`
 	Email                      string              `json:"email,omitempty"`
@@ -87,13 +87,13 @@ type User struct {
 	Attributes                 map[string][]string `json:"attributes,omitempty"`
 	DisableableCredentialTypes []interface{}       `json:"disableableCredentialTypes,omitempty"`
 	RequiredActions            []interface{}       `json:"requiredActions,omitempty"`
-	Access                     map[string]bool     `json:"access,omitempty"`
+	Access                     map[string]bool     `json:"access"`
 }
 
 // SetPasswordRequest sets a new password
 type SetPasswordRequest struct {
 	Type      string `json:"type,omitempty"`
-	Temporary bool   `json:"temporary,omitempty"`
+	Temporary bool   `json:"temporary"`
 	Password  string `json:"value,omitempty"`
 }
 
@@ -147,11 +147,11 @@ type Attributes struct {
 
 // Access represents access
 type Access struct {
-	ManageGroupMembership bool `json:"manageGroupMembership,omitempty"`
-	View                  bool `json:"view,omitempty"`
-	MapRoles              bool `json:"mapRoles,omitempty"`
-	Impersonate           bool `json:"impersonate,omitempty"`
-	Manage                bool `json:"manage,omitempty"`
+	ManageGroupMembership bool `json:"manageGroupMembership"`
+	View                  bool `json:"view"`
+	MapRoles              bool `json:"mapRoles"`
+	Impersonate           bool `json:"impersonate"`
+	Manage                bool `json:"manage"`
 }
 
 // UserGroup is a UserGroup
@@ -163,7 +163,7 @@ type UserGroup struct {
 
 // GetUsersParams represents the optional parameters for getting users
 type GetUsersParams struct {
-	BriefRepresentation *bool  `json:"briefRepresentation,string,omitempty"`
+	BriefRepresentation bool   `json:"briefRepresentation,string"`
 	Email               string `json:"email,omitempty"`
 	First               int    `json:"first,string,omitempty"`
 	FirstName           string `json:"firstName,omitempty"`
@@ -201,9 +201,9 @@ type GetGroupsParams struct {
 type Role struct {
 	ID                 string              `json:"id,omitempty"`
 	Name               string              `json:"name,omitempty"`
-	ScopeParamRequired bool                `json:"scopeParamRequired,omitempty"`
-	Composite          bool                `json:"composite,omitempty"`
-	ClientRole         bool                `json:"clientRole,omitempty"`
+	ScopeParamRequired bool                `json:"scopeParamRequired"`
+	Composite          bool                `json:"composite"`
+	ClientRole         bool                `json:"clientRole"`
 	ContainerID        string              `json:"containerId,omitempty"`
 	Description        string              `json:"description,omitempty"`
 	Attributes         map[string][]string `json:"attributes,omitempty"`
@@ -245,7 +245,7 @@ type ProtocolMappers struct {
 	Name                  string                `json:"name,omitempty"`
 	Protocol              string                `json:"protocol,omitempty"`
 	ProtocolMapper        string                `json:"protocolMapper,omitempty"`
-	ConsentRequired       bool                  `json:"consentRequired,omitempty"`
+	ConsentRequired       bool                  `json:"consentRequired"`
 	ProtocolMappersConfig ProtocolMappersConfig `json:"config,omitempty"`
 }
 
@@ -266,22 +266,22 @@ type Client struct {
 	AdminURL                           string                         `json:"adminUrl,omitempty"`
 	Attributes                         map[string]string              `json:"attributes,omitempty"`
 	AuthenticationFlowBindingOverrides map[string]string              `json:"authenticationFlowBindingOverrides,omitempty"`
-	AuthorizationServicesEnabled       bool                           `json:"authorizationServicesEnabled,omitempty"`
+	AuthorizationServicesEnabled       bool                           `json:"authorizationServicesEnabled"`
 	AuthorizationSettings              *ResourceServerRepresentation  `json:"authorizationSettings,omitempty"`
 	BaseURL                            string                         `json:"baseURL,omitempty"`
-	BearerOnly                         bool                           `json:"bearerOnly,omitempty"`
+	BearerOnly                         bool                           `json:"bearerOnly"`
 	ClientAuthenticatorType            string                         `json:"clientAuthenticatorType,omitempty"`
 	ClientID                           string                         `json:"clientId,omitempty"`
-	ConsentRequired                    bool                           `json:"consentRequired,omitempty"`
+	ConsentRequired                    bool                           `json:"consentRequired"`
 	DefaultClientScopes                []string                       `json:"defaultClientScopes,omitempty"`
 	DefaultRoles                       []string                       `json:"defaultRoles,omitempty"`
 	Description                        string                         `json:"description,omitempty"`
-	DirectAccessGrantsEnabled          bool                           `json:"directAccessGrantsEnabled,omitempty"`
-	Enabled                            bool                           `json:"enabled,omitempty"`
-	FrontChannelLogout                 bool                           `json:"frontchannelLogout,omitempty"`
-	FullScopeAllowed                   bool                           `json:"fullScopeAllowed,omitempty"`
+	DirectAccessGrantsEnabled          bool                           `json:"directAccessGrantsEnabled"`
+	Enabled                            bool                           `json:"enabled"`
+	FrontChannelLogout                 bool                           `json:"frontchannelLogout"`
+	FullScopeAllowed                   bool                           `json:"fullScopeAllowed"`
 	ID                                 string                         `json:"id,omitempty"`
-	ImplicitFlowEnabled                bool                           `json:"implicitFlowEnabled,omitempty"`
+	ImplicitFlowEnabled                bool                           `json:"implicitFlowEnabled"`
 	Name                               string                         `json:"name,omitempty"`
 	NodeReRegistrationTimeout          int32                          `json:"nodeReRegistrationTimeout,omitempty"`
 	NotBefore                          int32                          `json:"notBefore,omitempty"`
@@ -289,21 +289,21 @@ type Client struct {
 	Origin                             string                         `json:"origin,omitempty"`
 	Protocol                           string                         `json:"protocol,omitempty"`
 	ProtocolMappers                    []ProtocolMapperRepresentation `json:"protocolMappers,omitempty"`
-	PublicClient                       bool                           `json:"publicClient,omitempty"`
+	PublicClient                       bool                           `json:"publicClient"`
 	RedirectURIs                       []string                       `json:"redirectUris,omitempty"`
 	RegisteredNodes                    map[string]string              `json:"registeredNodes,omitempty"`
 	RegistrationAccessToken            string                         `json:"registrationAccessToken,omitempty"`
 	RootURL                            string                         `json:"rootUrl,omitempty"`
 	Secret                             string                         `json:"secret,omitempty"`
-	ServiceAccountsEnabled             bool                           `json:"serviceAccountsEnabled,omitempty"`
-	StandardFlowEnabled                bool                           `json:"standardFlowEnabled,omitempty"`
-	SurrogateAuthRequired              bool                           `json:"surrogateAuthRequired,omitempty"`
+	ServiceAccountsEnabled             bool                           `json:"serviceAccountsEnabled"`
+	StandardFlowEnabled                bool                           `json:"standardFlowEnabled"`
+	SurrogateAuthRequired              bool                           `json:"surrogateAuthRequired"`
 	WebOrigins                         []string                       `json:"webOrigins,omitempty"`
 }
 
 // ResourceServerRepresentation represents the resources of a Server
 type ResourceServerRepresentation struct {
-	AllowRemoteResourceManagement bool                     `json:"allowRemoteResourceManagement,omitempty"`
+	AllowRemoteResourceManagement bool                     `json:"allowRemoteResourceManagement"`
 	ClientID                      string                   `json:"clientId,omitempty"`
 	ID                            string                   `json:"id,omitempty"`
 	Name                          string                   `json:"name,omitempty"`
@@ -364,7 +364,7 @@ type ResourceRepresentation struct {
 	DisplayName        string                `json:"displayName,omitempty"`
 	IconURI            string                `json:"icon_uri,omitempty"` //TODO: With "_" because that's how it's written down in the template
 	Name               string                `json:"name,omitempty"`
-	OwnerManagedAccess bool                  `json:"ownerManagedAccess,omitempty"`
+	OwnerManagedAccess bool                  `json:"ownerManagedAccess"`
 	Scopes             []ScopeRepresentation `json:"scopes,omitempty"`
 	Type               string                `json:"type,omitempty"`
 	URIs               []string              `json:"uris,omitempty"`
@@ -392,13 +392,13 @@ type ProtocolMapperRepresentation struct {
 // GetClientsParams represents the query parameters
 type GetClientsParams struct {
 	ClientID     string `json:"clientId,omitempty"`
-	ViewableOnly bool   `json:"viewableOnly,string,omitempty"`
+	ViewableOnly bool   `json:"viewableOnly,string"`
 }
 
 // UserInfo is returned by the userinfo endpoint
 type UserInfo struct {
 	Sub               string      `json:"sub,omitempty"`
-	EmailVerified     bool        `json:"email_verified,omitempty"`
+	EmailVerified     bool        `json:"email_verified"`
 	Address           interface{} `json:"address,omitempty"`
 	PreferredUsername string      `json:"preferred_username,omitempty"`
 	Email             string      `json:"email,omitempty"`
@@ -414,15 +414,15 @@ type RealmRepresentation struct {
 	AccountTheme                        string            `json:"accountTheme,omitempty"`
 	ActionTokenGeneratedByAdminLifespan int               `json:"actionTokenGeneratedByAdminLifespan,omitempty"`
 	ActionTokenGeneratedByUserLifespan  int               `json:"actionTokenGeneratedByUserLifespan,omitempty"`
-	AdminEventsDetailsEnabled           bool              `json:"adminEventsDetailsEnabled,omitempty"`
-	AdminEventsEnabled                  bool              `json:"adminEventsEnabled,omitempty"`
+	AdminEventsDetailsEnabled           bool              `json:"adminEventsDetailsEnabled"`
+	AdminEventsEnabled                  bool              `json:"adminEventsEnabled"`
 	AdminTheme                          string            `json:"adminTheme,omitempty"`
 	Attributes                          map[string]string `json:"attributes,omitempty"`
 	AuthenticationFlows                 []interface{}     `json:"authenticationFlows,omitempty"`
 	AuthenticatorConfig                 []interface{}     `json:"authenticatorConfig,omitempty"`
 	BrowserFlow                         string            `json:"browserFlow,omitempty"`
 	BrowserSecurityHeaders              map[string]string `json:"browserSecurityHeaders,omitempty"`
-	BruteForceProtected                 bool              `json:"bruteForceProtected,omitempty"`
+	BruteForceProtected                 bool              `json:"bruteForceProtected"`
 	ClientAuthenticationFlow            string            `json:"clientAuthenticationFlow,omitempty"`
 	ClientScopeMappings                 map[string]string `json:"clientScopeMappings,omitempty"`
 	ClientScopes                        []ClientScope     `json:"clientScopes,omitempty"`
@@ -438,12 +438,12 @@ type RealmRepresentation struct {
 	DisplayName                         string            `json:"displayName,omitempty"`
 	DisplayNameHTML                     string            `json:"displayNameHtml,omitempty"`
 	DockerAuthenticationFlow            string            `json:"dockerAuthenticationFlow,omitempty"`
-	DuplicateEmailsAllowed              bool              `json:"duplicateEmailsAllowed,omitempty"`
-	EditUsernameAllowed                 bool              `json:"editUsernameAllowed,omitempty"`
+	DuplicateEmailsAllowed              bool              `json:"duplicateEmailsAllowed"`
+	EditUsernameAllowed                 bool              `json:"editUsernameAllowed"`
 	EmailTheme                          string            `json:"emailTheme,omitempty"`
-	Enabled                             bool              `json:"enabled,omitempty"`
+	Enabled                             bool              `json:"enabled"`
 	EnabledEventTypes                   []string          `json:"enabledEventTypes,omitempty"`
-	EventsEnabled                       bool              `json:"eventsEnabled,omitempty"`
+	EventsEnabled                       bool              `json:"eventsEnabled"`
 	EventsExpiration                    int64             `json:"eventsExpiration,omitempty"`
 	EventsListeners                     []string          `json:"eventsListeners,omitempty"`
 	FailureFactor                       int               `json:"failureFactor,omitempty"`
@@ -452,17 +452,17 @@ type RealmRepresentation struct {
 	ID                                  string            `json:"id,omitempty"`
 	IdentityProviderMappers             []interface{}     `json:"identityProviderMappers,omitempty"`
 	IdentityProviders                   []interface{}     `json:"identityProviders,omitempty"`
-	InternationalizationEnabled         bool              `json:"internationalizationEnabled,omitempty"`
+	InternationalizationEnabled         bool              `json:"internationalizationEnabled"`
 	KeycloakVersion                     string            `json:"keycloakVersion,omitempty"`
 	LoginTheme                          string            `json:"loginTheme,omitempty"`
-	LoginWithEmailAllowed               bool              `json:"loginWithEmailAllowed,omitempty"`
+	LoginWithEmailAllowed               bool              `json:"loginWithEmailAllowed"`
 	MaxDeltaTimeSeconds                 int               `json:"maxDeltaTimeSeconds,omitempty"`
 	MaxFailureWaitSeconds               int               `json:"maxFailureWaitSeconds,omitempty"`
 	MinimumQuickLoginWaitSeconds        int               `json:"minimumQuickLoginWaitSeconds,omitempty"`
 	NotBefore                           int               `json:"notBefore,omitempty"`
 	OfflineSessionIdleTimeout           int               `json:"offlineSessionIdleTimeout,omitempty"`
 	OfflineSessionMaxLifespan           int               `json:"offlineSessionMaxLifespan,omitempty"`
-	OfflineSessionMaxLifespanEnabled    bool              `json:"offlineSessionMaxLifespanEnabled,omitempty"`
+	OfflineSessionMaxLifespanEnabled    bool              `json:"offlineSessionMaxLifespanEnabled"`
 	OtpPolicyAlgorithm                  string            `json:"otpPolicyAlgorithm,omitempty"`
 	OtpPolicyDigits                     int               `json:"otpPolicyDigits,omitempty"`
 	OtpPolicyInitialCounter             int               `json:"otpPolicyInitialCounter,omitempty"`
@@ -471,19 +471,19 @@ type RealmRepresentation struct {
 	OtpPolicyType                       string            `json:"otpPolicyType,omitempty"`
 	OtpSupportedApplications            []string          `json:"otpSupportedApplications,omitempty"`
 	PasswordPolicy                      string            `json:"passwordPolicy,omitempty"`
-	PermanentLockout                    bool              `json:"permanentLockout,omitempty"`
+	PermanentLockout                    bool              `json:"permanentLockout"`
 	ProtocolMappers                     []interface{}     `json:"protocolMappers,omitempty"`
 	QuickLoginCheckMilliSeconds         int64             `json:"quickLoginCheckMilliSeconds,omitempty"`
 	Realm                               string            `json:"realm,omitempty"`
 	RefreshTokenMaxReuse                int               `json:"refreshTokenMaxReuse,omitempty"`
-	RegistrationAllowed                 bool              `json:"registrationAllowed,omitempty"`
-	RegistrationEmailAsUsername         bool              `json:"registrationEmailAsUsername,omitempty"`
+	RegistrationAllowed                 bool              `json:"registrationAllowed"`
+	RegistrationEmailAsUsername         bool              `json:"registrationEmailAsUsername"`
 	RegistrationFlow                    string            `json:"registrationFlow,omitempty"`
-	RememberMe                          bool              `json:"rememberMe,omitempty"`
+	RememberMe                          bool              `json:"rememberMe"`
 	RequiredActions                     []interface{}     `json:"requiredActions,omitempty"`
 	ResetCredentialsFlow                string            `json:"resetCredentialsFlow,omitempty"`
-	ResetPasswordAllowed                bool              `json:"resetPasswordAllowed,omitempty"`
-	RevokeRefreshToken                  bool              `json:"revokeRefreshToken,omitempty"`
+	ResetPasswordAllowed                bool              `json:"resetPasswordAllowed"`
+	RevokeRefreshToken                  bool              `json:"revokeRefreshToken"`
 	Roles                               interface{}       `json:"roles,omitempty"`
 	ScopeMappings                       []interface{}     `json:"scopeMappings,omitempty"`
 	SMTPServer                          map[string]string `json:"smtpServer,omitempty"`
@@ -495,15 +495,15 @@ type RealmRepresentation struct {
 	SupportedLocales                    []string          `json:"supportedLocales,omitempty"`
 	UserFederationMappers               []interface{}     `json:"userFederationMappers,omitempty"`
 	UserFederationProviders             []interface{}     `json:"userFederationProviders,omitempty"`
-	UserManagedAccessAllowed            bool              `json:"userManagedAccessAllowed,omitempty"`
+	UserManagedAccessAllowed            bool              `json:"userManagedAccessAllowed"`
 	Users                               []interface{}     `json:"users,omitempty"`
-	VerifyEmail                         bool              `json:"verifyEmail,omitempty"`
+	VerifyEmail                         bool              `json:"verifyEmail"`
 	WaitIncrementSeconds                int               `json:"waitIncrementSeconds,omitempty"`
 }
 
 // MultivaluedHashMap represents something
 type MultivaluedHashMap struct {
-	Empty      bool    `json:"empty,omitempty"`
+	Empty      bool    `json:"empty"`
 	LoadFactor float32 `json:"loadFactor,omitempty"`
 	Threshold  int32   `json:"threshold,omitempty"`
 }
@@ -520,7 +520,7 @@ type CredentialRepresentation struct {
 	HashedSaltedValue string             `json:"hashedSaltedValue,omitempty"`
 	Period            int32              `json:"period,omitempty"`
 	Salt              string             `json:"salt,omitempty"`
-	Temporary         bool               `json:"temporary,omitempty"`
+	Temporary         bool               `json:"temporary"`
 	Type              string             `json:"type,omitempty"`
 	Value             string             `json:"value,omitempty"`
 }
diff --git a/tools/bump_version.go b/tools/bump_version.go
index 6c1aa7f..bd3bc6e 100644
--- a/tools/bump_version.go
+++ b/tools/bump_version.go
@@ -195,9 +195,12 @@ func main() {
 
 		if *major {
 			newTag.Major += 1
+			newTag.Minor = 0
+			newTag.Patch = 0
 		}
 		if *minor || (!*major && !*patch) {
 			newTag.Minor += 1
+			newTag.Patch = 0
 		}
 		if *patch {
 			newTag.Patch += 1


Test patch:
diff --git a/client_test.go b/client_test.go
index d760fc5..270adc4 100644
--- a/client_test.go
+++ b/client_test.go
@@ -54,8 +54,7 @@ const (
 )
 
 func FailIfErr(t *testing.T, err error, msg string) {
-	_, objectAlreadyExists := err.(*ObjectAlreadyExists)
-	if objectAlreadyExists {
+	if IsObjectAlreadyExists(err) {
 		return
 	}
 
@@ -87,6 +86,7 @@ func AssertEquals(t *testing.T, exp interface{}, act interface{}) {
 
 func GetConfig(t *testing.T) *Config {
 	configOnce.Do(func() {
+		rand.Seed(time.Now().UTC().UnixNano())
 		configFileName, ok := os.LookupEnv("GOCLOAK_TEST_CONFIG")
 		if !ok {
 			configFileName = filepath.Join("testdata", "config.json")
@@ -162,9 +162,9 @@ func GetClientByClientID(t *testing.T, client GoCloak, clientID string) *Client
 			ClientID: clientID,
 		})
 	FailIfErr(t, err, "GetClients failed")
-	for _, fetchedClient := range *clients {
+	for _, fetchedClient := range clients {
 		if fetchedClient.ClientID == clientID {
-			return &fetchedClient
+			return fetchedClient
 		}
 	}
 	t.Fatal("Client not found")
@@ -190,7 +190,7 @@ func CreateGroup(t *testing.T, client GoCloak) (func(), string) {
 		})
 	FailIfErr(t, err, "GetGroups failed")
 	var groupID string
-	for _, fetchedGroup := range *groups {
+	for _, fetchedGroup := range groups {
 		if fetchedGroup.Name == group.Name {
 			groupID = fetchedGroup.ID
 			break
@@ -224,8 +224,8 @@ func SetUpTestUser(t *testing.T, client GoCloak) {
 			token.AccessToken,
 			cfg.GoCloak.Realm,
 			user)
-		if err != nil && err.Error() == "Conflict: Object already exists" {
-			err = nil
+		FailIfErr(t, err, "CreateUser failed")
+		if IsObjectAlreadyExists(err) {
 			users, err := client.GetUsers(
 				token.AccessToken,
 				cfg.GoCloak.Realm,
@@ -233,7 +233,7 @@ func SetUpTestUser(t *testing.T, client GoCloak) {
 					Username: cfg.GoCloak.UserName,
 				})
 			FailIfErr(t, err, "GetUsers failed")
-			for _, user := range *users {
+			for _, user := range users {
 				if user.Username == cfg.GoCloak.UserName {
 					testUserID = user.ID
 					break
@@ -241,7 +241,7 @@ func SetUpTestUser(t *testing.T, client GoCloak) {
 			}
 		} else {
 			FailIfErr(t, err, "CreateUser failed")
-			testUserID = *createdUserID
+			testUserID = createdUserID
 		}
 
 		err = client.SetPassword(
@@ -390,7 +390,7 @@ func TestGocloak_LoginClient_UnknownRealm(t *testing.T) {
 	FailIf(t, err == nil, "Login shouldn't be successful")
 
 	errorMessage := err.Error()
-	FailIf(t, errorMessage != "404 Not Found", "Unexpected error message: "+errorMessage)
+	AssertEquals(t, "404 Not Found", errorMessage)
 }
 
 func TestGocloak_GetIssuer(t *testing.T) {
@@ -704,19 +704,19 @@ func TestGocloak_CreateListGetUpdateDeleteClient(t *testing.T) {
 		},
 	)
 	FailIfErr(t, err, "CreateClients failed")
-	FailIf(t, len(*clients) != 1, "GetClients should return exact 1 client")
-	t.Logf("Clients: %+v", *clients)
+	FailIf(t, len(clients) != 1, "GetClients should return exact 1 client")
+	t.Logf("Clients: %+v", clients)
 
 	// Getting exact client
 	createdClient, err := client.GetClient(
 		token.AccessToken,
 		cfg.GoCloak.Realm,
-		(*clients)[0].ID,
+		clients[0].ID,
 	)
 	FailIfErr(t, err, "GetClient failed")
 	t.Logf("Created client: %+v", createdClient)
 	// Checking that GetClient returns same client
-	AssertEquals(t, (*clients)[0], *createdClient)
+	AssertEquals(t, clients[0], createdClient)
 
 	// Updating the client
 
@@ -741,7 +741,7 @@ func TestGocloak_CreateListGetUpdateDeleteClient(t *testing.T) {
 	updatedClient, err := client.GetClient(
 		token.AccessToken,
 		cfg.GoCloak.Realm,
-		(*clients)[0].ID,
+		clients[0].ID,
 	)
 	FailIfErr(t, err, "GetClient failed")
 	t.Logf("Update client: %+v", createdClient)
@@ -764,7 +764,7 @@ func TestGocloak_CreateListGetUpdateDeleteClient(t *testing.T) {
 		},
 	)
 	FailIfErr(t, err, "CreateClients failed")
-	FailIf(t, len(*clients) != 0, "GetClients should not return any clients")
+	FailIf(t, len(clients) != 0, "GetClients should not return any clients")
 
 }
 
@@ -781,21 +781,6 @@ func TestGocloak_GetGroups(t *testing.T) {
 	FailIfErr(t, err, "GetGroups failed")
 }
 
-func TestGocloak_GetClients(t *testing.T) {
-	t.Parallel()
-	cfg := GetConfig(t)
-	client := NewClientWithDebug(t)
-	token := GetAdminToken(t, client)
-
-	_, err := client.GetClients(
-		token.AccessToken,
-		cfg.GoCloak.Realm,
-		GetClientsParams{
-			ClientID: cfg.GoCloak.ClientID,
-		})
-	FailIfErr(t, err, "GetClients failed")
-}
-
 func TestGocloak_GetClientRoles(t *testing.T) {
 	t.Parallel()
 	cfg := GetConfig(t)
@@ -864,7 +849,7 @@ func TestGocloak_ExecuteActionsEmail_UpdatePassword(t *testing.T) {
 		params)
 
 	if err != nil {
-		if err.Error() == "500 Internal Server Error" {
+		if err.Error() == "500 Internal Server Error: Failed to send execute actions email" {
 			return
 		}
 		FailIfErr(t, err, "ExecuteActionsEmail failed")
@@ -999,7 +984,7 @@ func TestGocloak_GetRealmRoles(t *testing.T) {
 		token.AccessToken,
 		cfg.GoCloak.Realm)
 	FailIfErr(t, err, "GetRealmRoles failed")
-	t.Logf("Roles: %+v", *roles)
+	t.Logf("Roles: %+v", roles)
 }
 
 func TestGocloak_UpdateRealmRole(t *testing.T) {
@@ -1106,8 +1091,8 @@ func TestGocloak_GetRealmRolesByUserID(t *testing.T) {
 		cfg.GoCloak.Realm,
 		userID)
 	FailIfErr(t, err, "GetRealmRolesByUserID failed")
-	t.Logf("User roles: %+v", *roles)
-	for _, r := range *roles {
+	t.Logf("User roles: %+v", roles)
+	for _, r := range roles {
 		if r.Name == role.Name {
 			return
 		}
@@ -1169,11 +1154,11 @@ func TestGocloak_DeleteRealmRoleFromUser(t *testing.T) {
 		cfg.GoCloak.Realm,
 		userID)
 	FailIfErr(t, err, "GetRealmRolesByUserID failed")
-	for _, r := range *roles {
+	for _, r := range roles {
 		FailIf(
 			t,
 			r.Name == role.Name,
-			"The role has been found in asigned roles. Role: %+v", role)
+			"The role has been found in assigned roles. Role: %+v", role)
 	}
 }
 
@@ -1246,7 +1231,7 @@ func CreateUser(t *testing.T, client GoCloak) (func(), string) {
 		cfg.GoCloak.Realm,
 		user)
 	FailIfErr(t, err, "CreateUser failed")
-	user.ID = *userID
+	user.ID = userID
 	t.Logf("Created User: %+v", user)
 	tearDown := func() {
 		err := client.DeleteUser(
@@ -1405,12 +1390,12 @@ func TestGocloak_GetUserGroups(t *testing.T) {
 	FailIfErr(t, err, "GetUserGroups failed")
 	FailIf(
 		t,
-		len(*groups) == 0,
+		len(groups) == 0,
 		"User is not in the Group")
 	AssertEquals(
 		t,
 		groupID,
-		(*groups)[0].ID)
+		groups[0].ID)
 }
 
 func TestGocloak_DeleteUser(t *testing.T) {
@@ -1476,12 +1461,12 @@ func TestGocloak_GetUsersByRoleName(t *testing.T) {
 
 	FailIf(
 		t,
-		len(*users) == 0,
+		len(users) == 0,
 		"User is not in the Group")
 	AssertEquals(
 		t,
 		userID,
-		(*users)[0].ID)
+		users[0].ID)
 }
 
 func TestGocloak_GetUserSessions(t *testing.T) {
@@ -1507,7 +1492,7 @@ func TestGocloak_GetUserSessions(t *testing.T) {
 		testUserID,
 	)
 	FailIfErr(t, err, "GetUserSessions failed")
-	FailIf(t, len(*sessions) == 0, "GetUserSessions returned an empty list")
+	FailIf(t, len(sessions) == 0, "GetUserSessions returned an empty list")
 }
 
 func TestGocloak_GetUserOfflineSessionsForClient(t *testing.T) {
@@ -1536,7 +1521,7 @@ func TestGocloak_GetUserOfflineSessionsForClient(t *testing.T) {
 		gocloakClientID,
 	)
 	FailIfErr(t, err, "GetUserOfflineSessionsForClient failed")
-	FailIf(t, len(*sessions) == 0, "GetUserOfflineSessionsForClient returned an empty list")
+	FailIf(t, len(sessions) == 0, "GetUserOfflineSessionsForClient returned an empty list")
 }
 
 func TestGocloak_GetClientUserSessions(t *testing.T) {
@@ -1562,7 +1547,7 @@ func TestGocloak_GetClientUserSessions(t *testing.T) {
 		gocloakClientID,
 	)
 	FailIfErr(t, err, "GetClientUserSessions failed")
-	FailIf(t, len(*sessions) == 0, "GetClientUserSessions returned an empty list")
+	FailIf(t, len(sessions) == 0, "GetClientUserSessions returned an empty list")
 }
 
 func TestGocloak_GetClientOfflineSessions(t *testing.T) {
@@ -1590,5 +1575,5 @@ func TestGocloak_GetClientOfflineSessions(t *testing.T) {
 		gocloakClientID,
 	)
 	FailIfErr(t, err, "GetClientOfflineSessions failed")
-	FailIf(t, len(*sessions) == 0, "GetClientOfflineSessions returned an empty list")
+	FailIf(t, len(sessions) == 0, "GetClientOfflineSessions returned an empty list")
 }