{"id":15288828,"url":"https://github.com/linqueta/eezee","last_synced_at":"2025-10-08T18:22:29.441Z","repository":{"id":48153416,"uuid":"228113967","full_name":"linqueta/eezee","owner":"linqueta","description":"The easiest HTTP client for Ruby","archived":false,"fork":false,"pushed_at":"2024-03-17T10:32:51.000Z","size":183,"stargazers_count":8,"open_issues_count":5,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-03T15:41:14.542Z","etag":null,"topics":["gem","http-client","ruby","ruby-on-rails","rubygems"],"latest_commit_sha":null,"homepage":"","language":"Ruby","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/linqueta.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-15T01:39:48.000Z","updated_at":"2021-04-01T20:28:49.000Z","dependencies_parsed_at":"2024-11-15T05:35:20.724Z","dependency_job_id":null,"html_url":"https://github.com/linqueta/eezee","commit_stats":{"total_commits":60,"total_committers":2,"mean_commits":30.0,"dds":"0.050000000000000044","last_synced_commit":"6166262f1b632888e0bc66218ddb149124c4f9f7"},"previous_names":["linqueta/katinguele"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linqueta%2Feezee","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linqueta%2Feezee/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linqueta%2Feezee/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/linqueta%2Feezee/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/linqueta","download_url":"https://codeload.github.com/linqueta/eezee/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248208539,"owners_count":21065202,"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":["gem","http-client","ruby","ruby-on-rails","rubygems"],"created_at":"2024-09-30T15:53:19.817Z","updated_at":"2025-10-08T18:22:29.377Z","avatar_url":"https://github.com/linqueta.png","language":"Ruby","readme":"# [Eezee][gem_page]\n\n*Eezee sounds like \"Easy\"*\n\n[![Gem Version][gem_version_image]][gem_version_page]\n[![Build Status][travis_status_image]][travis_page]\n[![Maintainability][code_climate_maintainability_image]][code_climate_maintainability_page]\n[![Test Coverage][code_climate_test_coverage_image]][code_climate_test_coverage_page]\n\nThe easiest HTTP client for Ruby!\n\nWith Eezee you can do these things:\n  * Define external services in an initializer file and use them through a simple method\n  * Take HTTP requests just extending a module and call the HTTP request method in your class/module\n  * Set before and after hooks to handle your requests, responses, and errors\n  * Handle all requests, responses, and errors in the same way\n  * Log the request, response, and errors\n  * Set general request timeout and open connection timeout\n  * Raise errors in failed requests\n  * Spend more time coding your API integrations instead defining and testing HTTP settings and clients\n\nThis gem is supported for Ruby 2.6+ applications.\n\n## Table of Contents\n- [Getting started](#getting-started)\n  - [Installation](#installation)\n  - [Supported HTTP Methods](#supported-http-methods)\n  - [How to take a request](#how-to-take-a-request)\n  - [Request options](#request-options)\n    - [Available Request options](#available-request-options)\n  - [Services](#services)\n    - [How a service works](#how-a-service-works)\n  - [Request](#request)\n  - [Response](#response)\n  - [Errors](#errors)\n  - [Examples](#examples)\n    - [Complete integrations](#complete-integrations)\n    - [Hooks](#hooks)\n- [The why to use Eezee instead Faraday](#the-why-to-use-Eezee-instead-faraday)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Getting started\n\n### Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'eezee'\n```\n\nIf you're on Rails you can run this line below to create the initializer:\n\n```shell\nrails generate eezee:install\n```\n\n### Supported HTTP Methods\n\nEezee supports these HTTP methods:\n\n- GET\n- POST\n- PATCH\n- PUT\n- DELETE\n\nAnd here are the corresponding Eezee's HTTP methods:\n\n- `get(request_options)`\n- `post(request_options)`\n- `patch(request_options)`\n- `put(request_options)`\n- `delete(request_options)`\n\nOBS: The param `request_options` is optional.\n\n### How to take a request\n\nTo take a request using any of these methods you just have to call the HTTP method, and if you want, you can pass the options.\n\n```ruby\nmodule RickMorty::Resource::Character\n  extend Eezee::Client\n\n  def self.index\n    get(url: 'rickandmortyapi.com/api', protocol: :https, path: 'character')\n  end\n\n  def self.find(id)\n    get(\n      url: 'rickandmortyapi.com/api',\n      protocol: :https,\n      path: 'character/:character_id',\n      params: { character_id: id }\n    )\n  end\n\n  def self.create(payload)\n    post(\n      url: 'rickandmortyapi.com/api',\n      protocol: :https,\n      path: 'character',\n      payload: payload\n    )\n  end\n\n  def self.update(id, payload)\n    post(\n      url: 'rickandmortyapi.com/api',\n      protocol: :https,\n      path: 'character/:character_id',\n      params: { character_id: id }\n      payload: payload\n    )\n  end\n\n  def self.destroy(id)\n    delete(\n      url: 'rickandmortyapi.com/api',\n      protocol: :https,\n      path: 'character/:character_id',\n      params: { character_id: id }\n    )\n  end\n```\n\n### Request options\n\nRequest options are the request settings. They can be used to define services, request options and as a param when you take the HTTP request. For example:\n\n```ruby\nmodule RickMorty::Resource::Character\n  extend Eezee::Client\n\n  eezee_request_options protocol: :https,\n                        url: 'rickandmortyapi.com/api'\n                        path: 'character/:character_id'\n\n  def self.index\n    get\n  end\n\n  def self.find(id)\n    get(params: { character_id: id })\n  end\n\n  def self.update(id, payload)\n    put(\n      params: { character_id: id },\n      payload: payload,\n      after: -\u003e(_req, res) { do_something!(res) }\n    )\n  end\nend\n```\n\nThe method `eezee_request_options` can receive all of [Available Request options](#available-request-options).\n\nWhen the HTTP methods were called, Eezee has created a Request setting with the options defined in the module and merge with the options passed as a param in the HTTP methods.\n\n#### Available Request options\n\nHere are the list of available options and about them:\n\n| Option | Required | Default | What is it? | Example |\n|--------|----------|---------|-------------|---------|\n| `url` | Yes | `nil` | The request's url | `\"rickandmortyapi.com/api\"` |\n| `protocol` | No | `nil` | The request's protocol | `:https` |\n| `path` | No | `nil` | The resource's path | `\"characters\\:characted_id\\addresses\"` |\n| `headers` | No | `{}` | The request's headers. | `{ Token: \"Bearer 1a8then...\" }` |\n| `params` | No | `{}` | The query params. If the url or path has a nested param like `:character_id` and you pass it in the hash, this value will be replaced. In the opposite, the value will be concatenated in the url like `...?character_id=10\u0026...`| `{ character_id: 10 }`|\n| `payload` | No | `{}` | The request's payload | `{ name: \"Linqueta\", gender: \"male\" }` |\n| `before` | No | `nil` | It's the before hook. You can pass Proc or Lambda to handle the request settings. See more in [Hooks](#hooks).  | `-\u003e(req) { merge_new_headers! }` |\n| `after` | No | `nil` | It's the after hook. You can pass Proc or Lambda to handle the request settings, response or error after the request. If it returns a valid value (different of false or `nil`) and the request raises an error, the error won't be raised to your application. See more in [Hooks](#hooks). | `-\u003e(req, res, err) { do_something! }` |\n| `timeout` | No | `nil` | If it exceeds this timeout to make whole request Eezee will raise the error `Eezee::TimeoutError` | `5` |\n| `open_timeout` | No | `nil` | If it exceed this timeout to open a connection Eezee will raise the error `Eezee::TimeoutError` | `2` |\n| `raise_error` | No | `false` | If you want that Eezee raises an error if the request has wasn't successful. See more in [Errors](#errors) | `true` |\n| `logger` | No | `false` | If you want to log the request, response, and error | `true` |\n| `url_encoded` | No | `false` | If you want to send request body as form_url_encoded | `true` |\n| `preserve_url_params` | No | `false` | The query params will be preserved if the url or path has a nested param like `:character_id` this value will be not replaced | `true` |\n| `ddtrace` | No | `nil` | Support for [DataDog apm](http://gems.datadoghq.com/trace/docs/#Faraday) | `{}` |\n\n### Services\n\nIt's common your app has integrations with many external services and this gem has a feature to organize in one file the settings of these external service integrations and it provides an easy way to get these settings.\n\nFor example, I will integrate with [Rick and Morty Api](https://rickandmortyapi.com/api/) using a service:\n\n- I'll declare it in an initializer file:\n\n```ruby\nEezee.configure do |config|\n  config.add_service :rick_morty_api,\n                     protocol: :https,\n                     url: 'rickandmortyapi.com/api'\nend\n```\n\n- In my resource, I'll catch the service and pass other settings:\n\n```ruby\nmodule RickMorty::Resource::Character\n  extend Eezee::Client\n\n  eezee_service :rick_morty_api\n  eezee_request_options path: 'character/:character_id'\n\n  def self.index\n    get\n  end\n\n  def self.find(id)\n    get(params: { character_id: id })\n  end\nend\n```\n\n#### How a service works\n\nWhen Ruby loads a class/module and it has the method `eezee_service` declared with a service's name, by default, Eezee will try load the service and create a request base for the class/module, so, when the class/module takes a request, Eezee will create the final request instance based on request base to take the HTTP request. You can turn it lazy setting the option `lazy: true`, therefore, the final request will be created just in the HTTP request. If the service doesn't exist when Eezee search about it, it will be raised the error `Eezee::Client::UnknownServiceError`.\n\nAbout the method `add_service`, you can pass all of [Available Request options](#available-request-options). The meaning of this part is to organize in one way the external services integrations.\n\n### Request\n\nIn [Hooks](#hooks), you always receive the param request and it is an instance of `Eezee::Request`. [Available Request options](#available-request-options) are the accessors of `Eezee::Request`, just call for the name, like:\n\n```ruby\nrequest.protocol\n# =\u003e :https\n\nrequest.url\n# =\u003e \"rickandmortyapi.com/api\"\n```\n\n### Response\n\nIn [Hooks](#hooks) and the return of the request you have an instance of `Eezee::Response`. This class can be used for successful and failed requests. Here are all methods you can call from a response:\n\n| Name | Type | What is it? |\n|------|------|-------------|\n| `original` | `Faraday::Response`, `Faraday::Error`, `Faraday::TimeoutError`, `Faraday::ConnectionFailed` or `Net::ReadTimeout` | The instance that made the `Eezee::Response`. |\n| `body` | `Hash` | The body response. It always is an instance of Hash (symbolized). If the response doesn't have a body response, the value will be `{}`. |\n| `success?` | Boolean (`TrueClass` or `FalseClass`) | If the request had a timeout error or response has the code 400+ the value will be `false`, else, the value will be `true`. |\n| `code` | `Integer` or `NilClass` | If the request had a timeout error the value will be `nil`, else, the value will be an integer. |\n| `timeout?` | Boolean (`TrueClass` or `FalseClass`) | If the request had a timeout error. |\n\n### Errors\n\nEezee can raise errors in some situations:\n  - When the specified service is unknown\n  - When the request got a timeout\n  - When the request got a failure response\n\n#### When the specified service is unknown\n  - `Eezee::Client::UnknownServiceError`\n\n#### When the request got a timeout\n  - `Eezee::TimeoutError`\n\n**Important**: This case happens just if the request option `raise_error` is `true`.\n\n#### When the request got a failure response\n  - `Eezee::RequestError` for all errors (ancestor of all below)\n  - `Eezee::BadRequestError` for code equals 400\n  - `Eezee::UnauthorizedError` for code equals 401\n  - `Eezee::ForbiddenError` for code equals 403\n  - `Eezee::ResourceNotFoundError` for code equals 404\n  - `Eezee::UnprocessableEntityError` for code equals 422\n  - `Eezee::ClientError` for code between 400 and 499\n  - `Eezee::InternalServerError` for code equals 500\n  - `Eezee::ServiceUnavailableError` for code equals 503\n  - `Eezee::ServerError` for code between 500 and 599\n\nAll of `Eezee::RequestError` has the accessor `@response` with an instace of `Eezee::Response`.\n\n**Important**: This case happens just if the request option `raise_error` is `true`.\n\n### Examples\n\nHere are some examples:\n\n#### Complete integrations\n\n- [Integrating with JsonPlaceHolder API and Go Rest API - With Service and Request options](https://gist.github.com/linqueta/b1c44cd3cca5e321893fdf3fa866c750)\n- [Integrating with JsonPlaceHolder API and Go Rest API - With Request options](https://gist.github.com/linqueta/7c9bf0988d2141c2f92aebe1b6613be5)\n- [Integrating with JsonPlaceHolder API and Go Rest API - Without Services and Request Options](https://gist.github.com/linqueta/a1ebe9bb598d2a66556019502e1eb433)\n\n#### Hooks\n\n- [Adding a header into the request using before hook](https://gist.github.com/linqueta/badce27997df7a594bf0e87db858e225)\n- [Handling resource not found errors using after hook](https://gist.github.com/linqueta/32bf5c12f23d2cb3e8d456e468892943)\n\n## The why to use Eezee instead Faraday\n\nSo, it's an important part of this README. This gem uses [Faraday](https://github.com/lostisland/faraday) as the HTTP client and Faraday is an excellent HTTP client, but it brings many difficult, or, in other words, many things could be easier, like:\n\n- If you work with microservices, you'll create a Faraday Connection setting per ms, or, it's so common to see many Faraday Connection setting in the same project.\n- To raise errors with Faraday you know to set an adapter (it could be easier)\n- When we have a successful response or an error, the way to catch the params (code, body) is completely different\n- Faraday doesn't have any way to set the external services in an initializer, you'll have to create yours\n- At least, it's common in projects the people create files to instantiate Faraday Connection but these people don't test these files\n\nAll of these things and others are contemplated by **Eezee**!\n\n## Contributing\n\n1. Fork it\n2. Create your feature branch (git checkout -b my-new-feature)\n3. Commit your changes (git commit -am 'Add some feature')\n4. Push to the branch (git push origin my-new-feature)\n5. Create new Pull Request\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License][mit_license_page].\n\n[gem_page]: https://github.com/linqueta/eezee\n[code_of_conduct_page]: https://github.com/linqueta/eezee/blob/master/CODE_OF_CONDUCT.md\n[mit_license_page]: https://opensource.org/licenses/MIT\n[contributor_convenant_page]: http://contributor-covenant.org\n[travis_status_image]: https://travis-ci.org/linqueta/eezee.svg?branch=master\n[travis_page]: https://travis-ci.org/linqueta/eezee\n[code_climate_maintainability_image]: https://api.codeclimate.com/v1/badges/b5ec73de9875a4675b5a/maintainability\n[code_climate_maintainability_page]: https://codeclimate.com/github/linqueta/eezee/maintainability\n[code_climate_test_coverage_image]: https://api.codeclimate.com/v1/badges/b5ec73de9875a4675b5a/test_coverage\n[code_climate_test_coverage_page]: https://codeclimate.com/github/linqueta/eezee/test_coverage\n[gem_version_image]: https://badge.fury.io/rb/eezee.svg\n[gem_version_page]: https://rubygems.org/gems/eezee\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinqueta%2Feezee","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flinqueta%2Feezee","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flinqueta%2Feezee/lists"}