PHP code example of flytachi / winter-cast

1. Go to this page and download the library: Download flytachi/winter-cast library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

flytachi / winter-cast example snippets


use Flytachi\Winter\Cast\Cast;

// One-liner
$response = Cast::sendGet('https://api.example.com/users');
$users = $response->json();

// Or with fluent API
$response = Cast::get('https://api.example.com/users')
    ->timeout(5)
    ->send();

use Flytachi\Winter\Cast\Cast;
use Flytachi\Winter\Cast\Common\CastHeader;

$response = Cast::post('https://api.example.com/users')
    ->withHeaders(
        CastHeader::instance()
            ->json()
            ->authBearer($token)
    )
    ->withJsonBody([
        'name' => 'John Doe',
        'email' => '[email protected]'
    ])
    ->throwOnError()
    ->send();

$user = $response->json();

// Build request (returns CastRequest)
$request = Cast::get('https://api.com/data');

// Send immediately (returns CastResponse)
$response = Cast::sendGet('https://api.com/data');

use Flytachi\Winter\Cast\Common\CastRequest;

$request = CastRequest::get('https://api.com/users')
    ->withQueryParam('page', 1)
    ->withQueryParam('limit', 10)
    ->timeout(30)
    ->connectTimeout(5)
    ->retry(3, 1000)  // 3 retries, 1s delay
    ->maxResponseSize(50 * 1024 * 1024)  // 50MB limit
    ->throwOnError()
    ->send();

use Flytachi\Winter\Cast\Common\CastHeader;

$headers = CastHeader::instance()
    ->json()                      // Accept + Content-Type
    ->authBearer($token)          // Authorization: Bearer
    ->acceptLanguage('ru')        // Accept-Language
    ->userAgent('MyApp/1.0')      // User-Agent
    ->set('X-Custom', 'value');   // Custom header

$response->statusCode;        // int: HTTP status code
$response->body();            // ?string: Raw body
$response->json();            // ?array: Parsed JSON
$response->headers();         // array: All headers
$response->header('X-Rate-Limit');  // ?string: Specific header
$response->info();            // array: cURL info

// Status checks
$response->isSuccess();       // 2xx
$response->isClientError();   // 4xx
$response->isServerError();   // 5xx
$response->isRedirection();   // 3xx
$response->isConnectionError(); // Connection failed

// Static params
Cast::get('https://api.com/search', ['q' => 'php', 'type' => 'repos']);

// Dynamic params
Cast::get('https://api.com/search')
    ->withQueryParam('q', 'php')
    ->withQueryParam('type', 'repos')
    ->withQueryParams(['sort' => 'stars', 'order' => 'desc'])
    ->send();

// JSON body
Cast::post($url)
    ->withJsonBody(['key' => 'value'])
    ->send();

// Form data
Cast::post($url)
    ->withFormParams(['key' => 'value'])
    ->send();

// Multipart (file upload)
Cast::post($url)
    ->withMultipartBody([
        'file' => new CURLFile('/path/to/file.jpg'),
        'title' => 'My Image'
    ])
    ->send();

// Raw body
Cast::post($url)
    ->withBody('<xml>data</xml>')
    ->send();

Cast::get($url)
    ->timeout(30)           // Total request timeout (seconds)
    ->connectTimeout(10)    // Connection timeout (seconds)
    ->retry(3, 1000)        // 3 retries, 1s base delay, exponential backoff
    ->send();

// Disable exponential backoff (fixed delay)
Cast::get($url)
    ->retry(3, 1000, false) // 3 retries, fixed 1s delay
    ->send();

use Flytachi\Winter\Cast\Exception\TimeoutException;
use Flytachi\Winter\Cast\Exception\ConnectionException;
use Flytachi\Winter\Cast\Exception\RequestException;

try {
    $response = Cast::get($url)
        ->throwOnError()  // Enable exceptions for HTTP errors
        ->send();
        
} catch (TimeoutException $e) {
    // Request timed out - retry with longer timeout
    echo "Timeout: {$e->getMessage()}";
    
} catch (ConnectionException $e) {
    // Connection failed - try backup server
    echo "Connection failed: {$e->getMessage()}";
    
} catch (RequestException $e) {
    // HTTP error (4xx/5xx) - access response object
    echo "HTTP {$e->response->statusCode}: {$e->response->body()}";
}

use Flytachi\Winter\Cast\Common\CastClient;
use Flytachi\Winter\Cast\Common\CastRequest;

class ApiService
{
    public function __construct(
        private readonly CastClient $httpClient
    ) {}
    
    public function fetchUsers(): array
    {
        $request = CastRequest::get('https://api.com/users')
            ->timeout(5);
            
        $response = $this->httpClient->send($request);
        return $response->json();
    }
}

// DI Container configuration
$client = new CastClient(
    defaultTimeout: 30,
    defaultConnectTimeout: 10
);
$service = new ApiService($client);

$client = new CastClient(
    defaultTimeout: 60,
    defaultConnectTimeout: 15,
    defaultOptions: [
        CURLOPT_SSL_VERIFYPEER => false,  // Disable SSL verification (dev only!)
        CURLOPT_FOLLOWLOCATION => true,
    ]
);

// Use custom client
Cast::setGlobalClient($client);

use Flytachi\Winter\Cast\Common\CastMiddleware;
use Flytachi\Winter\Cast\Common\CastRequest;
use Flytachi\Winter\Cast\Common\CastResponse;

class TimingMiddleware implements CastMiddleware
{
    public function handle(CastRequest $request, callable $next): CastResponse
    {
        $start = microtime(true);

        $response = $next($request);  // Pass to next middleware/client

        $duration = microtime(true) - $start;
        echo "Request took {$duration}s\n";

        return $response;
    }
}

use Flytachi\Winter\Cast\Common\CastClient;

$client = new CastClient();
$client
    ->addMiddleware(new LoggingMiddleware($logger))
    ->addMiddleware(new BearerAuthMiddleware($token))
    ->addMiddleware(new TimingMiddleware());

// Middleware executes in order: Logging → Auth → Timing → Request

$client = new CastClient();
$client->addMiddleware(new BearerAuthMiddleware($token));

Cast::setGlobalClient($client);

// All requests now use middleware
Cast::sendGet('https://api.com/data');

use Flytachi\Winter\Cast\Stereotype\LoggingMiddleware;

$client->addMiddleware(new LoggingMiddleware(
    logger: $psrLogger,
    requestLevel: LogLevel::INFO,     // Log level for requests
    responseLevel: LogLevel::INFO,    // Log level for 2xx/3xx
    errorLevel: LogLevel::WARNING,    // Log level for 4xx/5xx
    logBody: false,                   // Log request/response body
    bodyMaxLength: 500                // Truncate body at N chars
));

// Output:
// [INFO] HTTP Request: GET https://api.com/users
// [INFO] HTTP Response: 200 (125.4ms)

use Flytachi\Winter\Cast\Stereotype\BearerAuthMiddleware;

// Static token
$client->addMiddleware(new BearerAuthMiddleware('your-api-token'));

// Dynamic token (fetched for each request)
$client->addMiddleware(new BearerAuthMiddleware(
    fn() => $tokenService->getAccessToken()
));

use Flytachi\Winter\Cast\Stereotype\BasicAuthMiddleware;

$client->addMiddleware(new BasicAuthMiddleware('username', 'password'));

use Flytachi\Winter\Cast\Stereotype\HeadersMiddleware;

$client->addMiddleware(new HeadersMiddleware(
    CastHeader::instance()
        ->userAgent('MyApp/1.0')
        ->acceptLanguage('ru')
        ->set('X-API-Version', '2')
));

use Flytachi\Winter\Cast\Stereotype\RetryOnUnauthorizedMiddleware;

$client->addMiddleware(new RetryOnUnauthorizedMiddleware(
    tokenRefresher: function (): string {
        // Refresh your token
        $response = Cast::sendPost('https://auth.api.com/refresh', [
            'refresh_token' => $storedRefreshToken
        ]);
        return $response->json()['access_token'];
    },
    maxRetries: 1  // Retry once after refresh
));

use Flytachi\Winter\Cast\Stereotype\ApiService;
use Flytachi\Winter\Cast\Common\CastHeader;

class PaymentApi extends ApiService
{
    protected static function baseUrl(): string
    {
        return 'https://api.payment.com/v1';
    }

    protected static function headers(): CastHeader
    {
        return CastHeader::instance()
            ->authBearer(env('PAYMENT_TOKEN'))
            ->json();
    }

    public static function getBalance(): array
    {
        $response = self::get('balance')->send(self::client());
        return self::tryResult($response);
    }

    public static function createPayment(array $data): array
    {
        $response = self::post('payments')
            ->withJsonBody($data)
            ->send(self::client());
        return self::tryResult($response);
    }
}

// Usage
$balance = PaymentApi::getBalance();
$payment = PaymentApi::createPayment(['amount' => 100]);

class PaymentApi extends ApiService
{
    protected static function baseUrl(): string
    {
        return env('PAYMENT_API_URL');
    }

    protected static function headers(): CastHeader
    {
        return CastHeader::instance()->json();
    }

    protected static function createClient(): CastClient
    {
        return (new CastClient(defaultTimeout: 30))
            ->addMiddleware(new LoggingMiddleware($logger))
            ->addMiddleware(new BearerAuthMiddleware(
                fn() => TokenService::getToken()
            ))
            ->addMiddleware(new RetryOnUnauthorizedMiddleware(
                fn() => TokenService::refresh()
            ));
    }
}

// ✅ Allowed
Cast::get('https://api.com/data')->send();
Cast::get('http://localhost/api')->send();

// ❌ Rejected (throws CastException)
Cast::get('file:///etc/passwd')->send();
Cast::get('ftp://example.com')->send();

// Default: 10MB limit
Cast::get($url)->send();

// Custom limit
Cast::get($url)
    ->maxResponseSize(50 * 1024 * 1024)  // 50MB
    ->send();

// Disable limit (use with caution!)
Cast::get($url)
    ->maxResponseSize(null)
    ->send();

use Flytachi\Winter\Cast\Common\CastClient;
use Flytachi\Winter\Cast\Common\CastResponse;

// Mock client for testing
class MockClient extends CastClient
{
    public function send(CastRequest $request): CastResponse
    {
        return new CastResponse(
            statusCode: 200,
            body: '{"id":1,"name":"Test User"}',
            headers: ['Content-Type' => 'application/json'],
            info: []
        );
    }
}

$service = new ApiService(new MockClient());

$repos = Cast::get('https://api.github.com/users/flytachi/repos')
    ->withHeaders(
        CastHeader::instance()
            ->acceptLanguage('en')
            ->userAgent('Winter-Cast/1.0')
    )
    ->send()
    ->json();

$response = Cast::post('https://api.example.com/data')
    ->withHeaders(
        CastHeader::instance()
            ->json()
            ->authBearer($accessToken)
    )
    ->withJsonBody(['key' => 'value'])
    ->throwOnError()
    ->send();

$response = Cast::get('https://example.com/file.pdf')
    ->maxResponseSize(100 * 1024 * 1024)  // 100MB
    ->timeout(120)
    ->send();

file_put_contents('/tmp/file.pdf', $response->body());

$page = 1;
$allUsers = [];

do {
    $response = Cast::get('https://api.com/users')
        ->withQueryParam('page', $page)
        ->withQueryParam('limit', 100)
        ->send();
        
    $data = $response->json();
    $allUsers = array_merge($allUsers, $data['users']);
    $page++;
    
} while (!empty($data['users']));