Skip to content

Commit a5b807e

Browse files
author
Jonathan Visser
committed
Add support for listing backups (GET /v2/app/{app}/backup/)
1 parent 0987c68 commit a5b807e

3 files changed

Lines changed: 184 additions & 0 deletions

File tree

src/HypernodeClient.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Hypernode\Api\Exception\HypernodeApiServerException;
1010
use Hypernode\Api\Service\Addon;
1111
use Hypernode\Api\Service\App;
12+
use Hypernode\Api\Service\Backup;
1213
use Hypernode\Api\Service\BrancherApp;
1314
use Hypernode\Api\Service\Logbook;
1415
use Hypernode\Api\Service\Settings;
@@ -19,6 +20,7 @@ class HypernodeClient
1920
public HttpMethodsClientInterface $api;
2021
public Addon $addon;
2122
public App $app;
23+
public Backup $backup;
2224
public BrancherApp $brancherApp;
2325
public Settings $settings;
2426
public Logbook $logbook;
@@ -28,6 +30,7 @@ public function __construct(HttpMethodsClientInterface $apiClient)
2830
$this->api = $apiClient;
2931
$this->addon = new Addon($this);
3032
$this->app = new App($this);
33+
$this->backup = new Backup($this);
3134
$this->brancherApp = new BrancherApp($this);
3235
$this->settings = new Settings($this);
3336
$this->logbook = new Logbook($this);

src/Service/Backup.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Hypernode\Api\Service;
6+
7+
use Hypernode\Api\Exception\HypernodeApiClientException;
8+
use Hypernode\Api\Exception\HypernodeApiServerException;
9+
10+
class Backup extends AbstractService
11+
{
12+
public const V2_APP_BACKUP_URL = "/v2/app/%s/backup/";
13+
14+
/**
15+
* Show all backups that are currently available for the given Hypernode.
16+
*
17+
* @param string $app Name of the Hypernode
18+
* @param array $params Query parameters, e.g. limit and offset
19+
* @return array List of backups
20+
* @throws HypernodeApiClientException
21+
* @throws HypernodeApiServerException
22+
*/
23+
public function getList(string $app, array $params = []): array
24+
{
25+
$backups = [];
26+
27+
$requestUrl = sprintf(self::V2_APP_BACKUP_URL, $app);
28+
if ($params) {
29+
$requestUrl .= '?' . http_build_query($params);
30+
}
31+
32+
while ($requestUrl) {
33+
$response = $this->client->api->get($requestUrl);
34+
35+
$this->client->maybeThrowApiExceptions($response);
36+
$data = $this->client->getJsonFromResponse($response);
37+
38+
foreach ($data['results'] as $item) {
39+
$backups[] = $item;
40+
}
41+
42+
$requestUrl = $data['next'];
43+
}
44+
45+
return $backups;
46+
}
47+
}

tests/unit/Service/BackupTest.php

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Hypernode\Api\Service;
6+
7+
use GuzzleHttp\Psr7\Response;
8+
use Hypernode\Api\Exception\HypernodeApiClientException;
9+
use Hypernode\Api\Exception\HypernodeApiServerException;
10+
use Hypernode\Api\HypernodeClientTestCase;
11+
12+
class BackupTest extends HypernodeClientTestCase
13+
{
14+
public function testGetList()
15+
{
16+
$backups = [
17+
[
18+
'backup_id' => 'backup-123',
19+
'type' => 'periodic',
20+
'backup_created_at' => '2026-07-14T01:00:00Z',
21+
'expired_at' => '2026-07-28T01:00:00Z',
22+
],
23+
[
24+
'backup_id' => 'backup-456',
25+
'type' => 'instant',
26+
'backup_created_at' => '2026-07-15T09:30:00Z',
27+
'expired_at' => '2026-07-29T09:30:00Z',
28+
],
29+
];
30+
$this->responses->append(
31+
new Response(200, [], json_encode([
32+
'count' => 2,
33+
'next' => null,
34+
'previous' => null,
35+
'results' => $backups,
36+
])),
37+
);
38+
39+
$result = $this->client->backup->getList('johndoe');
40+
41+
$request = $this->responses->getLastRequest();
42+
$this->assertEquals('GET', $request->getMethod());
43+
$this->assertEquals('/v2/app/johndoe/backup/', $request->getUri());
44+
$this->assertEquals($backups, $result);
45+
}
46+
47+
public function testGetListAcceptsParams()
48+
{
49+
$this->responses->append(
50+
new Response(200, [], json_encode([
51+
'count' => 0,
52+
'next' => null,
53+
'previous' => null,
54+
'results' => [],
55+
])),
56+
);
57+
58+
$result = $this->client->backup->getList('johndoe', ['limit' => 10, 'offset' => 20]);
59+
60+
$request = $this->responses->getLastRequest();
61+
$this->assertEquals('GET', $request->getMethod());
62+
$this->assertEquals('/v2/app/johndoe/backup/?limit=10&offset=20', $request->getUri());
63+
$this->assertEquals([], $result);
64+
}
65+
66+
public function testGetListPaginates()
67+
{
68+
$this->responses->append(
69+
new Response(200, [], json_encode([
70+
'count' => 2,
71+
'next' => 'https://api.hypernode.com/v2/app/johndoe/backup/?limit=1&offset=1',
72+
'previous' => null,
73+
'results' => [
74+
[
75+
'backup_id' => 'backup-123',
76+
'type' => 'periodic',
77+
'backup_created_at' => '2026-07-14T01:00:00Z',
78+
'expired_at' => '2026-07-28T01:00:00Z',
79+
],
80+
],
81+
])),
82+
new Response(200, [], json_encode([
83+
'count' => 2,
84+
'next' => null,
85+
'previous' => null,
86+
'results' => [
87+
[
88+
'backup_id' => 'backup-456',
89+
'type' => 'instant',
90+
'backup_created_at' => '2026-07-15T09:30:00Z',
91+
'expired_at' => '2026-07-29T09:30:00Z',
92+
],
93+
],
94+
])),
95+
);
96+
97+
$result = $this->client->backup->getList('johndoe');
98+
99+
$this->assertCount(2, $result);
100+
$this->assertEquals('backup-123', $result[0]['backup_id']);
101+
$this->assertEquals('backup-456', $result[1]['backup_id']);
102+
103+
$request = $this->responses->getLastRequest();
104+
$this->assertEquals('GET', $request->getMethod());
105+
$this->assertEquals(
106+
'https://api.hypernode.com/v2/app/johndoe/backup/?limit=1&offset=1',
107+
$request->getUri()
108+
);
109+
}
110+
111+
public function testGetListRaisesClientExceptions()
112+
{
113+
$badRequestResponse = new Response(400, [], json_encode([
114+
'non_field_errors' => ['Your request was invalid.']
115+
]));
116+
$this->responses->append($badRequestResponse);
117+
118+
$this->expectExceptionObject(new HypernodeApiClientException($badRequestResponse));
119+
120+
$this->client->backup->getList('johndoe');
121+
}
122+
123+
public function testGetListRaisesServerExceptions()
124+
{
125+
$badRequestResponse = new Response(500, [], json_encode([
126+
'non_field_errors' => ['Something went wrong processing your request.']
127+
]));
128+
$this->responses->append($badRequestResponse);
129+
130+
$this->expectExceptionObject(new HypernodeApiServerException($badRequestResponse));
131+
132+
$this->client->backup->getList('johndoe');
133+
}
134+
}

0 commit comments

Comments
 (0)