{"id":28610882,"url":"https://github.com/Thavarshan/fetch-php","last_synced_at":"2025-06-11T23:02:45.059Z","repository":{"id":257004802,"uuid":"857068805","full_name":"Thavarshan/fetch-php","owner":"Thavarshan","description":"🚀 A lightweight HTTP library inspired by JavaScript's fetch, bringing simplicity and flexibility to PHP HTTP requests.","archived":false,"fork":false,"pushed_at":"2025-05-19T18:10:46.000Z","size":2099,"stargazers_count":409,"open_issues_count":0,"forks_count":23,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-05-22T07:03:18.066Z","etag":null,"topics":["fetch","fetch-api","fetch-php","guzzle","guzzle-php-library","guzzlehttp","http","http-client","javascript-fetch","javascript-fetch-api","php"],"latest_commit_sha":null,"homepage":"https://fetch-php.thavarshan.com/","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Thavarshan.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":".github/SUPPORT.md","governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"thavarshan","buy_me_a_coffee":"thavarshan"}},"created_at":"2024-09-13T18:33:05.000Z","updated_at":"2025-05-21T19:56:32.000Z","dependencies_parsed_at":"2024-09-14T09:24:17.284Z","dependency_job_id":"6fc235db-0f21-4555-a7c3-bbe6ee87a3da","html_url":"https://github.com/Thavarshan/fetch-php","commit_stats":{"total_commits":85,"total_committers":2,"mean_commits":42.5,"dds":0.04705882352941182,"last_synced_commit":"0eded664de97a0f8bfb91bb364c2c53f0325f3a5"},"previous_names":["thavarshan/fetch-php"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/Thavarshan/fetch-php","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thavarshan%2Ffetch-php","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thavarshan%2Ffetch-php/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thavarshan%2Ffetch-php/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thavarshan%2Ffetch-php/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Thavarshan","download_url":"https://codeload.github.com/Thavarshan/fetch-php/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Thavarshan%2Ffetch-php/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259360728,"owners_count":22845817,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fetch","fetch-api","fetch-php","guzzle","guzzle-php-library","guzzlehttp","http","http-client","javascript-fetch","javascript-fetch-api","php"],"created_at":"2025-06-11T23:01:48.521Z","updated_at":"2025-06-11T23:02:45.033Z","avatar_url":"https://github.com/Thavarshan.png","language":"PHP","readme":"# Fetch PHP\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/jerome/fetch-php.svg)](https://packagist.org/packages/jerome/fetch-php)\n[![Tests](https://github.com/Thavarshan/fetch-php/actions/workflows/tests.yml/badge.svg?label=tests\u0026branch=main)](https://github.com/Thavarshan/fetch-php/actions/workflows/tests.yml)\n[![Lint](https://github.com/Thavarshan/fetch-php/actions/workflows/lint.yml/badge.svg)](https://github.com/Thavarshan/fetch-php/actions/workflows/lint.yml)\n[![CodeQL](https://github.com/Thavarshan/fetch-php/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/Thavarshan/fetch-php/actions/workflows/github-code-scanning/codeql)\n[![PHPStan](https://img.shields.io/badge/PHPStan-level%20max-brightgreen.svg)](https://phpstan.org/)\n[![PHP Version](https://img.shields.io/packagist/php-v/jerome/fetch-php.svg)](https://packagist.org/packages/jerome/fetch-php)\n[![License](https://img.shields.io/packagist/l/jerome/fetch-php.svg)](https://packagist.org/packages/jerome/fetch-php)\n[![Total Downloads](https://img.shields.io/packagist/dt/jerome/fetch-php.svg)](https://packagist.org/packages/jerome/fetch-php)\n[![GitHub Stars](https://img.shields.io/github/stars/Thavarshan/fetch-php.svg?style=social\u0026label=Stars)](https://github.com/Thavarshan/fetch-php/stargazers)\n\n**Fetch PHP** is a modern HTTP client library for PHP that brings JavaScript's `fetch` API experience to PHP. Built on top of Guzzle, Fetch PHP allows you to write HTTP code with a clean, intuitive JavaScript-like syntax while still maintaining PHP's familiar patterns.\n\nWith support for both synchronous and asynchronous requests, a fluent chainable API, and powerful retry mechanics, Fetch PHP streamlines HTTP operations in your PHP applications.\n\nFull documentation can be found [here](https://fetch-php.thavarshan.com/)\n\n---\n\n## Key Features\n\n- **JavaScript-like Syntax**: Write HTTP requests just like you would in JavaScript with the `fetch()` function and `async`/`await` patterns\n- **Promise-based API**: Use familiar `.then()`, `.catch()`, and `.finally()` methods for async operations\n- **Fluent Interface**: Build requests with a clean, chainable API\n- **Built on Guzzle**: Benefit from Guzzle's robust functionality with a more elegant API\n- **Retry Mechanics**: Automatically retry failed requests with exponential backoff\n- **PHP-style Helper Functions**: Includes traditional PHP function helpers (`get()`, `post()`, etc.) for those who prefer that style\n\n## Why Choose Fetch PHP?\n\n### Beyond Guzzle\n\nWhile Guzzle is a powerful HTTP client, Fetch PHP enhances the experience by providing:\n\n- **JavaScript-like API**: Enjoy the familiar `fetch()` API and `async`/`await` patterns from JavaScript\n- **Global client management**: Configure once, use everywhere with the global client\n- **Simplified requests**: Make common HTTP requests with less code\n- **Enhanced error handling**: Reliable retry mechanics and clear error information\n- **Type-safe enums**: Use enums for HTTP methods, content types, and status codes\n\n| Feature | Fetch PHP | Guzzle |\n|---------|-----------|--------|\n| API Style | JavaScript-like fetch + async/await + PHP-style helpers | PHP-style only |\n| Client Management | Global client + instance options | Instance-based only |\n| Request Syntax | Clean, minimal | More verbose |\n| Types | Modern PHP 8.1+ enums | String constants |\n| Helper Functions | Multiple styles available | Limited |\n\n## Installation\n\n```bash\ncomposer require jerome/fetch-php\n```\n\n\u003e **Requirements**: PHP 8.1 or higher\n\n## Basic Usage\n\n### JavaScript-style API\n\n```php\n// Simple GET request\n$response = fetch('https://api.example.com/users');\n$users = $response-\u003ejson();\n\n// POST request with JSON body\n$response = fetch('https://api.example.com/users', [\n    'method' =\u003e 'POST',\n    'json' =\u003e ['name' =\u003e 'John Doe', 'email' =\u003e 'john@example.com'],\n]);\n```\n\n### PHP-style Helpers\n\n```php\n// GET request with query parameters\n$response = get('https://api.example.com/users', ['page' =\u003e 1, 'limit' =\u003e 10]);\n\n// POST request with JSON data\n$response = post('https://api.example.com/users', [\n    'name' =\u003e 'John Doe',\n    'email' =\u003e 'john@example.com'\n]);\n```\n\n### Fluent API\n\n```php\n// Chain methods to build your request\n$response = fetch_client()\n    -\u003ebaseUri('https://api.example.com')\n    -\u003ewithHeaders(['Accept' =\u003e 'application/json'])\n    -\u003ewithToken('your-auth-token')\n    -\u003ewithQueryParameters(['page' =\u003e 1, 'limit' =\u003e 10])\n    -\u003eget('/users');\n```\n\n## Async/Await Pattern\n\n### Using Async/Await\n\n```php\n// Import async/await functions\nuse function async;\nuse function await;\n\n// Wrap your fetch call in an async function\n$promise = async(function() {\n    return fetch('https://api.example.com/users');\n});\n\n// Await the result\n$response = await($promise);\n$users = $response-\u003ejson();\n\necho \"Fetched \" . count($users) . \" users\";\n```\n\n### Multiple Concurrent Requests with Async/Await\n\n```php\nuse function async;\nuse function await;\nuse function all;\n\n// Execute an async function\nawait(async(function() {\n    // Create multiple requests\n    $results = await(all([\n        'users' =\u003e async(fn() =\u003e fetch('https://api.example.com/users')),\n        'posts' =\u003e async(fn() =\u003e fetch('https://api.example.com/posts')),\n        'comments' =\u003e async(fn() =\u003e fetch('https://api.example.com/comments'))\n    ]));\n\n    // Process the results\n    $users = $results['users']-\u003ejson();\n    $posts = $results['posts']-\u003ejson();\n    $comments = $results['comments']-\u003ejson();\n\n    echo \"Fetched \" . count($users) . \" users, \" .\n         count($posts) . \" posts, and \" .\n         count($comments) . \" comments\";\n}));\n```\n\n### Sequential Requests with Async/Await\n\n```php\nuse function async;\nuse function await;\n\nawait(async(function() {\n    // First request: get auth token\n    $authResponse = await(async(fn() =\u003e\n        fetch('https://api.example.com/auth/login', [\n            'method' =\u003e 'POST',\n            'json' =\u003e [\n                'username' =\u003e 'user',\n                'password' =\u003e 'pass'\n            ]\n        ])\n    ));\n\n    $token = $authResponse-\u003ejson()['token'];\n\n    // Second request: use token to get user data\n    $userResponse = await(async(fn() =\u003e\n        fetch('https://api.example.com/me', [\n            'token' =\u003e $token\n        ])\n    ));\n\n    return $userResponse-\u003ejson();\n}));\n```\n\n### Error Handling with Async/Await\n\n```php\nuse function async;\nuse function await;\n\ntry {\n    $data = await(async(function() {\n        $response = await(async(fn() =\u003e\n            fetch('https://api.example.com/users/999')\n        ));\n\n        if ($response-\u003eisNotFound()) {\n            throw new \\Exception(\"User not found\");\n        }\n\n        return $response-\u003ejson();\n    }));\n\n    // Process the data\n\n} catch (\\Exception $e) {\n    echo \"Error: \" . $e-\u003egetMessage();\n}\n```\n\n## Traditional Promise-based Pattern\n\n```php\n// Set up an async request\n// Get the handler for async operations\n$handler = fetch_client()-\u003egetHandler();\n$handler-\u003easync();\n\n// Make the async request\n$promise = $handler-\u003eget('https://api.example.com/users');\n\n// Handle the result with callbacks\n$promise-\u003ethen(\n    function ($response) {\n        // Process successful response\n        $users = $response-\u003ejson();\n        foreach ($users as $user) {\n            echo $user['name'] . PHP_EOL;\n        }\n    },\n    function ($exception) {\n        // Handle errors\n        echo \"Error: \" . $exception-\u003egetMessage();\n    }\n);\n```\n\n## Advanced Async Usage\n\n### Concurrent Requests with Promise Utilities\n\n```php\nuse function race;\n\n// Create promises for redundant endpoints\n$promises = [\n    async(fn() =\u003e fetch('https://api1.example.com/data')),\n    async(fn() =\u003e fetch('https://api2.example.com/data')),\n    async(fn() =\u003e fetch('https://api3.example.com/data'))\n];\n\n// Get the result from whichever completes first\n$response = await(race($promises));\n$data = $response-\u003ejson();\necho \"Got data from the fastest source\";\n```\n\n### Controlled Concurrency with Map\n\n```php\nuse function map;\n\n// List of user IDs to fetch\n$userIds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n\n// Process at most 3 requests at a time\n$responses = await(map($userIds, function($id) {\n    return async(function() use ($id) {\n        return fetch(\"https://api.example.com/users/{$id}\");\n    });\n}, 3));\n\n// Process the responses\nforeach ($responses as $index =\u003e $response) {\n    $user = $response-\u003ejson();\n    echo \"Processed user {$user['name']}\\n\";\n}\n```\n\n### Batch Processing\n\n```php\nuse function batch;\n\n// Array of items to process\n$items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n\n// Process in batches of 3 with max 2 concurrent batches\n$results = await(batch(\n    $items,\n    function($batch) {\n        // Process a batch\n        return async(function() use ($batch) {\n            $batchResults = [];\n            foreach ($batch as $id) {\n                $response = await(async(fn() =\u003e\n                    fetch(\"https://api.example.com/users/{$id}\")\n                ));\n                $batchResults[] = $response-\u003ejson();\n            }\n            return $batchResults;\n        });\n    },\n    3, // batch size\n    2  // concurrency\n));\n```\n\n### With Retries\n\n```php\nuse function retry;\n\n// Retry a flaky request up to 3 times with exponential backoff\n$data = await(retry(\n    function() {\n        return async(function() {\n            return fetch('https://api.example.com/unstable-endpoint');\n        });\n    },\n    3, // max attempts\n    function($attempt) {\n        // Exponential backoff strategy\n        return min(pow(2, $attempt) * 100, 1000);\n    }\n));\n```\n\n## Advanced Configuration\n\n### Authentication\n\n```php\n// Basic auth\n$response = fetch('https://api.example.com/secure', [\n    'auth' =\u003e ['username', 'password']\n]);\n\n// Bearer token\n$response = fetch_client()\n    -\u003ewithToken('your-oauth-token')\n    -\u003eget('https://api.example.com/secure');\n```\n\n### Proxies\n\n```php\n$response = fetch('https://api.example.com', [\n    'proxy' =\u003e 'http://proxy.example.com:8080'\n]);\n\n// Or with fluent API\n$response = fetch_client()\n    -\u003ewithProxy('http://proxy.example.com:8080')\n    -\u003eget('https://api.example.com');\n```\n\n### Global Client Configuration\n\n```php\n// Configure once at application bootstrap\nfetch_client([\n    'base_uri' =\u003e 'https://api.example.com',\n    'headers' =\u003e [\n        'User-Agent' =\u003e 'MyApp/1.0',\n        'Accept' =\u003e 'application/json',\n    ],\n    'timeout' =\u003e 10,\n]);\n\n// Use the configured client throughout your application\nfunction getUserData($userId) {\n    return fetch_client()-\u003eget(\"/users/{$userId}\")-\u003ejson();\n}\n\nfunction createUser($userData) {\n    return fetch_client()-\u003epost('/users', $userData)-\u003ejson();\n}\n```\n\n## Working with Responses\n\n```php\n$response = fetch('https://api.example.com/users/1');\n\n// Check if request was successful\nif ($response-\u003eisSuccess()) {\n    // HTTP status code\n    echo $response-\u003egetStatusCode(); // 200\n\n    // Response body as JSON\n    $user = $response-\u003ejson();\n\n    // Response body as string\n    $body = $response-\u003egetBody()-\u003egetContents();\n\n    // Get a specific header\n    $contentType = $response-\u003egetHeaderLine('Content-Type');\n\n    // Check status code categories\n    if ($response-\u003egetStatus()-\u003eisSuccess()) {\n        echo \"Request succeeded\";\n    }\n}\n```\n\n## Working with Type-Safe Enums\n\n```php\nuse Fetch\\Enum\\Method;\nuse Fetch\\Enum\\ContentType;\nuse Fetch\\Enum\\Status;\n\n// Use enums for HTTP methods\n$client = fetch_client();\n$response = $client-\u003erequest(Method::POST, '/users', $userData);\n\n// Check HTTP status with enums\nif ($response-\u003egetStatus() === Status::OK) {\n    // Process successful response\n}\n\n// Content type handling\n$response = $client-\u003ewithBody($data, ContentType::JSON)-\u003epost('/users');\n```\n\n## Error Handling\n\n```php\n// Synchronous error handling\ntry {\n    $response = fetch('https://api.example.com/nonexistent');\n\n    if (!$response-\u003eisSuccess()) {\n        echo \"Request failed with status: \" . $response-\u003egetStatusCode();\n    }\n} catch (\\Throwable $e) {\n    echo \"Exception: \" . $e-\u003egetMessage();\n}\n\n// Asynchronous error handling\n$handler = fetch_client()-\u003egetHandler();\n$handler-\u003easync();\n\n$promise = $handler-\u003eget('https://api.example.com/nonexistent')\n    -\u003ethen(function ($response) {\n        if ($response-\u003eisSuccess()) {\n            return $response-\u003ejson();\n        }\n        throw new \\Exception(\"Request failed with status: \" . $response-\u003egetStatusCode());\n    })\n    -\u003ecatch(function (\\Throwable $e) {\n        echo \"Error: \" . $e-\u003egetMessage();\n    });\n```\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details.\n\n## Contributing\n\nContributions are welcome! We're currently looking for help with:\n\n- Expanding test coverage\n- Improving documentation\n- Adding support for additional HTTP features\n\nTo contribute:\n\n1. Fork the Project\n2. Create your Feature Branch (`git checkout -b feature/amazing-feature`)\n3. Commit your Changes (`git commit -m 'Add some amazing-feature'`)\n4. Push to the Branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## Acknowledgments\n\n- Thanks to **Guzzle HTTP** for providing the underlying HTTP client\n- Thanks to all contributors who have helped improve this package\n- Special thanks to the PHP community for their support and feedback\n","funding_links":["https://github.com/sponsors/thavarshan","https://buymeacoffee.com/thavarshan"],"categories":["PHP"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FThavarshan%2Ffetch-php","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FThavarshan%2Ffetch-php","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FThavarshan%2Ffetch-php/lists"}