diff --git a/CHANGELOG.md b/CHANGELOG.md index 5afb5cb..34d4011 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - The supported weg.li-API spec as Swagger 2.0 json format was added. +### Changed + +- The endpoints for listing charges and districs and getting a district by ZIP were changed to reflect the latest API changes. + ## [0.3.0 - 2024-03-07](https://github.com/Art4/wegliphant/compare/0.2.0...0.3.0) ### Added diff --git a/README.md b/README.md index 9e28db2..af4fc59 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ - API Docs: https://www.weg.li/api - API Source: https://www.weg.li/apidocs.json -- API Version: https://github.com/weg-li/weg-li/tree/c1b13d731cba72b18a221c9b6c71324d78614bd2 -- API Datetime: 2024-03-06T09:21:36Z +- API Version: https://github.com/weg-li/weg-li/tree/9247d97012486a052e0a326bec83e754ace750a6 +- API Datetime: 2024-03-22T08:19:09Z Requires: PHP ^8.1 diff --git a/src/Client.php b/src/Client.php index 5cc86e3..e902998 100644 --- a/src/Client.php +++ b/src/Client.php @@ -34,7 +34,7 @@ public function authenticate(string $apiKey): void } /** - * List all districts using the endpoint `GET /districts.json` + * List all districts using the endpoint `GET /api/districts` * * @link https://www.weg.li/api * @@ -45,13 +45,13 @@ public function authenticate(string $apiKey): void */ public function listDistricts(): array { - $response = $this->sendJsonRequest('GET', '/districts.json'); + $response = $this->sendJsonRequest('GET', '/api/districts'); return $this->parseJsonResponseToArray($response, 200); } /** - * Get one district by ZIP using the endpoint `GET /districts/.json` + * Get one district by ZIP using the endpoint `GET /api/districts/` * * @link https://www.weg.li/api * @@ -62,13 +62,13 @@ public function listDistricts(): array */ public function getDistrictByZip(string $zip): array { - $response = $this->sendJsonRequest('GET', '/districts/' . $zip . '.json'); + $response = $this->sendJsonRequest('GET', '/api/districts/' . $zip); return $this->parseJsonResponseToArray($response, 200); } /** - * List all charges using the endpoint `GET /charges.json` + * List all charges using the endpoint `GET /api/charges` * * @link https://www.weg.li/api * @@ -79,7 +79,7 @@ public function getDistrictByZip(string $zip): array */ public function listCharges(): array { - $response = $this->sendJsonRequest('GET', '/charges.json'); + $response = $this->sendJsonRequest('GET', '/api/charges'); return $this->parseJsonResponseToArray($response, 200); } diff --git a/tests/Unit/Client/AuthenticateTest.php b/tests/Unit/Client/AuthenticateTest.php index 977febd..1eb37c7 100644 --- a/tests/Unit/Client/AuthenticateTest.php +++ b/tests/Unit/Client/AuthenticateTest.php @@ -28,7 +28,7 @@ public function testAuthenticateSetsCorrectHeader(): void ]); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/districts.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/districts')->willReturn($request); $stream = $this->createConfiguredMock( StreamInterface::class, diff --git a/tests/Unit/Client/GetDistrictByZipTest.php b/tests/Unit/Client/GetDistrictByZipTest.php index 150767d..7d16503 100644 --- a/tests/Unit/Client/GetDistrictByZipTest.php +++ b/tests/Unit/Client/GetDistrictByZipTest.php @@ -35,11 +35,16 @@ public function testGetDistrictByZipReturnsArray(): void 'updated_at' => '2020-03-06T17:53:09.034+01:00', ]; + $apiKey = 'c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2'; + $request = $this->createMock(RequestInterface::class); - $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); + $request->expects($this->exactly(2))->method('withHeader')->willReturnMap([ + ['Accept', 'application/json', $request], + ['X-API-KEY', $apiKey, $request], + ]); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/districts/12305.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/districts/12305')->willReturn($request); $stream = $this->createConfiguredMock( StreamInterface::class, @@ -64,6 +69,7 @@ public function testGetDistrictByZipReturnsArray(): void $httpClient, $requestFactory, ); + $client->authenticate($apiKey); $response = $client->getDistrictByZip('12305'); @@ -75,11 +81,16 @@ public function testGetDistrictByZipReturnsArray(): void public function testGetDistrictByZipThrowsClientException(): void { + $apiKey = 'c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2'; + $request = $this->createMock(RequestInterface::class); - $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); + $request->expects($this->exactly(2))->method('withHeader')->willReturnMap([ + ['Accept', 'application/json', $request], + ['X-API-KEY', $apiKey, $request], + ]); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/districts/12305.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/districts/12305')->willReturn($request); $httpClient = $this->createMock(ClientInterface::class); $httpClient->expects($this->exactly(1))->method('sendRequest')->willThrowException( @@ -90,6 +101,7 @@ public function testGetDistrictByZipThrowsClientException(): void $httpClient, $requestFactory, ); + $client->authenticate($apiKey); $this->expectException(ClientExceptionInterface::class); $this->expectExceptionMessage(''); @@ -103,12 +115,12 @@ public function testGetDistrictByZipThrowsUnexpectedResponseExceptionOnWrongStat $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/districts/00000.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/districts/00000')->willReturn($request); $response = $this->createConfiguredMock( ResponseInterface::class, [ - 'getStatusCode' => 500, + 'getStatusCode' => 401, ] ); @@ -121,7 +133,7 @@ public function testGetDistrictByZipThrowsUnexpectedResponseExceptionOnWrongStat ); $this->expectException(UnexpectedResponseException::class); - $this->expectExceptionMessage('Server replied with the status code 500, but 200 was expected.'); + $this->expectExceptionMessage('Server replied with the status code 401, but 200 was expected.'); $client->getDistrictByZip('00000'); } @@ -132,7 +144,7 @@ public function testGetDistrictByZipThrowsUnexpectedResponseExceptionOnWrongCont $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/districts/12305.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/districts/12305')->willReturn($request); $response = $this->createConfiguredMock( ResponseInterface::class, @@ -162,7 +174,7 @@ public function testGetDistrictByZipThrowsUnexpectedResponseExceptionOnInvalidJs $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/districts/12305.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/districts/12305')->willReturn($request); $stream = $this->createConfiguredMock( StreamInterface::class, @@ -200,7 +212,7 @@ public function testGetDistrictByZipThrowsUnexpectedResponseExceptionOnJsonBodyW $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/districts/12305.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/districts/12305')->willReturn($request); $stream = $this->createConfiguredMock( StreamInterface::class, diff --git a/tests/Unit/Client/ListChargesTest.php b/tests/Unit/Client/ListChargesTest.php index 8247f53..22caf3d 100644 --- a/tests/Unit/Client/ListChargesTest.php +++ b/tests/Unit/Client/ListChargesTest.php @@ -107,11 +107,16 @@ public function testListChargesReturnsArray(): void ], ]; + $apiKey = 'c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2'; + $request = $this->createMock(RequestInterface::class); - $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); + $request->expects($this->exactly(2))->method('withHeader')->willReturnMap([ + ['Accept', 'application/json', $request], + ['X-API-KEY', $apiKey, $request], + ]); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/charges.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/charges')->willReturn($request); $stream = $this->createConfiguredMock( StreamInterface::class, @@ -136,6 +141,7 @@ public function testListChargesReturnsArray(): void $httpClient, $requestFactory, ); + $client->authenticate($apiKey); $response = $client->listCharges(); @@ -147,11 +153,16 @@ public function testListChargesReturnsArray(): void public function testListChargesThrowsClientException(): void { + $apiKey = 'c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2'; + $request = $this->createMock(RequestInterface::class); - $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); + $request->expects($this->exactly(2))->method('withHeader')->willReturnMap([ + ['Accept', 'application/json', $request], + ['X-API-KEY', $apiKey, $request], + ]); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/charges.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/charges')->willReturn($request); $httpClient = $this->createMock(ClientInterface::class); $httpClient->expects($this->exactly(1))->method('sendRequest')->willThrowException( @@ -162,6 +173,7 @@ public function testListChargesThrowsClientException(): void $httpClient, $requestFactory, ); + $client->authenticate($apiKey); $this->expectException(ClientExceptionInterface::class); $this->expectExceptionMessage(''); @@ -175,12 +187,12 @@ public function testListChargesThrowsUnexpectedResponseExceptionOnWrongStatusCod $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/charges.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/charges')->willReturn($request); $response = $this->createConfiguredMock( ResponseInterface::class, [ - 'getStatusCode' => 500, + 'getStatusCode' => 401, ] ); @@ -193,7 +205,7 @@ public function testListChargesThrowsUnexpectedResponseExceptionOnWrongStatusCod ); $this->expectException(UnexpectedResponseException::class); - $this->expectExceptionMessage('Server replied with the status code 500, but 200 was expected.'); + $this->expectExceptionMessage('Server replied with the status code 401, but 200 was expected.'); $client->listCharges(); } @@ -204,7 +216,7 @@ public function testListChargesThrowsUnexpectedResponseExceptionOnWrongContentTy $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/charges.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/charges')->willReturn($request); $response = $this->createConfiguredMock( ResponseInterface::class, @@ -234,7 +246,7 @@ public function testListChargesThrowsUnexpectedResponseExceptionOnInvalidJsonBod $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/charges.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/charges')->willReturn($request); $stream = $this->createConfiguredMock( StreamInterface::class, @@ -272,7 +284,7 @@ public function testListChargesThrowsUnexpectedResponseExceptionOnJsonBodyWithou $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/charges.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/charges')->willReturn($request); $stream = $this->createConfiguredMock( StreamInterface::class, diff --git a/tests/Unit/Client/ListDistrictsTest.php b/tests/Unit/Client/ListDistrictsTest.php index 66a774f..8e3616b 100644 --- a/tests/Unit/Client/ListDistrictsTest.php +++ b/tests/Unit/Client/ListDistrictsTest.php @@ -65,11 +65,16 @@ public function testListDistrictsReturnsArray(): void ], ]; + $apiKey = 'c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2'; + $request = $this->createMock(RequestInterface::class); - $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); + $request->expects($this->exactly(2))->method('withHeader')->willReturnMap([ + ['Accept', 'application/json', $request], + ['X-API-KEY', $apiKey, $request], + ]); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/districts.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/districts')->willReturn($request); $stream = $this->createConfiguredMock( StreamInterface::class, @@ -94,6 +99,7 @@ public function testListDistrictsReturnsArray(): void $httpClient, $requestFactory, ); + $client->authenticate($apiKey); $response = $client->listDistricts(); @@ -105,11 +111,16 @@ public function testListDistrictsReturnsArray(): void public function testListDistrictsThrowsClientException(): void { + $apiKey = 'c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2'; + $request = $this->createMock(RequestInterface::class); - $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); + $request->expects($this->exactly(2))->method('withHeader')->willReturnMap([ + ['Accept', 'application/json', $request], + ['X-API-KEY', $apiKey, $request], + ]); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/districts.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/districts')->willReturn($request); $httpClient = $this->createMock(ClientInterface::class); $httpClient->expects($this->exactly(1))->method('sendRequest')->willThrowException( @@ -120,6 +131,7 @@ public function testListDistrictsThrowsClientException(): void $httpClient, $requestFactory, ); + $client->authenticate($apiKey); $this->expectException(ClientExceptionInterface::class); $this->expectExceptionMessage(''); @@ -133,12 +145,12 @@ public function testListDistrictsThrowsUnexpectedResponseExceptionOnWrongStatusC $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/districts.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/districts')->willReturn($request); $response = $this->createConfiguredMock( ResponseInterface::class, [ - 'getStatusCode' => 500, + 'getStatusCode' => 401, ] ); @@ -151,7 +163,7 @@ public function testListDistrictsThrowsUnexpectedResponseExceptionOnWrongStatusC ); $this->expectException(UnexpectedResponseException::class); - $this->expectExceptionMessage('Server replied with the status code 500, but 200 was expected.'); + $this->expectExceptionMessage('Server replied with the status code 401, but 200 was expected.'); $client->listDistricts(); } @@ -162,7 +174,7 @@ public function testListDistrictsThrowsUnexpectedResponseExceptionOnWrongContent $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/districts.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/districts')->willReturn($request); $response = $this->createConfiguredMock( ResponseInterface::class, @@ -192,7 +204,7 @@ public function testListDistrictsThrowsUnexpectedResponseExceptionOnInvalidJsonB $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/districts.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/districts')->willReturn($request); $stream = $this->createConfiguredMock( StreamInterface::class, @@ -230,7 +242,7 @@ public function testListDistrictsThrowsUnexpectedResponseExceptionOnJsonBodyWith $request->expects($this->exactly(1))->method('withHeader')->willReturn($request); $requestFactory = $this->createMock(RequestFactoryInterface::class); - $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/districts.json')->willReturn($request); + $requestFactory->expects($this->exactly(1))->method('createRequest')->with('GET', 'https://www.weg.li/api/districts')->willReturn($request); $stream = $this->createConfiguredMock( StreamInterface::class, diff --git a/tests/spec/apidocs.json b/tests/spec/apidocs.json index e7e76e4..382b4df 100644 --- a/tests/spec/apidocs.json +++ b/tests/spec/apidocs.json @@ -13,7 +13,7 @@ } ], "info": { - "version": "1.0.0+c1b13d731cba72b18a221c9b6c71324d78614bd2", + "version": "1.0.0+9247d97012486a052e0a326bec83e754ace750a6", "title": "weg.li API Docs", "description": "\n The weg.li API allows an authorized user to manage notices, upload photos and notify the authorities.\n\n The API-KEY can be obtained via the profile page https://www.weg.li/user\n\n Creating a notice requires creating uploads for each photo previously and uploading the binary data through a presigned URL to the gcloud.\n\n So in order to create a notice the client needs to follow those steps:\n 1. Create a new upload using the filename, the size in bytes of the file, the MD5 base64 Digest of the file and the content-type image/jpeg\n 2. Use the response fields 'url' and 'headers' in order to upload the binary data via PUT request\n 3. Repeat for every photo\n 4. Create notice using signed_id keys of the uploads created as the values to the photos array of the notice\n\n An example Implementation can be found here https://github.com/weg-li/weg-li/blob/master/api_usage_example\n ", "termsOfService": "https://www.weg.li/privacy/", @@ -51,6 +51,122 @@ "application/json" ], "paths": { + "/charges": { + "get": { + "summary": "Get all Charges", + "description": "Returns a list of all charges", + "tags": [ + "charge" + ], + "responses": { + "200": { + "description": "charge response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Charge" + } + } + }, + "default": { + "description": "unexpected error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + } + }, + "/charges/{tbnr}": { + "get": { + "summary": "Get Chage", + "description": "Gets a charge for given tbnr/id", + "tags": [ + "charge" + ], + "parameters": [ + { + "name": "tbnr", + "in": "path", + "description": "TBNR of notice", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "charge response", + "schema": { + "$ref": "#/definitions/Charge" + } + }, + "default": { + "description": "unexpected error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + } + }, + "/districts": { + "get": { + "summary": "Get all Districts", + "description": "Returns a list of all districts", + "tags": [ + "district" + ], + "responses": { + "200": { + "description": "district response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/District" + } + } + }, + "default": { + "description": "unexpected error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + } + }, + "/districts/{zip}": { + "get": { + "summary": "Get District", + "description": "Gets a district for given zip/id", + "tags": [ + "district" + ], + "parameters": [ + { + "name": "zip", + "in": "path", + "description": "Zip of notice", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "district response", + "schema": { + "$ref": "#/definitions/District" + } + }, + "default": { + "description": "unexpected error", + "schema": { + "$ref": "#/definitions/Error" + } + } + } + } + }, "/notices": { "get": { "summary": "Get all Notices", @@ -279,6 +395,113 @@ } }, "definitions": { + "Charge": { + "properties": { + "tbnr": { + "type": "string", + "pattern": "^\\d{6}$" + }, + "description": { + "type": "string" + }, + "fine": { + "type": "number", + "format": "float" + }, + "bkat": { + "type": "string" + }, + "penalty": { + "type": "string" + }, + "fap": { + "type": "string" + }, + "points": { + "type": "string" + }, + "valid_from": { + "type": "string", + "format": "date-time" + }, + "valid_to": { + "type": "string", + "format": "date-time" + }, + "implementation": { + "type": "string" + }, + "classification": { + "type": "string" + }, + "rule_id": { + "type": "string" + }, + "table_id": { + "type": "string" + }, + "required_refinements": { + "type": "string" + }, + "max_fine": { + "type": "string" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + } + } + }, + "District": { + "properties": { + "name": { + "type": "string" + }, + "zip": { + "type": "string", + "pattern": "^\\d{5}$" + }, + "email": { + "type": "string", + "pattern": ".+@.+\\..+" + }, + "latitude": { + "type": "number", + "format": "float" + }, + "longitude": { + "type": "number", + "format": "float" + }, + "personal_email": { + "type": "boolean" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "aliases": { + "type": "array", + "items": { + "type": "string" + } + }, + "prefixes": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "Notice": { "properties": { "token": {