Repository: hetznercloud/hcloud-go
Pull request #219 (2022-12-19 12:55:20)

feat: Use generics to get pointers to types
Since the minimum required Go version is 1.18 according to go.mod we can use generics to have a single function that can return a pointer to any type. This avoids the need to add more $Type helpers in the future.

The new Ptr function is introduced and exsiting functions are updated to call through Ptr instead. Any exported functions are now marked as deprecated but not removed in order to avoid breaking backwards compatibility. All non-exported functions are removed. All call sites are updated to use Ptr directly.

apricote: Thanks for the contribution @daenney!

We still test against Go 1.17, even though the `go.mod` specifies v1.18+.

We should remove the tests for Go v1.17 and codify our Go version requirements (probably in line with [official support](https://go.dev/doc/devel/release#policy)).

I will create a PR for this and notify you once that is merged :)
apricote: #220 is merged, you may now rebase your branch against `main`.
daenney: @apricote Thanks! Pushed a rebase.

Patch:
diff --git a/hcloud/floating_ip.go b/hcloud/floating_ip.go
index b180409..988936d 100644
--- a/hcloud/floating_ip.go
+++ b/hcloud/floating_ip.go
@@ -241,10 +241,10 @@ func (c *FloatingIPClient) Create(ctx context.Context, opts FloatingIPCreateOpts
 		Name:        opts.Name,
 	}
 	if opts.HomeLocation != nil {
-		reqBody.HomeLocation = String(opts.HomeLocation.Name)
+		reqBody.HomeLocation = Ptr(opts.HomeLocation.Name)
 	}
 	if opts.Server != nil {
-		reqBody.Server = Int(opts.Server.ID)
+		reqBody.Server = Ptr(opts.Server.ID)
 	}
 	if opts.Labels != nil {
 		reqBody.Labels = &opts.Labels
diff --git a/hcloud/helper.go b/hcloud/helper.go
index e8e2642..1965609 100644
--- a/hcloud/helper.go
+++ b/hcloud/helper.go
@@ -2,17 +2,27 @@ package hcloud
 
 import "time"
 
+// Ptr returns a pointer to p.
+func Ptr[T any](p T) *T {
+	return &p
+}
+
 // String returns a pointer to the passed string s.
-func String(s string) *string { return &s }
+//
+// Deprecated: Use [Ptr] instead.
+func String(s string) *string { return Ptr(s) }
 
 // Int returns a pointer to the passed integer i.
-func Int(i int) *int { return &i }
+//
+// Deprecated: Use [Ptr] instead.
+func Int(i int) *int { return Ptr(i) }
 
 // Bool returns a pointer to the passed bool b.
-func Bool(b bool) *bool { return &b }
+//
+// Deprecated: Use [Ptr] instead.
+func Bool(b bool) *bool { return Ptr(b) }
 
 // Duration returns a pointer to the passed time.Duration d.
-func Duration(d time.Duration) *time.Duration { return &d }
-
-func intSlice(is []int) *[]int          { return &is }
-func stringSlice(ss []string) *[]string { return &ss }
+//
+// Deprecated: Use [Ptr] instead.
+func Duration(d time.Duration) *time.Duration { return Ptr(d) }
diff --git a/hcloud/image.go b/hcloud/image.go
index 0867aac..6a71898 100644
--- a/hcloud/image.go
+++ b/hcloud/image.go
@@ -222,7 +222,7 @@ func (c *ImageClient) Update(ctx context.Context, image *Image, opts ImageUpdate
 		Description: opts.Description,
 	}
 	if opts.Type != "" {
-		reqBody.Type = String(string(opts.Type))
+		reqBody.Type = Ptr(string(opts.Type))
 	}
 	if opts.Labels != nil {
 		reqBody.Labels = &opts.Labels
diff --git a/hcloud/load_balancer.go b/hcloud/load_balancer.go
index 96aeaf4..81e2e03 100644
--- a/hcloud/load_balancer.go
+++ b/hcloud/load_balancer.go
@@ -491,7 +491,6 @@ type LoadBalancerCreateResult struct {
 func (c *LoadBalancerClient) Create(ctx context.Context, opts LoadBalancerCreateOpts) (LoadBalancerCreateResult, *Response, error) {
 	reqBody := loadBalancerCreateOptsToSchema(opts)
 	reqBodyData, err := json.Marshal(reqBody)
-
 	if err != nil {
 		return LoadBalancerCreateResult{}, nil, err
 	}
@@ -865,7 +864,7 @@ func (c *LoadBalancerClient) AttachToNetwork(ctx context.Context, loadBalancer *
 		Network: opts.Network.ID,
 	}
 	if opts.IP != nil {
-		reqBody.IP = String(opts.IP.String())
+		reqBody.IP = Ptr(opts.IP.String())
 	}
 	reqBodyData, err := json.Marshal(reqBody)
 	if err != nil {
diff --git a/hcloud/schema.go b/hcloud/schema.go
index 633a568..100917a 100644
--- a/hcloud/schema.go
+++ b/hcloud/schema.go
@@ -881,19 +881,19 @@ func loadBalancerCreateOptsToSchema(opts LoadBalancerCreateOpts) schema.LoadBala
 	}
 	if opts.Location != nil {
 		if opts.Location.ID != 0 {
-			req.Location = String(strconv.Itoa(opts.Location.ID))
+			req.Location = Ptr(strconv.Itoa(opts.Location.ID))
 		} else {
-			req.Location = String(opts.Location.Name)
+			req.Location = Ptr(opts.Location.Name)
 		}
 	}
 	if opts.NetworkZone != "" {
-		req.NetworkZone = String(string(opts.NetworkZone))
+		req.NetworkZone = Ptr(string(opts.NetworkZone))
 	}
 	if opts.Labels != nil {
 		req.Labels = &opts.Labels
 	}
 	if opts.Network != nil {
-		req.Network = Int(opts.Network.ID)
+		req.Network = Ptr(opts.Network.ID)
 	}
 	for _, target := range opts.Targets {
 		schemaTarget := schema.LoadBalancerCreateRequestTarget{
@@ -927,7 +927,7 @@ func loadBalancerCreateOptsToSchema(opts LoadBalancerCreateOpts) schema.LoadBala
 			}
 			if service.HTTP.CookieLifetime != nil {
 				if sec := service.HTTP.CookieLifetime.Seconds(); sec != 0 {
-					schemaService.HTTP.CookieLifetime = Int(int(sec))
+					schemaService.HTTP.CookieLifetime = Ptr(int(sec))
 				}
 			}
 			if service.HTTP.Certificates != nil {
@@ -945,10 +945,10 @@ func loadBalancerCreateOptsToSchema(opts LoadBalancerCreateOpts) schema.LoadBala
 				Retries:  service.HealthCheck.Retries,
 			}
 			if service.HealthCheck.Interval != nil {
-				schemaHealthCheck.Interval = Int(int(service.HealthCheck.Interval.Seconds()))
+				schemaHealthCheck.Interval = Ptr(int(service.HealthCheck.Interval.Seconds()))
 			}
 			if service.HealthCheck.Timeout != nil {
-				schemaHealthCheck.Timeout = Int(int(service.HealthCheck.Timeout.Seconds()))
+				schemaHealthCheck.Timeout = Ptr(int(service.HealthCheck.Timeout.Seconds()))
 			}
 			if service.HealthCheck.HTTP != nil {
 				schemaHealthCheckHTTP := &schema.LoadBalancerCreateRequestServiceHealthCheckHTTP{
@@ -983,7 +983,7 @@ func loadBalancerAddServiceOptsToSchema(opts LoadBalancerAddServiceOpts) schema.
 			StickySessions: opts.HTTP.StickySessions,
 		}
 		if opts.HTTP.CookieLifetime != nil {
-			req.HTTP.CookieLifetime = Int(int(opts.HTTP.CookieLifetime.Seconds()))
+			req.HTTP.CookieLifetime = Ptr(int(opts.HTTP.CookieLifetime.Seconds()))
 		}
 		if opts.HTTP.Certificates != nil {
 			certificates := []int{}
@@ -1000,10 +1000,10 @@ func loadBalancerAddServiceOptsToSchema(opts LoadBalancerAddServiceOpts) schema.
 			Retries:  opts.HealthCheck.Retries,
 		}
 		if opts.HealthCheck.Interval != nil {
-			req.HealthCheck.Interval = Int(int(opts.HealthCheck.Interval.Seconds()))
+			req.HealthCheck.Interval = Ptr(int(opts.HealthCheck.Interval.Seconds()))
 		}
 		if opts.HealthCheck.Timeout != nil {
-			req.HealthCheck.Timeout = Int(int(opts.HealthCheck.Timeout.Seconds()))
+			req.HealthCheck.Timeout = Ptr(int(opts.HealthCheck.Timeout.Seconds()))
 		}
 		if opts.HealthCheck.HTTP != nil {
 			req.HealthCheck.HTTP = &schema.LoadBalancerActionAddServiceRequestHealthCheckHTTP{
@@ -1026,7 +1026,7 @@ func loadBalancerUpdateServiceOptsToSchema(opts LoadBalancerUpdateServiceOpts) s
 		Proxyprotocol:   opts.Proxyprotocol,
 	}
 	if opts.Protocol != "" {
-		req.Protocol = String(string(opts.Protocol))
+		req.Protocol = Ptr(string(opts.Protocol))
 	}
 	if opts.HTTP != nil {
 		req.HTTP = &schema.LoadBalancerActionUpdateServiceRequestHTTP{
@@ -1035,7 +1035,7 @@ func loadBalancerUpdateServiceOptsToSchema(opts LoadBalancerUpdateServiceOpts) s
 			StickySessions: opts.HTTP.StickySessions,
 		}
 		if opts.HTTP.CookieLifetime != nil {
-			req.HTTP.CookieLifetime = Int(int(opts.HTTP.CookieLifetime.Seconds()))
+			req.HTTP.CookieLifetime = Ptr(int(opts.HTTP.CookieLifetime.Seconds()))
 		}
 		if opts.HTTP.Certificates != nil {
 			certificates := []int{}
@@ -1051,13 +1051,13 @@ func loadBalancerUpdateServiceOptsToSchema(opts LoadBalancerUpdateServiceOpts) s
 			Retries: opts.HealthCheck.Retries,
 		}
 		if opts.HealthCheck.Interval != nil {
-			req.HealthCheck.Interval = Int(int(opts.HealthCheck.Interval.Seconds()))
+			req.HealthCheck.Interval = Ptr(int(opts.HealthCheck.Interval.Seconds()))
 		}
 		if opts.HealthCheck.Timeout != nil {
-			req.HealthCheck.Timeout = Int(int(opts.HealthCheck.Timeout.Seconds()))
+			req.HealthCheck.Timeout = Ptr(int(opts.HealthCheck.Timeout.Seconds()))
 		}
 		if opts.HealthCheck.Protocol != "" {
-			req.HealthCheck.Protocol = String(string(opts.HealthCheck.Protocol))
+			req.HealthCheck.Protocol = Ptr(string(opts.HealthCheck.Protocol))
 		}
 		if opts.HealthCheck.HTTP != nil {
 			req.HealthCheck.HTTP = &schema.LoadBalancerActionUpdateServiceRequestHealthCheckHTTP{
diff --git a/hcloud/server.go b/hcloud/server.go
index 707425d..da708a2 100644
--- a/hcloud/server.go
+++ b/hcloud/server.go
@@ -664,7 +664,7 @@ func (c *ServerClient) CreateImage(ctx context.Context, server *Server, opts *Se
 			reqBody.Description = opts.Description
 		}
 		if opts.Type != "" {
-			reqBody.Type = String(string(opts.Type))
+			reqBody.Type = Ptr(string(opts.Type))
 		}
 		if opts.Labels != nil {
 			reqBody.Labels = &opts.Labels
@@ -707,7 +707,7 @@ type ServerEnableRescueResult struct {
 // EnableRescue enables rescue mode for a server.
 func (c *ServerClient) EnableRescue(ctx context.Context, server *Server, opts ServerEnableRescueOpts) (ServerEnableRescueResult, *Response, error) {
 	reqBody := schema.ServerActionEnableRescueRequest{
-		Type: String(string(opts.Type)),
+		Type: Ptr(string(opts.Type)),
 	}
 	for _, sshKey := range opts.SSHKeys {
 		reqBody.SSHKeys = append(reqBody.SSHKeys, sshKey.ID)
@@ -832,7 +832,7 @@ func (c *ServerClient) DetachISO(ctx context.Context, server *Server) (*Action,
 func (c *ServerClient) EnableBackup(ctx context.Context, server *Server, window string) (*Action, *Response, error) {
 	reqBody := schema.ServerActionEnableBackupRequest{}
 	if window != "" {
-		reqBody.BackupWindow = String(window)
+		reqBody.BackupWindow = Ptr(window)
 	}
 	reqBodyData, err := json.Marshal(reqBody)
 	if err != nil {
@@ -985,10 +985,10 @@ func (c *ServerClient) AttachToNetwork(ctx context.Context, server *Server, opts
 		Network: opts.Network.ID,
 	}
 	if opts.IP != nil {
-		reqBody.IP = String(opts.IP.String())
+		reqBody.IP = Ptr(opts.IP.String())
 	}
 	for _, aliasIP := range opts.AliasIPs {
-		reqBody.AliasIPs = append(reqBody.AliasIPs, String(aliasIP.String()))
+		reqBody.AliasIPs = append(reqBody.AliasIPs, Ptr(aliasIP.String()))
 	}
 	reqBodyData, err := json.Marshal(reqBody)
 	if err != nil {
diff --git a/hcloud/volume.go b/hcloud/volume.go
index 93e221e..f939d89 100644
--- a/hcloud/volume.go
+++ b/hcloud/volume.go
@@ -210,7 +210,7 @@ func (c *VolumeClient) Create(ctx context.Context, opts VolumeCreateOpts) (Volum
 		reqBody.Labels = &opts.Labels
 	}
 	if opts.Server != nil {
-		reqBody.Server = Int(opts.Server.ID)
+		reqBody.Server = Ptr(opts.Server.ID)
 	}
 	if opts.Location != nil {
 		if opts.Location.ID != 0 {


Test patch:
diff --git a/hcloud/certificate_test.go b/hcloud/certificate_test.go
index 055351a..003bcb5 100644
--- a/hcloud/certificate_test.go
+++ b/hcloud/certificate_test.go
@@ -405,7 +405,7 @@ func TestCertificateClientUpdate(t *testing.T) {
 			t.Fatal(err)
 		}
 		expectedReqBody := schema.CertificateUpdateRequest{
-			Name: String("test"),
+			Name: Ptr("test"),
 			Labels: func() *map[string]string {
 				labels := map[string]string{"key": "value"}
 				return &labels
diff --git a/hcloud/firewall_test.go b/hcloud/firewall_test.go
index bdda89d..6184b77 100644
--- a/hcloud/firewall_test.go
+++ b/hcloud/firewall_test.go
@@ -281,7 +281,7 @@ func TestFirewallClientUpdate(t *testing.T) {
 			t.Fatal(err)
 		}
 		expectedReqBody := schema.FirewallUpdateRequest{
-			Name: String("test"),
+			Name: Ptr("test"),
 			Labels: func() *map[string]string {
 				labels := map[string]string{"key": "value"}
 				return &labels
diff --git a/hcloud/floating_ip_test.go b/hcloud/floating_ip_test.go
index eb1709e..b3494a1 100644
--- a/hcloud/floating_ip_test.go
+++ b/hcloud/floating_ip_test.go
@@ -247,7 +247,7 @@ func TestFloatingIPClientCreate(t *testing.T) {
 
 	opts := FloatingIPCreateOpts{
 		Type:         FloatingIPTypeIPv4,
-		Description:  String("test"),
+		Description:  Ptr("test"),
 		HomeLocation: &Location{Name: "test"},
 		Server:       &Server{ID: 1},
 		Labels:       map[string]string{"key": "value"},
@@ -292,10 +292,10 @@ func TestFloatingIPClientCreateWithName(t *testing.T) {
 
 	opts := FloatingIPCreateOpts{
 		Type:         FloatingIPTypeIPv4,
-		Description:  String("test"),
+		Description:  Ptr("test"),
 		HomeLocation: &Location{Name: "test"},
 		Server:       &Server{ID: 1},
-		Name:         String("MyFloatingIP"),
+		Name:         Ptr("MyFloatingIP"),
 		Labels:       map[string]string{"key": "value"},
 	}
 
@@ -564,7 +564,7 @@ func TestFloatingIPClientChangeProtection(t *testing.T) {
 		})
 
 		opts := FloatingIPChangeProtectionOpts{
-			Delete: Bool(true),
+			Delete: Ptr(true),
 		}
 		action, _, err := env.Client.FloatingIP.ChangeProtection(ctx, floatingIP, opts)
 		if err != nil {
diff --git a/hcloud/image_test.go b/hcloud/image_test.go
index 6a339c0..28fd0cd 100644
--- a/hcloud/image_test.go
+++ b/hcloud/image_test.go
@@ -338,7 +338,7 @@ func TestImageClientUpdate(t *testing.T) {
 		})
 
 		opts := ImageUpdateOpts{
-			Description: String("test"),
+			Description: Ptr("test"),
 			Type:        ImageTypeSnapshot,
 		}
 		updatedImage, _, err := env.Client.Image.Update(ctx, image, opts)
@@ -417,7 +417,7 @@ func TestImageClientChangeProtection(t *testing.T) {
 		})
 
 		opts := ImageChangeProtectionOpts{
-			Delete: Bool(true),
+			Delete: Ptr(true),
 		}
 		action, _, err := env.Client.Image.ChangeProtection(ctx, image, opts)
 		if err != nil {
diff --git a/hcloud/load_balancer_test.go b/hcloud/load_balancer_test.go
index e414831..7d78341 100644
--- a/hcloud/load_balancer_test.go
+++ b/hcloud/load_balancer_test.go
@@ -179,7 +179,7 @@ func TestLoadBalancerCreate(t *testing.T) {
 			Algorithm: &schema.LoadBalancerCreateRequestAlgorithm{
 				Type: "round_robin",
 			},
-			Location: String("fsn1"),
+			Location: Ptr("fsn1"),
 		}
 		if !cmp.Equal(expectedReqBody, reqBody) {
 			t.Log(cmp.Diff(expectedReqBody, reqBody))
@@ -246,7 +246,7 @@ func TestLoadBalancerClientUpdate(t *testing.T) {
 			t.Fatal(err)
 		}
 		expectedReqBody := schema.LoadBalancerUpdateRequest{
-			Name: String("test"),
+			Name: Ptr("test"),
 		}
 		if !cmp.Equal(expectedReqBody, reqBody) {
 			t.Log(cmp.Diff(expectedReqBody, reqBody))
@@ -289,7 +289,7 @@ func TestLoadBalancerClientChangeProtection(t *testing.T) {
 			t.Fatal(err)
 		}
 		expectedReqBody := schema.LoadBalancerActionChangeProtectionRequest{
-			Delete: Bool(true),
+			Delete: Ptr(true),
 		}
 		if !cmp.Equal(expectedReqBody, reqBody) {
 			t.Log(cmp.Diff(expectedReqBody, reqBody))
@@ -308,7 +308,7 @@ func TestLoadBalancerClientChangeProtection(t *testing.T) {
 	)
 
 	opts := LoadBalancerChangeProtectionOpts{
-		Delete: Bool(true),
+		Delete: Ptr(true),
 	}
 	action, _, err := env.Client.LoadBalancer.ChangeProtection(ctx, loadBalancer, opts)
 	if err != nil {
@@ -336,7 +336,7 @@ func TestLoadBalancerClientAddServerTarget(t *testing.T) {
 			Server: &schema.LoadBalancerActionAddTargetRequestServer{
 				ID: 1,
 			},
-			UsePrivateIP: Bool(true),
+			UsePrivateIP: Ptr(true),
 		}
 		if !cmp.Equal(expectedReqBody, reqBody) {
 			t.Log(cmp.Diff(expectedReqBody, reqBody))
@@ -357,7 +357,7 @@ func TestLoadBalancerClientAddServerTarget(t *testing.T) {
 
 	opts := LoadBalancerAddServerTargetOpts{
 		Server:       server,
-		UsePrivateIP: Bool(true),
+		UsePrivateIP: Ptr(true),
 	}
 	action, _, err := env.Client.LoadBalancer.AddServerTarget(ctx, loadBalancer, opts)
 	if err != nil {
@@ -426,23 +426,23 @@ func TestLoadBalancerAddService(t *testing.T) {
 		}
 		expectedReqBody := schema.LoadBalancerActionAddServiceRequest{
 			Protocol:        string(LoadBalancerServiceProtocolHTTP),
-			ListenPort:      Int(4711),
-			DestinationPort: Int(80),
+			ListenPort:      Ptr(4711),
+			DestinationPort: Ptr(80),
 			HTTP: &schema.LoadBalancerActionAddServiceRequestHTTP{
-				CookieName:     String("HCLBSTICKY"),
-				CookieLifetime: Int(5 * 60),
-				RedirectHTTP:   Bool(false),
-				StickySessions: Bool(true),
+				CookieName:     Ptr("HCLBSTICKY"),
+				CookieLifetime: Ptr(5 * 60),
+				RedirectHTTP:   Ptr(false),
+				StickySessions: Ptr(true),
 			},
 			HealthCheck: &schema.LoadBalancerActionAddServiceRequestHealthCheck{
 				Protocol: "http",
-				Port:     Int(4711),
-				Interval: Int(15),
-				Timeout:  Int(10),
-				Retries:  Int(3),
+				Port:     Ptr(4711),
+				Interval: Ptr(15),
+				Timeout:  Ptr(10),
+				Retries:  Ptr(3),
 				HTTP: &schema.LoadBalancerActionAddServiceRequestHealthCheckHTTP{
-					Domain: String("example.com"),
-					Path:   String("/"),
+					Domain: Ptr("example.com"),
+					Path:   Ptr("/"),
 				},
 			},
 		}
@@ -464,23 +464,23 @@ func TestLoadBalancerAddService(t *testing.T) {
 
 	opts := LoadBalancerAddServiceOpts{
 		Protocol:        LoadBalancerServiceProtocolHTTP,
-		ListenPort:      Int(4711),
-		DestinationPort: Int(80),
+		ListenPort:      Ptr(4711),
+		DestinationPort: Ptr(80),
 		HTTP: &LoadBalancerAddServiceOptsHTTP{
-			CookieName:     String("HCLBSTICKY"),
-			CookieLifetime: Duration(5 * time.Minute),
-			RedirectHTTP:   Bool(false),
-			StickySessions: Bool(true),
+			CookieName:     Ptr("HCLBSTICKY"),
+			CookieLifetime: Ptr(5 * time.Minute),
+			RedirectHTTP:   Ptr(false),
+			StickySessions: Ptr(true),
 		},
 		HealthCheck: &LoadBalancerAddServiceOptsHealthCheck{
 			Protocol: "http",
-			Port:     Int(4711),
-			Interval: Duration(15 * time.Second),
-			Timeout:  Duration(10 * time.Second),
-			Retries:  Int(3),
+			Port:     Ptr(4711),
+			Interval: Ptr(15 * time.Second),
+			Timeout:  Ptr(10 * time.Second),
+			Retries:  Ptr(3),
 			HTTP: &LoadBalancerAddServiceOptsHealthCheckHTTP{
-				Domain: String("example.com"),
-				Path:   String("/"),
+				Domain: Ptr("example.com"),
+				Path:   Ptr("/"),
 			},
 		},
 	}
@@ -506,24 +506,24 @@ func TestLoadBalancerUpdateService(t *testing.T) {
 			t.Fatal(err)
 		}
 		expectedReqBody := schema.LoadBalancerActionUpdateServiceRequest{
-			Protocol:        String(string(LoadBalancerServiceProtocolHTTP)),
+			Protocol:        Ptr(string(LoadBalancerServiceProtocolHTTP)),
 			ListenPort:      4711,
-			DestinationPort: Int(80),
+			DestinationPort: Ptr(80),
 			HTTP: &schema.LoadBalancerActionUpdateServiceRequestHTTP{
-				CookieName:     String("HCLBSTICKY"),
-				CookieLifetime: Int(5 * 60),
-				RedirectHTTP:   Bool(false),
-				StickySessions: Bool(true),
+				CookieName:     Ptr("HCLBSTICKY"),
+				CookieLifetime: Ptr(5 * 60),
+				RedirectHTTP:   Ptr(false),
+				StickySessions: Ptr(true),
 			},
 			HealthCheck: &schema.LoadBalancerActionUpdateServiceRequestHealthCheck{
-				Protocol: String(string(LoadBalancerServiceProtocolHTTP)),
-				Port:     Int(4711),
-				Interval: Int(15),
-				Timeout:  Int(10),
-				Retries:  Int(3),
+				Protocol: Ptr(string(LoadBalancerServiceProtocolHTTP)),
+				Port:     Ptr(4711),
+				Interval: Ptr(15),
+				Timeout:  Ptr(10),
+				Retries:  Ptr(3),
 				HTTP: &schema.LoadBalancerActionUpdateServiceRequestHealthCheckHTTP{
-					Domain: String("example.com"),
-					Path:   String("/"),
+					Domain: Ptr("example.com"),
+					Path:   Ptr("/"),
 				},
 			},
 		}
@@ -545,22 +545,22 @@ func TestLoadBalancerUpdateService(t *testing.T) {
 
 	opts := LoadBalancerUpdateServiceOpts{
 		Protocol:        LoadBalancerServiceProtocolHTTP,
-		DestinationPort: Int(80),
+		DestinationPort: Ptr(80),
 		HTTP: &LoadBalancerUpdateServiceOptsHTTP{
-			CookieName:     String("HCLBSTICKY"),
-			CookieLifetime: Duration(5 * time.Minute),
-			RedirectHTTP:   Bool(false),
-			StickySessions: Bool(true),
+			CookieName:     Ptr("HCLBSTICKY"),
+			CookieLifetime: Ptr(5 * time.Minute),
+			RedirectHTTP:   Ptr(false),
+			StickySessions: Ptr(true),
 		},
 		HealthCheck: &LoadBalancerUpdateServiceOptsHealthCheck{
 			Protocol: LoadBalancerServiceProtocolHTTP,
-			Port:     Int(4711),
-			Interval: Duration(15 * time.Second),
-			Timeout:  Duration(10 * time.Second),
-			Retries:  Int(3),
+			Port:     Ptr(4711),
+			Interval: Ptr(15 * time.Second),
+			Timeout:  Ptr(10 * time.Second),
+			Retries:  Ptr(3),
 			HTTP: &LoadBalancerUpdateServiceOptsHealthCheckHTTP{
-				Domain: String("example.com"),
-				Path:   String("/"),
+				Domain: Ptr("example.com"),
+				Path:   Ptr("/"),
 			},
 		},
 	}
@@ -670,7 +670,7 @@ func TestLoadBalancerClientAttachToNetwork(t *testing.T) {
 		}
 		expectedReqBody := schema.LoadBalancerActionAttachToNetworkRequest{
 			Network: 1,
-			IP:      String("10.0.1.1"),
+			IP:      Ptr("10.0.1.1"),
 		}
 		if !cmp.Equal(expectedReqBody, reqBody) {
 			t.Log(cmp.Diff(expectedReqBody, reqBody))
@@ -898,7 +898,7 @@ func TestLoadBalancerClientAddLabelSelectorTarget(t *testing.T) {
 	ctx := context.Background()
 	action, _, err := env.Client.LoadBalancer.AddLabelSelectorTarget(ctx, &LoadBalancer{ID: 1}, LoadBalancerAddLabelSelectorTargetOpts{
 		Selector:     "key=value",
-		UsePrivateIP: Bool(false),
+		UsePrivateIP: Ptr(false),
 	})
 	if err != nil {
 		t.Fatal(err)
diff --git a/hcloud/network_test.go b/hcloud/network_test.go
index 5b0855b..d5f5d00 100644
--- a/hcloud/network_test.go
+++ b/hcloud/network_test.go
@@ -622,7 +622,7 @@ func TestNetworkClientChangeProtection(t *testing.T) {
 		})
 
 		opts := NetworkChangeProtectionOpts{
-			Delete: Bool(true),
+			Delete: Ptr(true),
 		}
 		action, _, err := env.Client.Network.ChangeProtection(ctx, network, opts)
 		if err != nil {
diff --git a/hcloud/schema_test.go b/hcloud/schema_test.go
index 9301d78..a4313a1 100644
--- a/hcloud/schema_test.go
+++ b/hcloud/schema_test.go
@@ -2346,7 +2346,7 @@ func TestLoadBalancerCreateOptsToSchema(t *testing.T) {
 				Algorithm: &schema.LoadBalancerCreateRequestAlgorithm{
 					Type: string(LoadBalancerAlgorithmTypeRoundRobin),
 				},
-				NetworkZone: String(string(NetworkZoneEUCentral)),
+				NetworkZone: Ptr(string(NetworkZoneEUCentral)),
 			},
 		},
 		"all set": {
@@ -2356,32 +2356,32 @@ func TestLoadBalancerCreateOptsToSchema(t *testing.T) {
 				Algorithm:        &LoadBalancerAlgorithm{Type: LoadBalancerAlgorithmTypeRoundRobin},
 				NetworkZone:      NetworkZoneEUCentral,
 				Labels:           map[string]string{"foo": "bar"},
-				PublicInterface:  Bool(true),
+				PublicInterface:  Ptr(true),
 				Network:          &Network{ID: 3},
 				Services: []LoadBalancerCreateOptsService{
 					{
 						Protocol:        LoadBalancerServiceProtocolHTTP,
-						DestinationPort: Int(80),
-						Proxyprotocol:   Bool(true),
+						DestinationPort: Ptr(80),
+						Proxyprotocol:   Ptr(true),
 						HTTP: &LoadBalancerCreateOptsServiceHTTP{
-							CookieName:     String("keks"),
-							CookieLifetime: Duration(5 * time.Minute),
-							RedirectHTTP:   Bool(true),
-							StickySessions: Bool(true),
+							CookieName:     Ptr("keks"),
+							CookieLifetime: Ptr(5 * time.Minute),
+							RedirectHTTP:   Ptr(true),
+							StickySessions: Ptr(true),
 							Certificates:   []*Certificate{{ID: 1}, {ID: 2}},
 						},
 						HealthCheck: &LoadBalancerCreateOptsServiceHealthCheck{
 							Protocol: LoadBalancerServiceProtocolHTTP,
-							Port:     Int(80),
-							Interval: Duration(5 * time.Second),
-							Timeout:  Duration(1 * time.Second),
-							Retries:  Int(3),
+							Port:     Ptr(80),
+							Interval: Ptr(5 * time.Second),
+							Timeout:  Ptr(1 * time.Second),
+							Retries:  Ptr(3),
 							HTTP: &LoadBalancerCreateOptsServiceHealthCheckHTTP{
-								Domain:      String("example.com"),
-								Path:        String("/health"),
-								Response:    String("ok"),
+								Domain:      Ptr("example.com"),
+								Path:        Ptr("/health"),
+								Response:    Ptr("ok"),
 								StatusCodes: []string{"2??", "3??"},
-								TLS:         Bool(true),
+								TLS:         Ptr(true),
 							},
 						},
 					},
@@ -2405,37 +2405,37 @@ func TestLoadBalancerCreateOptsToSchema(t *testing.T) {
 				Algorithm: &schema.LoadBalancerCreateRequestAlgorithm{
 					Type: string(LoadBalancerAlgorithmTypeRoundRobin),
 				},
-				NetworkZone: String(string(NetworkZoneEUCentral)),
+				NetworkZone: Ptr(string(NetworkZoneEUCentral)),
 				Labels: func() *map[string]string {
 					labels := map[string]string{"foo": "bar"}
 					return &labels
 				}(),
-				PublicInterface: Bool(true),
-				Network:         Int(3),
+				PublicInterface: Ptr(true),
+				Network:         Ptr(3),
 				Services: []schema.LoadBalancerCreateRequestService{
 					{
 						Protocol:        string(LoadBalancerServiceProtocolHTTP),
-						DestinationPort: Int(80),
-						Proxyprotocol:   Bool(true),
+						DestinationPort: Ptr(80),
+						Proxyprotocol:   Ptr(true),
 						HTTP: &schema.LoadBalancerCreateRequestServiceHTTP{
-							CookieName:     String("keks"),
-							CookieLifetime: Int(5 * 60),
-							RedirectHTTP:   Bool(true),
-							StickySessions: Bool(true),
-							Certificates:   intSlice([]int{1, 2}),
+							CookieName:     Ptr("keks"),
+							CookieLifetime: Ptr(5 * 60),
+							RedirectHTTP:   Ptr(true),
+							StickySessions: Ptr(true),
+							Certificates:   Ptr([]int{1, 2}),
 						},
 						HealthCheck: &schema.LoadBalancerCreateRequestServiceHealthCheck{
 							Protocol: string(LoadBalancerServiceProtocolHTTP),
-							Port:     Int(80),
-							Interval: Int(5),
-							Timeout:  Int(1),
-							Retries:  Int(3),
+							Port:     Ptr(80),
+							Interval: Ptr(5),
+							Timeout:  Ptr(1),
+							Retries:  Ptr(3),
 							HTTP: &schema.LoadBalancerCreateRequestServiceHealthCheckHTTP{
-								Domain:      String("example.com"),
-								Path:        String("/health"),
-								Response:    String("ok"),
-								StatusCodes: stringSlice([]string{"2??", "3??"}),
-								TLS:         Bool(true),
+								Domain:      Ptr("example.com"),
+								Path:        Ptr("/health"),
+								Response:    Ptr("ok"),
+								StatusCodes: Ptr([]string{"2??", "3??"}),
+								TLS:         Ptr(true),
 							},
 						},
 					},
@@ -2484,53 +2484,53 @@ func TestLoadBalancerAddServiceOptsToSchema(t *testing.T) {
 		"all set": {
 			Opts: LoadBalancerAddServiceOpts{
 				Protocol:        LoadBalancerServiceProtocolHTTP,
-				DestinationPort: Int(80),
-				Proxyprotocol:   Bool(true),
+				DestinationPort: Ptr(80),
+				Proxyprotocol:   Ptr(true),
 				HTTP: &LoadBalancerAddServiceOptsHTTP{
-					CookieName:     String("keks"),
-					CookieLifetime: Duration(5 * time.Minute),
-					RedirectHTTP:   Bool(true),
-					StickySessions: Bool(true),
+					CookieName:     Ptr("keks"),
+					CookieLifetime: Ptr(5 * time.Minute),
+					RedirectHTTP:   Ptr(true),
+					StickySessions: Ptr(true),
 					Certificates:   []*Certificate{{ID: 1}, {ID: 2}},
 				},
 				HealthCheck: &LoadBalancerAddServiceOptsHealthCheck{
 					Protocol: LoadBalancerServiceProtocolHTTP,
-					Port:     Int(80),
-					Interval: Duration(5 * time.Second),
-					Timeout:  Duration(1 * time.Second),
-					Retries:  Int(3),
+					Port:     Ptr(80),
+					Interval: Ptr(5 * time.Second),
+					Timeout:  Ptr(1 * time.Second),
+					Retries:  Ptr(3),
 					HTTP: &LoadBalancerAddServiceOptsHealthCheckHTTP{
-						Domain:      String("example.com"),
-						Path:        String("/health"),
-						Response:    String("ok"),
+						Domain:      Ptr("example.com"),
+						Path:        Ptr("/health"),
+						Response:    Ptr("ok"),
 						StatusCodes: []string{"2??", "3??"},
-						TLS:         Bool(true),
+						TLS:         Ptr(true),
 					},
 				},
 			},
 			Request: schema.LoadBalancerActionAddServiceRequest{
 				Protocol:        string(LoadBalancerServiceProtocolHTTP),
-				DestinationPort: Int(80),
-				Proxyprotocol:   Bool(true),
+				DestinationPort: Ptr(80),
+				Proxyprotocol:   Ptr(true),
 				HTTP: &schema.LoadBalancerActionAddServiceRequestHTTP{
-					CookieName:     String("keks"),
-					CookieLifetime: Int(5 * 60),
-					RedirectHTTP:   Bool(true),
-					StickySessions: Bool(true),
-					Certificates:   intSlice([]int{1, 2}),
+					CookieName:     Ptr("keks"),
+					CookieLifetime: Ptr(5 * 60),
+					RedirectHTTP:   Ptr(true),
+					StickySessions: Ptr(true),
+					Certificates:   Ptr([]int{1, 2}),
 				},
 				HealthCheck: &schema.LoadBalancerActionAddServiceRequestHealthCheck{
 					Protocol: string(LoadBalancerServiceProtocolHTTP),
-					Port:     Int(80),
-					Interval: Int(5),
-					Timeout:  Int(1),
-					Retries:  Int(3),
+					Port:     Ptr(80),
+					Interval: Ptr(5),
+					Timeout:  Ptr(1),
+					Retries:  Ptr(3),
 					HTTP: &schema.LoadBalancerActionAddServiceRequestHealthCheckHTTP{
-						Domain:      String("example.com"),
-						Path:        String("/health"),
-						Response:    String("ok"),
-						StatusCodes: stringSlice([]string{"2??", "3??"}),
-						TLS:         Bool(true),
+						Domain:      Ptr("example.com"),
+						Path:        Ptr("/health"),
+						Response:    Ptr("ok"),
+						StatusCodes: Ptr([]string{"2??", "3??"}),
+						TLS:         Ptr(true),
 					},
 				},
 			},
@@ -2538,26 +2538,26 @@ func TestLoadBalancerAddServiceOptsToSchema(t *testing.T) {
 		"no health check": {
 			Opts: LoadBalancerAddServiceOpts{
 				Protocol:        LoadBalancerServiceProtocolHTTP,
-				DestinationPort: Int(80),
-				Proxyprotocol:   Bool(true),
+				DestinationPort: Ptr(80),
+				Proxyprotocol:   Ptr(true),
 				HTTP: &LoadBalancerAddServiceOptsHTTP{
-					CookieName:     String("keks"),
-					CookieLifetime: Duration(5 * time.Minute),
-					RedirectHTTP:   Bool(true),
-					StickySessions: Bool(true),
+					CookieName:     Ptr("keks"),
+					CookieLifetime: Ptr(5 * time.Minute),
+					RedirectHTTP:   Ptr(true),
+					StickySessions: Ptr(true),
 					Certificates:   []*Certificate{{ID: 1}, {ID: 2}},
 				},
 			},
 			Request: schema.LoadBalancerActionAddServiceRequest{
 				Protocol:        string(LoadBalancerServiceProtocolHTTP),
-				DestinationPort: Int(80),
-				Proxyprotocol:   Bool(true),
+				DestinationPort: Ptr(80),
+				Proxyprotocol:   Ptr(true),
 				HTTP: &schema.LoadBalancerActionAddServiceRequestHTTP{
-					CookieName:     String("keks"),
-					CookieLifetime: Int(5 * 60),
-					RedirectHTTP:   Bool(true),
-					StickySessions: Bool(true),
-					Certificates:   intSlice([]int{1, 2}),
+					CookieName:     Ptr("keks"),
+					CookieLifetime: Ptr(5 * 60),
+					RedirectHTTP:   Ptr(true),
+					StickySessions: Ptr(true),
+					Certificates:   Ptr([]int{1, 2}),
 				},
 				HealthCheck: nil,
 			},
@@ -2586,53 +2586,53 @@ func TestLoadBalancerUpdateServiceOptsToSchema(t *testing.T) {
 		"all set": {
 			Opts: LoadBalancerUpdateServiceOpts{
 				Protocol:        LoadBalancerServiceProtocolHTTP,
-				DestinationPort: Int(80),
-				Proxyprotocol:   Bool(true),
+				DestinationPort: Ptr(80),
+				Proxyprotocol:   Ptr(true),
 				HTTP: &LoadBalancerUpdateServiceOptsHTTP{
-					CookieName:     String("keks"),
-					CookieLifetime: Duration(5 * time.Minute),
-					RedirectHTTP:   Bool(true),
-					StickySessions: Bool(true),
+					CookieName:     Ptr("keks"),
+					CookieLifetime: Ptr(5 * time.Minute),
+					RedirectHTTP:   Ptr(true),
+					StickySessions: Ptr(true),
 					Certificates:   []*Certificate{{ID: 1}, {ID: 2}},
 				},
 				HealthCheck: &LoadBalancerUpdateServiceOptsHealthCheck{
 					Protocol: LoadBalancerServiceProtocolHTTP,
-					Port:     Int(80),
-					Interval: Duration(5 * time.Second),
-					Timeout:  Duration(1 * time.Second),
-					Retries:  Int(3),
+					Port:     Ptr(80),
+					Interval: Ptr(5 * time.Second),
+					Timeout:  Ptr(1 * time.Second),
+					Retries:  Ptr(3),
 					HTTP: &LoadBalancerUpdateServiceOptsHealthCheckHTTP{
-						Domain:      String("example.com"),
-						Path:        String("/health"),
-						Response:    String("ok"),
+						Domain:      Ptr("example.com"),
+						Path:        Ptr("/health"),
+						Response:    Ptr("ok"),
 						StatusCodes: []string{"2??", "3??"},
-						TLS:         Bool(true),
+						TLS:         Ptr(true),
 					},
 				},
 			},
 			Request: schema.LoadBalancerActionUpdateServiceRequest{
-				Protocol:        String(string(LoadBalancerServiceProtocolHTTP)),
-				DestinationPort: Int(80),
-				Proxyprotocol:   Bool(true),
+				Protocol:        Ptr(string(LoadBalancerServiceProtocolHTTP)),
+				DestinationPort: Ptr(80),
+				Proxyprotocol:   Ptr(true),
 				HTTP: &schema.LoadBalancerActionUpdateServiceRequestHTTP{
-					CookieName:     String("keks"),
-					CookieLifetime: Int(5 * 60),
-					RedirectHTTP:   Bool(true),
-					StickySessions: Bool(true),
-					Certificates:   intSlice([]int{1, 2}),
+					CookieName:     Ptr("keks"),
+					CookieLifetime: Ptr(5 * 60),
+					RedirectHTTP:   Ptr(true),
+					StickySessions: Ptr(true),
+					Certificates:   Ptr([]int{1, 2}),
 				},
 				HealthCheck: &schema.LoadBalancerActionUpdateServiceRequestHealthCheck{
-					Protocol: String(string(LoadBalancerServiceProtocolHTTP)),
-					Port:     Int(80),
-					Interval: Int(5),
-					Timeout:  Int(1),
-					Retries:  Int(3),
+					Protocol: Ptr(string(LoadBalancerServiceProtocolHTTP)),
+					Port:     Ptr(80),
+					Interval: Ptr(5),
+					Timeout:  Ptr(1),
+					Retries:  Ptr(3),
 					HTTP: &schema.LoadBalancerActionUpdateServiceRequestHealthCheckHTTP{
-						Domain:      String("example.com"),
-						Path:        String("/health"),
-						Response:    String("ok"),
-						StatusCodes: stringSlice([]string{"2??", "3??"}),
-						TLS:         Bool(true),
+						Domain:      Ptr("example.com"),
+						Path:        Ptr("/health"),
+						Response:    Ptr("ok"),
+						StatusCodes: Ptr([]string{"2??", "3??"}),
+						TLS:         Ptr(true),
 					},
 				},
 			},
@@ -2640,26 +2640,26 @@ func TestLoadBalancerUpdateServiceOptsToSchema(t *testing.T) {
 		"no health check": {
 			Opts: LoadBalancerUpdateServiceOpts{
 				Protocol:        LoadBalancerServiceProtocolHTTP,
-				DestinationPort: Int(80),
-				Proxyprotocol:   Bool(true),
+				DestinationPort: Ptr(80),
+				Proxyprotocol:   Ptr(true),
 				HTTP: &LoadBalancerUpdateServiceOptsHTTP{
-					CookieName:     String("keks"),
-					CookieLifetime: Duration(5 * time.Minute),
-					RedirectHTTP:   Bool(true),
-					StickySessions: Bool(true),
+					CookieName:     Ptr("keks"),
+					CookieLifetime: Ptr(5 * time.Minute),
+					RedirectHTTP:   Ptr(true),
+					StickySessions: Ptr(true),
 					Certificates:   []*Certificate{{ID: 1}, {ID: 2}},
 				},
 			},
 			Request: schema.LoadBalancerActionUpdateServiceRequest{
-				Protocol:        String(string(LoadBalancerServiceProtocolHTTP)),
-				DestinationPort: Int(80),
-				Proxyprotocol:   Bool(true),
+				Protocol:        Ptr(string(LoadBalancerServiceProtocolHTTP)),
+				DestinationPort: Ptr(80),
+				Proxyprotocol:   Ptr(true),
 				HTTP: &schema.LoadBalancerActionUpdateServiceRequestHTTP{
-					CookieName:     String("keks"),
-					CookieLifetime: Int(5 * 60),
-					RedirectHTTP:   Bool(true),
-					StickySessions: Bool(true),
-					Certificates:   intSlice([]int{1, 2}),
+					CookieName:     Ptr("keks"),
+					CookieLifetime: Ptr(5 * 60),
+					RedirectHTTP:   Ptr(true),
+					StickySessions: Ptr(true),
+					Certificates:   Ptr([]int{1, 2}),
 				},
 				HealthCheck: nil,
 			},
diff --git a/hcloud/server_test.go b/hcloud/server_test.go
index 672b8ec..2a3de4b 100644
--- a/hcloud/server_test.go
+++ b/hcloud/server_test.go
@@ -341,7 +341,7 @@ func TestServersCreateWithoutSSHKeys(t *testing.T) {
 			Server: schema.Server{
 				ID: 1,
 			},
-			RootPassword: String("test"),
+			RootPassword: Ptr("test"),
 		})
 	})
 
@@ -399,7 +399,7 @@ func TestServersCreateWithVolumes(t *testing.T) {
 			{ID: 1},
 			{ID: 2},
 		},
-		Automount: Bool(true),
+		Automount: Ptr(true),
 	})
 	if err != nil {
 		t.Fatal(err)
@@ -846,7 +846,7 @@ func TestServersCreateWithLabels(t *testing.T) {
 			Server: schema.Server{
 				ID: 1,
 			},
-			RootPassword: String("test"),
+			RootPassword: Ptr("test"),
 		})
 	})
 
@@ -892,7 +892,7 @@ func TestServersCreateWithoutStarting(t *testing.T) {
 		Name:             "test",
 		ServerType:       &ServerType{ID: 1},
 		Image:            &Image{ID: 2},
-		StartAfterCreate: Bool(false),
+		StartAfterCreate: Ptr(false),
 	})
 	if err != nil {
 		t.Fatal(err)
@@ -1373,7 +1373,7 @@ func TestServerClientCreateImageWithOptions(t *testing.T) {
 	ctx := context.Background()
 	opts := &ServerCreateImageOpts{
 		Type:        ImageTypeBackup,
-		Description: String("my backup"),
+		Description: Ptr("my backup"),
 	}
 	result, _, err := env.Client.Server.CreateImage(ctx, &Server{ID: 1}, opts)
 	if err != nil {
@@ -1810,8 +1810,8 @@ func TestServerClientChangeProtection(t *testing.T) {
 		})
 
 		opts := ServerChangeProtectionOpts{
-			Delete:  Bool(true),
-			Rebuild: Bool(true),
+			Delete:  Ptr(true),
+			Rebuild: Ptr(true),
 		}
 		action, _, err := env.Client.Server.ChangeProtection(ctx, server, opts)
 		if err != nil {
diff --git a/hcloud/volume_test.go b/hcloud/volume_test.go
index fdb046b..025ee17 100644
--- a/hcloud/volume_test.go
+++ b/hcloud/volume_test.go
@@ -438,8 +438,8 @@ func TestVolumeClientCreateWithAutomount(t *testing.T) {
 		Size:      42,
 		Server:    &Server{ID: 1},
 		Labels:    map[string]string{"key": "value"},
-		Automount: Bool(true),
-		Format:    String("xfs"),
+		Automount: Ptr(true),
+		Format:    Ptr("xfs"),
 	}
 	result, _, err := env.Client.Volume.Create(ctx, opts)
 	if err != nil {