{"id":15529391,"url":"https://github.com/mnapoli/bof","last_synced_at":"2025-06-22T23:05:56.466Z","repository":{"id":57018494,"uuid":"217579572","full_name":"mnapoli/bof","owner":"mnapoli","description":"The HTTP client for humans","archived":false,"fork":false,"pushed_at":"2021-10-09T16:18:06.000Z","size":60,"stargazers_count":79,"open_issues_count":1,"forks_count":4,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-15T11:41:23.284Z","etag":null,"topics":["guzzle","http","http-client","php","psr-7"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mnapoli.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-10-25T17:04:05.000Z","updated_at":"2024-05-20T10:18:43.000Z","dependencies_parsed_at":"2022-08-22T12:00:22.013Z","dependency_job_id":null,"html_url":"https://github.com/mnapoli/bof","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":"mnapoli/project-template","purl":"pkg:github/mnapoli/bof","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnapoli%2Fbof","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnapoli%2Fbof/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnapoli%2Fbof/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnapoli%2Fbof/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mnapoli","download_url":"https://codeload.github.com/mnapoli/bof/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnapoli%2Fbof/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261380906,"owners_count":23149966,"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":["guzzle","http","http-client","php","psr-7"],"created_at":"2024-10-02T11:17:46.643Z","updated_at":"2025-06-22T23:05:51.450Z","avatar_url":"https://github.com/mnapoli.png","language":"PHP","readme":"The HTTP client for humans.\n\n[![Build Status](https://img.shields.io/travis/com/mnapoli/bof/master.svg?style=flat-square)](https://travis-ci.com/mnapoli/bof)\n[![Latest Version](https://img.shields.io/github/release/mnapoli/bof.svg?style=flat-square)](https://packagist.org/packages/mnapoli/bof)\n\n![](img/logo.png)\n\n## Why?\n\nBof is a HTTP client meant to be as user friendly as possible.\n\nIt makes the most classic use cases, such as downloading a file, interacting with a JSON API or submitting a form, as simple as possible.\n\nSince Bof is based on [Guzzle](http://docs.guzzlephp.org/en/stable/overview.html), more advanced use cases can be addressed by using Guzzle's methods directly.\n\nTo sum up, Bof:\n\n- is user friendly\n- avoids magic strings and arrays for configuration: instead it provides explicit, typed and documented methods that can be autocompleted by IDEs\n- comes with sane defaults: JSON is supported natively, 4xx and 5xx responses throw exceptions, timeouts are short by default\n- is PSR-7 compliant\n\nFuture plans:\n\n- PSR-18 compliance (the HTTP client standard)\n- resiliency mechanisms such as retry, backoff, etc.\n\nWant a short illustration? Here is Bof compared to Guzzle:\n\n```php\n// Bof\n$http = new Bof\\Http;\n$createdProduct = $http\n    -\u003ewithHeader('Authorization', 'Token abcd')\n    -\u003epostJson('https://example.com/api/products', [\n        'Hello' =\u003e 'world',\n    ])\n    -\u003egetData();\n\n// Guzzle\n$client = new GuzzleHttp\\Client([\n    'headers' =\u003e [\n        'Authorization' =\u003e 'Token abcd',\n    ],\n]);\n$response = $client-\u003erequest('POST', 'https://example.com/api/products', [\n   'json' =\u003e [\n        'Hello' =\u003e 'world',\n   ]\n]);\n$createdProduct = json_decode($response-\u003egetBody()-\u003e__toString(), true);\nif (json_last_error() !== JSON_ERROR_NONE) {\n    throw new Exception('There was an error while decoding the JSON response');\n}\n```\n\n## Do we need a new HTTP client?\n\nProbably not. If this client attracts interest, that may mean that our already popular HTTP clients could use a simpler API targeting the simple use cases. If you maintain a HTTP client and are interested, I would love to merge Bof into existing libraries. Open an issue!\n\n## Installation\n\n```bash\ncomposer require mnapoli/bof\n```\n\n## Usage\n\n```php\n$http = new Bof\\Http;\n\n$response = $http-\u003eget('https://example.com/api/products');\n```\n\n### Configuration\n\n**The `Bof\\Http` class is immutable**.\n\nConfiguration is applied by calling `withXxx()` methods which create a new object every time:\n\n```php\n$http = new Bof\\Http;\n\n// The header will apply to all subsequent requests\n$http = $http-\u003ewithHeader('Authorization', \"Bearer $token\");\n```\n\nRemember that `withXxx()` methods return *a copy* of the original client:\n\n```php\n$http1 = new Bof\\Http;\n\n$http2 = $http1-\u003ewithHeader('Authorization', \"Bearer $token\");\n\n// $http1 does not have the header applied\n// $http2 has the header\n```\n\nThanks to that pattern, the same methods can be used to apply configuration only for a specific request:\n\n```php\n$products = $http-\u003ewithHeader('Authorization', \"Bearer $token\")\n    -\u003eget('https://example.com/api/products')\n    -\u003egetData();\n\n// The next requests will *not* have the `Authorization` header\n```\n\n### Responses\n\nResponses are PSR-7 compliant. They also provide methods to facilitate working with JSON responses:\n\n```php\n$http = new Bof\\Http;\n\n$products = $http-\u003eget('https://example.com/api/products')\n    -\u003egetData();\n```\n\nThe `getData()` method will decode the JSON response.\n\nAll PSR-7 methods are also available:\n\n```php\n$response = $http-\u003eget('https://example.com/api/products');\necho $response-\u003egetStatusCode();\necho $response-\u003egetHeader('Content-Length')[0];\necho $response-\u003egetBody()-\u003egetContents();\n```\n\n[Learn more](http://docs.guzzlephp.org/en/stable/quickstart.html#using-responses).\n\n### Sending JSON data\n\nUsing the JSON methods, the data will automatically encoded to JSON. A `Content-Type` header of `application/json` will be added.\n\n```php\n$http-\u003epostJson('https://example.com/api/products', [\n    'foo' =\u003e 'bar',\n]);\n// putJson() or patchJson() works as well\n```\n\n### Sending form data\n\nData can also be sent as a `application/x-www-form-urlencoded` POST request:\n\n```php\n$http-\u003epostForm('https://example.com/api/products', [\n    'foo' =\u003e 'bar',\n    'baz' =\u003e ['hi', 'there!'],\n]);\n// putForm() works as well\n```\n\n### Exceptions\n\nInvalid HTTP responses (status code 4xx or 5xx) will throw exceptions.\n\n```php\ntry {\n    $http-\u003eget('https://example.com/api/products');\n} catch (\\GuzzleHttp\\Exception\\GuzzleException $e) {\n    // $e-\u003egetRequest()\n    // $e-\u003egetResponse()\n    ...\n}\n```\n\n[Learn more](http://docs.guzzlephp.org/en/stable/quickstart.html#exceptions).\n\n### Headers\n\n```php\n$http = $http-\u003ewithHeader('Authorization', \"Bearer $token\");\n\n// Headers can have multiple values\n$http = $http-\u003ewithHeader('X-Foo', ['Bar', 'Baz']);\n```\n\n### Timeouts\n\nTimeouts are set at short values by default:\n\n- 5 seconds for the request timeout\n- 3 seconds for the HTTP connection timeout\n\nYou can set shorter or longer timeouts (or disable them by setting them at `0`):\n\n```php\n// 2 seconds for the request timeout, 1 second for the connection timeout\n$http = $http-\u003ewithTimeout(2, 1);\n```\n\n### Query string parameters\n\nYou can set query string parameters in the request's URI:\n\n$response = $http-\u003eget('http://httpbin.org?foo=bar');\n\nYou can specify the query string parameters as an array:\n\n```php\n$http-\u003ewithQueryParams(['foo' =\u003e 'bar'])\n    -\u003eget('http://httpbin.org');\n```\n\nProviding the option as an array will use PHP's `http_build_query` function to format the query string.\n\nAnd finally, you can provide the query request option as a string.\n\n```php\n$http-\u003ewithQueryParams('foo=bar')\n    -\u003eget('http://httpbin.org');\n```\n\n### Proxy\n\nUse `withSingleProxy()` to specify a proxy for all protocols:\n\n```php\n$http = $http-\u003ewithSingleProxy('tcp://localhost:8125');\n```\n\nUse `withMultipleProxies()` to specify a different proxy for HTTP and HTTPS, as well as a list of host names that should not be proxied to:\n\n```php\n$http = $http-\u003ewithMultipleProxies(\n    'tcp://localhost:8125', // Use this proxy with HTTP \n    'tcp://localhost:9124', // Use this proxy with HTTPS\n    ['.mit.edu', 'foo.com'] // Don't use a proxy with these\n);\n```\n\nNote that you can provide proxy URLs that contain a scheme, username, and password. For example, `http://username:password@192.168.16.1:10`.\n\n## Guzzle integration\n\nBof is based on Guzzle. You can even make it use your own Guzzle client, for example if you preconfigured it:\n\n```php\n$guzzleClient = new GuzzleHttp\\Client([\n    'base_uri' =\u003e 'http://httpbin.org',\n    'timeout'  =\u003e 2.0,\n]);\n\n$http = new Bof\\Http($guzzleClient);\n```\n\n[Learn more](http://docs.guzzlephp.org/en/stable/request-options.html).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmnapoli%2Fbof","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmnapoli%2Fbof","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmnapoli%2Fbof/lists"}