{"id":19405658,"url":"https://github.com/johnament/shaboopy","last_synced_at":"2026-06-12T13:31:17.120Z","repository":{"id":68090596,"uuid":"77001764","full_name":"johnament/shaboopy","owner":"johnament","description":"fadsg","archived":false,"fork":false,"pushed_at":"2016-12-21T00:38:01.000Z","size":1540,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-02-25T00:47:19.769Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/johnament.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","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":"2016-12-21T00:23:39.000Z","updated_at":"2018-09-13T07:04:10.000Z","dependencies_parsed_at":"2023-09-12T09:00:18.795Z","dependency_job_id":null,"html_url":"https://github.com/johnament/shaboopy","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/johnament/shaboopy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnament%2Fshaboopy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnament%2Fshaboopy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnament%2Fshaboopy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnament%2Fshaboopy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johnament","download_url":"https://codeload.github.com/johnament/shaboopy/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johnament%2Fshaboopy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34247460,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-12T02:00:06.859Z","response_time":109,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2024-11-10T11:39:01.375Z","updated_at":"2026-06-12T13:31:17.100Z","avatar_url":"https://github.com/johnament.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Feign makes writing java http clients easier\n\n[![Join the chat at https://gitter.im/Netflix/feign](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Netflix/feign?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge\u0026utm_content=badge)\n[![Build Status](https://travis-ci.org/OpenFeign/feign.svg?branch=master)](https://travis-ci.org/OpenFeign/feign)\n\nFeign is a java to http client binder inspired by [Retrofit](https://github.com/square/retrofit), [JAXRS-2.0](https://jax-rs-spec.java.net/nonav/2.0/apidocs/index.html), and [WebSocket](http://www.oracle.com/technetwork/articles/java/jsr356-1937161.html).  Feign's first goal was reducing the complexity of binding [Denominator](https://github.com/Netflix/Denominator) uniformly to http apis regardless of [restfulness](http://www.slideshare.net/adrianfcole/99problems).\n\n### Why Feign and not X?\n\nYou can use tools like Jersey and CXF to write java clients for ReST or SOAP services.  You can write your own code on top of http transport libraries like Apache HC.  Feign aims to connect your code to http apis with minimal overhead and code. Via customizable decoders and error handling, you should be able to write to any text-based http api.\n\n### How does Feign work?\n\nFeign works by processing annotations into a templatized request.  Just before sending it off, arguments are applied to these templates in a straightforward fashion.  While this limits Feign to only supporting text-based apis, it dramatically simplified system aspects such as replaying requests.  It is also stupid easy to unit test your conversions knowing this.\n\n### Basics\n\nUsage typically looks like this, an adaptation of the [canonical Retrofit sample](https://github.com/square/retrofit/blob/master/samples/src/main/java/com/example/retrofit/SimpleService.java).\n\n```java\ninterface GitHub {\n  @RequestLine(\"GET /repos/{owner}/{repo}/contributors\")\n  List\u003cContributor\u003e contributors(@Param(\"owner\") String owner, @Param(\"repo\") String repo);\n}\n\nstatic class Contributor {\n  String login;\n  int contributions;\n}\n\npublic static void main(String... args) {\n  GitHub github = Feign.builder()\n                       .decoder(new GsonDecoder())\n                       .target(GitHub.class, \"https://api.github.com\");\n\n  // Fetch and print a list of the contributors to this library.\n  List\u003cContributor\u003e contributors = github.contributors(\"netflix\", \"feign\");\n  for (Contributor contributor : contributors) {\n    System.out.println(contributor.login + \" (\" + contributor.contributions + \")\");\n  }\n}\n```\n\n### Customization\n\nFeign has several aspects that can be customized.  For simple cases, you can use `Feign.builder()` to construct an API interface with your custom components.  For example:\n\n```java\ninterface Bank {\n  @RequestLine(\"POST /account/{id}\")\n  Account getAccountInfo(@Param(\"id\") String id);\n}\n...\nBank bank = Feign.builder().decoder(new AccountDecoder()).target(Bank.class, \"https://api.examplebank.com\");\n```\n\n### Multiple Interfaces\nFeign can produce multiple api interfaces.  These are defined as `Target\u003cT\u003e` (default `HardCodedTarget\u003cT\u003e`), which allow for dynamic discovery and decoration of requests prior to execution.\n\nFor example, the following pattern might decorate each request with the current url and auth token from the identity service.\n\n```java\nCloudDNS cloudDNS = Feign.builder().target(new CloudIdentityTarget\u003cCloudDNS\u003e(user, apiKey));\n```\n\n### Examples\nFeign includes example [GitHub](./example-github) and [Wikipedia](./example-wikipedia) clients. The denominator project can also be scraped for Feign in practice. Particularly, look at its [example daemon](https://github.com/Netflix/denominator/tree/master/example-daemon).\n\n### Integrations\nFeign intends to work well within Netflix and other Open Source communities.  Modules are welcome to integrate with your favorite projects!\n\n### Gson\n[Gson](./gson) includes an encoder and decoder you can use with a JSON API.\n\nAdd `GsonEncoder` and/or `GsonDecoder` to your `Feign.Builder` like so:\n\n```java\nGsonCodec codec = new GsonCodec();\nGitHub github = Feign.builder()\n                     .encoder(new GsonEncoder())\n                     .decoder(new GsonDecoder())\n                     .target(GitHub.class, \"https://api.github.com\");\n```\n\n### Jackson\n[Jackson](./jackson) includes an encoder and decoder you can use with a JSON API.\n\nAdd `JacksonEncoder` and/or `JacksonDecoder` to your `Feign.Builder` like so:\n\n```java\nGitHub github = Feign.builder()\n                     .encoder(new JacksonEncoder())\n                     .decoder(new JacksonDecoder())\n                     .target(GitHub.class, \"https://api.github.com\");\n```\n\n### Sax\n[SaxDecoder](./sax) allows you to decode XML in a way that is compatible with normal JVM and also Android environments.\n\nHere's an example of how to configure Sax response parsing:\n```java\napi = Feign.builder()\n           .decoder(SAXDecoder.builder()\n                              .registerContentHandler(UserIdHandler.class)\n                              .build())\n           .target(Api.class, \"https://apihost\");\n```\n\n### JAXB\n[JAXB](./jaxb) includes an encoder and decoder you can use with an XML API.\n\nAdd `JAXBEncoder` and/or `JAXBDecoder` to your `Feign.Builder` like so:\n\n```java\napi = Feign.builder()\n           .encoder(new JAXBEncoder())\n           .decoder(new JAXBDecoder())\n           .target(Api.class, \"https://apihost\");\n```\n\n### JAX-RS\n[JAXRSContract](./jaxrs) overrides annotation processing to instead use standard ones supplied by the JAX-RS specification.  This is currently targeted at the 1.1 spec.\n\nHere's the example above re-written to use JAX-RS:\n```java\ninterface GitHub {\n  @GET @Path(\"/repos/{owner}/{repo}/contributors\")\n  List\u003cContributor\u003e contributors(@PathParam(\"owner\") String owner, @PathParam(\"repo\") String repo);\n}\n```\n```java\nGitHub github = Feign.builder()\n                     .contract(new JAXRSContract())\n                     .target(GitHub.class, \"https://api.github.com\");\n```\n### OkHttp\n[OkHttpClient](./okhttp) directs Feign's http requests to [OkHttp](http://square.github.io/okhttp/), which enables SPDY and better network control.\n\nTo use OkHttp with Feign, add the OkHttp module to your classpath. Then, configure Feign to use the OkHttpClient:\n\n```java\nGitHub github = Feign.builder()\n                     .client(new OkHttpClient())\n                     .target(GitHub.class, \"https://api.github.com\");\n```\n\n### Ribbon\n[RibbonClient](./ribbon) overrides URL resolution of Feign's client, adding smart routing and resiliency capabilities provided by [Ribbon](https://github.com/Netflix/ribbon).\n\nIntegration requires you to pass your ribbon client name as the host part of the url, for example `myAppProd`.\n```java\nMyService api = Feign.builder().client(RibbonClient.create()).target(MyService.class, \"https://myAppProd\");\n\n```\n\n### Hystrix\n[HystrixFeign](./hystrix) configures circuit breaker support provided by [Hystrix](https://github.com/Netflix/Hystrix).\n\nTo use Hystrix with Feign, add the Hystrix module to your classpath. Then use the `HystrixFeign` builder:\n\n```java\nMyService api = HystrixFeign.builder().target(MyService.class, \"https://myAppProd\");\n\n```\n\n### SLF4J\n[SLF4JModule](./slf4j) allows directing Feign's logging to [SLF4J](http://www.slf4j.org/), allowing you to easily use a logging backend of your choice (Logback, Log4J, etc.)\n\nTo use SLF4J with Feign, add both the SLF4J module and an SLF4J binding of your choice to your classpath.  Then, configure Feign to use the Slf4jLogger:\n\n```java\nGitHub github = Feign.builder()\n                     .logger(new Slf4jLogger())\n                     .target(GitHub.class, \"https://api.github.com\");\n```\n\n### Decoders\n`Feign.builder()` allows you to specify additional configuration such as how to decode a response.\n\nIf any methods in your interface return types besides `Response`, `String`, `byte[]` or `void`, you'll need to configure a non-default `Decoder`.\n\nHere's how to configure JSON decoding (using the `feign-gson` extension):\n\n```java\nGitHub github = Feign.builder()\n                     .decoder(new GsonDecoder())\n                     .target(GitHub.class, \"https://api.github.com\");\n```\n\n### Encoders\nThe simplest way to send a request body to a server is to define a `POST` method that has a `String` or `byte[]` parameter without any annotations on it. You will likely need to add a `Content-Type` header.\n\n```java\ninterface LoginClient {\n  @RequestLine(\"POST /\")\n  @Headers(\"Content-Type: application/json\")\n  void login(String content);\n}\n...\nclient.login(\"{\\\"user_name\\\": \\\"denominator\\\", \\\"password\\\": \\\"secret\\\"}\");\n```\n\nBy configuring an `Encoder`, you can send a type-safe request body. Here's an example using the `feign-gson` extension:\n\n```java\nstatic class Credentials {\n  final String user_name;\n  final String password;\n\n  Credentials(String user_name, String password) {\n    this.user_name = user_name;\n    this.password = password;\n  }\n}\n\ninterface LoginClient {\n  @RequestLine(\"POST /\")\n  void login(Credentials creds);\n}\n...\nLoginClient client = Feign.builder()\n                          .encoder(new GsonEncoder())\n                          .target(LoginClient.class, \"https://foo.com\");\n\nclient.login(new Credentials(\"denominator\", \"secret\"));\n```\n\n### @Body templates\nThe `@Body` annotation indicates a template to expand using parameters annotated with `@Param`. You will likely need to add a `Content-Type` header.\n\n```java\ninterface LoginClient {\n\n  @RequestLine(\"POST /\")\n  @Headers(\"Content-Type: application/xml\")\n  @Body(\"\u003clogin \\\"user_name\\\"=\\\"{user_name}\\\" \\\"password\\\"=\\\"{password}\\\"/\u003e\")\n  void xml(@Param(\"user_name\") String user, @Param(\"password\") String password);\n\n  @RequestLine(\"POST /\")\n  @Headers(\"Content-Type: application/json\")\n  // json curly braces must be escaped!\n  @Body(\"%7B\\\"user_name\\\": \\\"{user_name}\\\", \\\"password\\\": \\\"{password}\\\"%7D\")\n  void json(@Param(\"user_name\") String user, @Param(\"password\") String password);\n}\n...\nclient.xml(\"denominator\", \"secret\"); // \u003clogin \"user_name\"=\"denominator\" \"password\"=\"secret\"/\u003e\nclient.json(\"denominator\", \"secret\"); // {\"user_name\": \"denominator\", \"password\": \"secret\"}\n```\n\n### Headers\nFeign supports settings headers on requests either as part of the api or as part of the client\ndepending on the use case.\n\n#### Set headers using apis\nIn cases where specific interfaces or calls should always have certain header values set, it\nmakes sense to define headers as part of the api.\n\nStatic headers can be set on an api interface or method using the `@Headers` annotation.\n\n```java\n@Headers(\"Accept: application/json\")\ninterface BaseApi\u003cV\u003e {\n  @Headers(\"Content-Type: application/json\")\n  @RequestLine(\"PUT /api/{key}\")\n  void put(@Param(\"key\") String, V value);\n}\n```\n\nMethods can specify dynamic content for static headers using variable expansion in `@Headers`.\n\n```java\n @RequestLine(\"POST /\")\n @Headers(\"X-Ping: {token}\")\n void post(@Param(\"token\") String token);\n```\n\nIn cases where both the header field keys and values are dynamic and the range of possible keys cannot\nbe known ahead of time and may vary between different method calls in the same api/client (e.g. custom\nmetadata header fields such as \"x-amz-meta-\\*\" or \"x-goog-meta-\\*\"), a Map parameter can be annotated\nwith `HeaderMap` to construct a query that uses the contents of the map as its header parameters.\n\n```java\n @RequestLine(\"POST /\")\n void post(@HeaderMap Map\u003cString, Object\u003e headerMap);\n```\n\nThese approaches specify header entries as part of the api and do not require any customizations\nwhen building the Feign client.\n\n#### Setting headers per target\nIn cases where headers should differ for the same api based on different endpoints or where per-request\ncustomization is required, headers can be set as part of the client using a `RequestInterceptor` or a\n`Target`.\n\nFor an example of setting headers using a `RequestInterceptor`, see the `Request Interceptors` section.\n\nHeaders can be set as part of a custom `Target`.\n\n```java\n  static class DynamicAuthTokenTarget\u003cT\u003e implements Target\u003cT\u003e {\n    public DynamicAuthTokenTarget(Class\u003cT\u003e clazz,\n                                  UrlAndTokenProvider provider,\n                                  ThreadLocal\u003cString\u003e requestIdProvider);\n    ...\n    @Override\n    public Request apply(RequestTemplate input) {\n      TokenIdAndPublicURL urlAndToken = provider.get();\n      if (input.url().indexOf(\"http\") != 0) {\n        input.insert(0, urlAndToken.publicURL);\n      }\n      input.header(\"X-Auth-Token\", urlAndToken.tokenId);\n      input.header(\"X-Request-ID\", requestIdProvider.get());\n\n      return input.request();\n    }\n  }\n  ...\n  Bank bank = Feign.builder()\n          .target(new DynamicAuthTokenTarget(Bank.class, provider, requestIdProvider));\n```\n\nThese approaches depend on the custom `RequestInterceptor` or `Target` being set on the Feign\nclient when it is built and can be used as a way to set headers on all api calls on a per-client\nbasis. This can be useful for doing things such as setting an authentication token in the header\nof all api requests on a per-client basis. The methods are run when the api call is made on the\nthread that invokes the api call, which allows the headers to be set dynamically at call time and\nin a context-specific manner -- for example, thread-local storage can be used to set different\nheader values depending on the invoking thread, which can be useful for things such as setting\nthread-specific trace identifiers for requests.\n\n### Advanced usage\n\n#### Base Apis\nIn many cases, apis for a service follow the same conventions. Feign supports this pattern via single-inheritance interfaces.\n\nConsider the example:\n```java\ninterface BaseAPI {\n  @RequestLine(\"GET /health\")\n  String health();\n\n  @RequestLine(\"GET /all\")\n  List\u003cEntity\u003e all();\n}\n```\n\nYou can define and target a specific api, inheriting the base methods.\n```java\ninterface CustomAPI extends BaseAPI {\n  @RequestLine(\"GET /custom\")\n  String custom();\n}\n```\n\nIn many cases, resource representations are also consistent. For this reason, type parameters are supported on the base api interface.\n\n```java\n@Headers(\"Accept: application/json\")\ninterface BaseApi\u003cV\u003e {\n\n  @RequestLine(\"GET /api/{key}\")\n  V get(@Param(\"key\") String);\n\n  @RequestLine(\"GET /api\")\n  List\u003cV\u003e list();\n\n  @Headers(\"Content-Type: application/json\")\n  @RequestLine(\"PUT /api/{key}\")\n  void put(@Param(\"key\") String, V value);\n}\n\ninterface FooApi extends BaseApi\u003cFoo\u003e { }\n\ninterface BarApi extends BaseApi\u003cBar\u003e { }\n```\n\n#### Logging\nYou can log the http messages going to and from the target by setting up a `Logger`.  Here's the easiest way to do that:\n```java\nGitHub github = Feign.builder()\n                     .decoder(new GsonDecoder())\n                     .logger(new Logger.JavaLogger().appendToFile(\"logs/http.log\"))\n                     .logLevel(Logger.Level.FULL)\n                     .target(GitHub.class, \"https://api.github.com\");\n```\n\nThe SLF4JLogger (see above) may also be of interest.\n\n\n#### Request Interceptors\nWhen you need to change all requests, regardless of their target, you'll want to configure a `RequestInterceptor`.\nFor example, if you are acting as an intermediary, you might want to propagate the `X-Forwarded-For` header.\n\n```java\nstatic class ForwardedForInterceptor implements RequestInterceptor {\n  @Override public void apply(RequestTemplate template) {\n    template.header(\"X-Forwarded-For\", \"origin.host.com\");\n  }\n}\n...\nBank bank = Feign.builder()\n                 .decoder(accountDecoder)\n                 .requestInterceptor(new ForwardedForInterceptor())\n                 .target(Bank.class, \"https://api.examplebank.com\");\n```\n\nAnother common example of an interceptor would be authentication, such as using the built-in `BasicAuthRequestInterceptor`.\n\n```java\nBank bank = Feign.builder()\n                 .decoder(accountDecoder)\n                 .requestInterceptor(new BasicAuthRequestInterceptor(username, password))\n                 .target(Bank.class, \"https://api.examplebank.com\");\n```\n\n#### Custom @Param Expansion\nParameters annotated with `Param` expand based on their `toString`. By\nspecifying a custom `Param.Expander`, users can control this behavior,\nfor example formatting dates.\n\n```java\n@RequestLine(\"GET /?since={date}\") Result list(@Param(value = \"date\", expander = DateToMillis.class) Date date);\n```\n\n#### Dynamic Query Parameters\nA Map parameter can be annotated with `QueryMap` to construct a query that uses the contents of the map as its query parameters.\n\n```java\n@RequestLine(\"GET /find\")\nV find(@QueryMap Map\u003cString, Object\u003e queryMap);\n```\n\n#### Static and Default Methods\nInterfaces targeted by Feign may have static or default methods (if using Java 8+).\nThese allows Feign clients to contain logic that is not expressly defined by the underlying API.\nFor example, static methods make it easy to specify common client build configurations; default methods can be used to compose queries or define default parameters.\n\n```java\ninterface GitHub {\n  @RequestLine(\"GET /repos/{owner}/{repo}/contributors\")\n  List\u003cContributor\u003e contributors(@Param(\"owner\") String owner, @Param(\"repo\") String repo);\n\n  @RequestLine(\"GET /users/{username}/repos?sort={sort}\")\n  List\u003cRepo\u003e repos(@Param(\"username\") String owner, @Param(\"sort\") String sort);\n\n  default List\u003cRepo\u003e repos(String owner) {\n    return repos(owner, \"full_name\");\n  }\n\n  /**\n   * Lists all contributors for all repos owned by a user.\n   */\n  default List\u003cContributor\u003e contributors(String user) {\n    MergingContributorList contributors = new MergingContributorList();\n    for(Repo repo : this.repos(owner)) {\n      contributors.addAll(this.contributors(user, repo.getName()));\n    }\n    return contributors.mergeResult();\n  }\n\n  static GitHub connect() {\n    return Feign.builder()\n                .decoder(new GsonDecoder())\n                .target(GitHub.class, \"https://api.github.com\");\n  }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnament%2Fshaboopy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohnament%2Fshaboopy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohnament%2Fshaboopy/lists"}