{"id":13879871,"url":"https://github.com/evilmartians/evil-client","last_synced_at":"2025-05-16T02:09:06.019Z","repository":{"id":40477068,"uuid":"44614489","full_name":"evilmartians/evil-client","owner":"evilmartians","description":"Human-friendly DSL for writing HTTP(s) clients in Ruby","archived":false,"fork":false,"pushed_at":"2025-01-09T11:01:07.000Z","size":505,"stargazers_count":109,"open_issues_count":1,"forks_count":17,"subscribers_count":34,"default_branch":"master","last_synced_at":"2025-05-15T16:06:38.126Z","etag":null,"topics":["api","api-client","http","http-client","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/evilmartians.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"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":"2015-10-20T15:07:55.000Z","updated_at":"2025-05-14T03:41:31.000Z","dependencies_parsed_at":"2024-06-19T01:37:19.254Z","dependency_job_id":"f5dc4a2f-8765-48e9-a864-2b7641fca0e5","html_url":"https://github.com/evilmartians/evil-client","commit_stats":{"total_commits":235,"total_committers":10,"mean_commits":23.5,"dds":"0.11489361702127665","last_synced_commit":"3467116f96af70cc558de2c48f00264706f6b095"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evilmartians%2Fevil-client","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evilmartians%2Fevil-client/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evilmartians%2Fevil-client/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evilmartians%2Fevil-client/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evilmartians","download_url":"https://codeload.github.com/evilmartians/evil-client/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254374533,"owners_count":22060614,"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":["api","api-client","http","http-client","ruby"],"created_at":"2024-08-06T08:02:36.938Z","updated_at":"2025-05-16T02:09:05.944Z","avatar_url":"https://github.com/evilmartians.png","language":"Ruby","readme":"# Evil::Client\n\nHuman-friendly DSL for writing HTTP(s) clients in Ruby\n\n\u003ca href=\"https://evilmartians.com/\"\u003e\n\u003cimg src=\"https://evilmartians.com/badges/sponsored-by-evil-martians.svg\" alt=\"Sponsored by Evil Martians\" width=\"236\" height=\"54\"\u003e\u003c/a\u003e\n\n[![Gem Version][gem-badger]][gem]\n[![Inline docs][inch-badger]][inch]\n[![Documentation Status][readthedocs-badger]][readthedocs]\n[![Coverage Status][coveralls-badger]][coveralls]\n\n## Intro\n\nThe gem allows writing http(s) clients in a way inspired by [Swagger][swagger] specifications. It stands away from mutable states and monkey patching when possible. To support multithreading all instances are immutable (though not frozen to avoid performance loss).\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'evil-client'\n```\n\nAnd then execute:\n\n```shell\n$ bundle\n```\n\nOr install it yourself as:\n\n```shell\n$ gem install evil-client\n```\n\n## Synopsis\n\nThe following example gives an idea of how a client to remote API looks like when written on top of `Evil::Client`. See [full documentation][readthedocs] for more details.\n\n```ruby\nrequire \"evil-client\"\n\nclass CatsClient \u003c Evil::Client\n  # Define options for the client's initializer\n  option :domain,   proc(\u0026:to_s)\n  option :user,     proc(\u0026:to_s)\n  option :password, proc(\u0026:to_s)\n\n  # Definitions shared by all operations\n  path     { \"https://#{domain}.example.com/api\" }\n  security { basic_auth settings.user, settings.password }\n\n  scope :cats do\n    # Scope-specific definitions\n    option :version,  default: proc { 1 }\n    path { \"v#{version}\" } # subpath added to root path\n\n    # Operation-specific definitions to update a cat by id\n    operation :update do\n      option :id,    proc(\u0026:to_i)\n      option :name,  optional: true\n      option :color, optional: true\n      option :age,   optional: true\n\n      let(:data) { options.select { |key, _| %i(name color age).include? key } }\n      validate   { errors.add :no_filters if data.empty? }\n\n      path        { \"cats/#{id}\" } # added to root path\n      http_method :patch # you can use plain syntax instead of a block\n      format      \"json\"\n      body        { options.except(:id, :version) } # [#slice] is available too\n\n      # Parses json response and wraps it into Cat instance with additional\n      # parameter\n      response 200 do |(status, headers, body)|\n        # Suppose you define a model for cats\n        Cat.new JSON.parse(body)\n      end\n\n      # Parses json response, wraps it into model with [#error] and raises\n      # an exception where [ResponseError#response] contains the model instance\n      response(400, 422) { |(status, *)| raise \"#{status}: Record invalid\" }\n    end\n  end\nend\n\n# Instantiate a client with a concrete settings\ncat_client = CatClient.new domain:   \"awesome-cats\",\n                           user:     \"cat_lover\",\n                           password: \"purr\"\n\n# Use verbose low-level DSL to send requests\ncat_client.scopes[:cats].new(version: 2)\n          .operations[:update].new(id: 4, age: 10, color: \"tabby\")\n          .call # sends request\n\n# Use top-level DSL for the same request\ncat_client.cats(version: 2).update(id: 4, age: 10, color: \"tabby\")\n\n# Both the methods send `PATCH https://awesome-cats.example.com/api/v2/cats/4`\n# with a specified body and headers (authorization via basic_auth)\n```\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).\n\n[codeclimate-badger]: https://img.shields.io/codeclimate/github/evilmartians/evil-client.svg?style=flat\n[codeclimate]: https://codeclimate.com/github/evilmartians/evil-client\n[dry-initializer]: http://dry-rb.org/gems/dry-initializer\n[gem-badger]: https://img.shields.io/gem/v/evil-client.svg?style=flat\n[gem]: https://rubygems.org/gems/evil-client\n[inch-badger]: http://inch-ci.org/github/evilmartians/evil-client.svg\n[inch]: https://inch-ci.org/github/evilmartians/evil-client\n[swagger]: http://swagger.io\n[readthedocs-badger]: https://readthedocs.org/projects/evilclient/badge/?version=latest\n[readthedocs]: http://evilclient.readthedocs.io/en/latest\n[coveralls-badger]: https://coveralls.io/repos/github/evilmartians/evil-client/badge.svg?branch=master\n[coveralls]: https://coveralls.io/github/evilmartians/evil-client?branch=master\n","funding_links":[],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevilmartians%2Fevil-client","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevilmartians%2Fevil-client","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevilmartians%2Fevil-client/lists"}