Skip to content

Commit 151a4b9

Browse files
Release v2.1.2 - Fix composer.json and add proper versioning
### Fixed - Added explicit version field to composer.json for proper Packagist versioning - Added autoload-dev section for test classes - Updated package description to include all supported cities ### Changed - Updated VERSION constant to 2.1.2 ### Added - CHANGELOG.md - HTTP client abstraction layer - Additional test files Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent c49e7ad commit 151a4b9

10 files changed

Lines changed: 1480 additions & 2 deletions

CHANGELOG.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Changelog
2+
3+
All notable changes to the IPTU API PHP SDK will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [2.1.2] - 2026-01-24
9+
10+
### Fixed
11+
- Added explicit `version` field to composer.json for proper Packagist versioning
12+
- Added `autoload-dev` section for test classes
13+
- Updated package description to include all supported cities
14+
15+
### Changed
16+
- Updated `VERSION` constant to `2.1.2`
17+
18+
## [2.1.0] - 2025-12-15
19+
20+
### Added
21+
- Per-request timeout parameter for all public methods
22+
- IPTU Tools endpoints for 2026 calendar data
23+
- `iptuToolsCidades()` - List cities with IPTU calendar
24+
- `iptuToolsCalendario()` - Get IPTU calendar for a city
25+
- `iptuToolsSimulador()` - Simulate payment options
26+
- `iptuToolsIsencao()` - Check exemption eligibility
27+
- `iptuToolsProximoVencimento()` - Get next due date info
28+
- Brasilia city support
29+
30+
### Changed
31+
- All methods now accept optional `?int $timeout` parameter to override default config timeout
32+
- Updated `VERSION` constant to `2.1.0`
33+
34+
### Example
35+
```php
36+
// Timeout específico para operações lentas
37+
$result = $client->valuationBatch($imoveis, timeout: 120);
38+
39+
// Via options array
40+
$result = $client->consultaEndereco("Avenida Paulista", "1000", "sp", [
41+
'incluirHistorico' => true,
42+
'timeout' => 60
43+
]);
44+
```
45+
46+
## [2.0.0] - 2025-11-01
47+
48+
### Added
49+
- Complete SDK rewrite with PHP 8.1+ features
50+
- `declare(strict_types=1)` for type safety
51+
- PSR-3 logging support via `LoggerInterface`
52+
- Exception hierarchy under `IPTUAPI\Exception` namespace
53+
- `IPTUAPIException` (base)
54+
- `AuthenticationException`, `ForbiddenException`, `NotFoundException`
55+
- `RateLimitException`, `ValidationException`, `ServerException`
56+
- `TimeoutException`, `NetworkException`
57+
- `isRetryable()` method on all exceptions
58+
- `toArray()` method for exception serialization
59+
- Configurable retry with exponential backoff via `RetryConfig`
60+
- Rate limit tracking via `getRateLimit()` and `getLastRequestId()`
61+
- `ClientConfig` for centralized configuration
62+
- Valuation endpoints (Pro+): `valuationEstimate()`, `valuationBatch()`, `valuationComparables()`
63+
- Data endpoints: `dadosIPTUHistorico()`, `dadosCNPJ()`, `dadosIPCACorrigir()`
64+
65+
### Changed
66+
- Minimum PHP version: 8.1
67+
- Client initialization: `new IPTUClient($apiKey, $config)`
68+
- All methods use named arguments (PHP 8.0+)
69+
70+
### Removed
71+
- PHP 7.x support
72+
- Legacy array-based error handling
73+
74+
## [1.0.0] - 2025-09-01
75+
76+
### Added
77+
- Initial release
78+
- Basic consultation methods: `consultaEndereco()`, `consultaSQL()`, `consultaCEP()`
79+
- Zoning query: `consultaZoneamento()`
80+
- Support for multiple cities (SP, BH, Recife, POA, Fortaleza, Curitiba, RJ)

composer.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"name": "raphaeltorquat0/iptuapi-php",
3-
"description": "SDK oficial para a IPTU API - Dados de IPTU de São Paulo e Belo Horizonte",
3+
"description": "SDK oficial para a IPTU API - Dados de IPTU de São Paulo, Belo Horizonte, Rio de Janeiro e outras cidades",
4+
"version": "2.1.2",
45
"type": "library",
56
"license": "proprietary",
67
"keywords": [
@@ -31,6 +32,11 @@
3132
"IPTUAPI\\": "src/"
3233
}
3334
},
35+
"autoload-dev": {
36+
"psr-4": {
37+
"IPTUAPI\\Tests\\": "tests/"
38+
}
39+
},
3440
"homepage": "https://iptuapi.com.br",
3541
"support": {
3642
"email": "contato@iptuapi.com.br",

src/Http/CurlHttpClient.php

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace IPTUAPI\Http;
6+
7+
use IPTUAPI\Exception\NetworkException;
8+
use IPTUAPI\Exception\TimeoutException;
9+
10+
/**
11+
* Implementação do cliente HTTP usando cURL.
12+
*/
13+
class CurlHttpClient implements HttpClientInterface
14+
{
15+
public function request(
16+
string $method,
17+
string $url,
18+
array $headers,
19+
?string $body,
20+
int $timeout
21+
): HttpResponse {
22+
$ch = curl_init();
23+
24+
$curlHeaders = [];
25+
foreach ($headers as $name => $value) {
26+
$curlHeaders[] = "{$name}: {$value}";
27+
}
28+
29+
curl_setopt_array($ch, [
30+
CURLOPT_URL => $url,
31+
CURLOPT_RETURNTRANSFER => true,
32+
CURLOPT_TIMEOUT => $timeout,
33+
CURLOPT_HEADER => true,
34+
CURLOPT_HTTPHEADER => $curlHeaders,
35+
]);
36+
37+
if ($method === 'POST') {
38+
curl_setopt($ch, CURLOPT_POST, true);
39+
if ($body !== null) {
40+
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
41+
}
42+
}
43+
44+
$response = curl_exec($ch);
45+
$statusCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
46+
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
47+
$error = curl_error($ch);
48+
$errno = curl_errno($ch);
49+
curl_close($ch);
50+
51+
if ($errno !== 0) {
52+
if ($errno === CURLE_OPERATION_TIMEDOUT) {
53+
throw new TimeoutException("Timeout após {$timeout}s", $timeout);
54+
}
55+
throw new NetworkException("Erro de conexão: {$error}");
56+
}
57+
58+
$headerStr = substr($response, 0, $headerSize);
59+
$bodyStr = substr($response, $headerSize);
60+
$headers = $this->parseHeaders($headerStr);
61+
62+
return new HttpResponse($statusCode, $bodyStr, $headers);
63+
}
64+
65+
private function parseHeaders(string $headerStr): array
66+
{
67+
$headers = [];
68+
foreach (explode("\r\n", $headerStr) as $line) {
69+
if (strpos($line, ':') !== false) {
70+
[$key, $value] = explode(':', $line, 2);
71+
$key = strtolower(trim($key));
72+
$headers[$key][] = trim($value);
73+
}
74+
}
75+
return $headers;
76+
}
77+
}

src/Http/HttpClientInterface.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace IPTUAPI\Http;
6+
7+
/**
8+
* Interface para abstração do cliente HTTP.
9+
* Permite injeção de dependência e mocking em testes.
10+
*/
11+
interface HttpClientInterface
12+
{
13+
/**
14+
* Executa uma requisição HTTP.
15+
*
16+
* @param string $method HTTP method (GET, POST, etc.)
17+
* @param string $url Full URL to request
18+
* @param array $headers Request headers
19+
* @param string|null $body Request body (JSON string)
20+
* @param int $timeout Timeout in seconds
21+
* @return HttpResponse
22+
*/
23+
public function request(
24+
string $method,
25+
string $url,
26+
array $headers,
27+
?string $body,
28+
int $timeout
29+
): HttpResponse;
30+
}

src/Http/HttpResponse.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace IPTUAPI\Http;
6+
7+
/**
8+
* Representa uma resposta HTTP.
9+
*/
10+
class HttpResponse
11+
{
12+
public function __construct(
13+
public readonly int $statusCode,
14+
public readonly string $body,
15+
public readonly array $headers
16+
) {
17+
}
18+
19+
/**
20+
* Verifica se a resposta foi bem-sucedida (2xx).
21+
*/
22+
public function isSuccess(): bool
23+
{
24+
return $this->statusCode >= 200 && $this->statusCode < 300;
25+
}
26+
27+
/**
28+
* Decodifica o body como JSON.
29+
*
30+
* @return array|null
31+
*/
32+
public function json(): ?array
33+
{
34+
$data = json_decode($this->body, true);
35+
return is_array($data) ? $data : null;
36+
}
37+
38+
/**
39+
* Obtém um header específico.
40+
*
41+
* @param string $name Nome do header (case-insensitive)
42+
* @return string|null
43+
*/
44+
public function getHeader(string $name): ?string
45+
{
46+
$name = strtolower($name);
47+
return $this->headers[$name][0] ?? null;
48+
}
49+
}

0 commit comments

Comments
 (0)