{"id":18331384,"url":"https://github.com/coveooss/feign-error-decoder","last_synced_at":"2025-04-24T04:51:59.940Z","repository":{"id":37493022,"uuid":"65139488","full_name":"coveooss/feign-error-decoder","owner":"coveooss","description":"Feign ErrorDecoder to map exceptions based on an error code","archived":false,"fork":false,"pushed_at":"2025-04-05T07:15:06.000Z","size":85,"stargazers_count":75,"open_issues_count":3,"forks_count":23,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-04-24T04:51:47.337Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","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/coveooss.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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-08-07T15:10:09.000Z","updated_at":"2024-09-29T14:13:52.000Z","dependencies_parsed_at":"2022-07-15T21:30:56.112Z","dependency_job_id":"a59ccacc-9325-4846-8879-010f0a159708","html_url":"https://github.com/coveooss/feign-error-decoder","commit_stats":null,"previous_names":["coveo/feign-error-decoder"],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coveooss%2Ffeign-error-decoder","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coveooss%2Ffeign-error-decoder/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coveooss%2Ffeign-error-decoder/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coveooss%2Ffeign-error-decoder/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coveooss","download_url":"https://codeload.github.com/coveooss/feign-error-decoder/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250566446,"owners_count":21451230,"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":[],"created_at":"2024-11-05T19:31:04.251Z","updated_at":"2025-04-24T04:51:59.919Z","avatar_url":"https://github.com/coveooss.png","language":"Java","funding_links":[],"categories":["REST错误处理"],"sub_categories":[],"readme":"[![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](https://github.com/coveo/feign-error-decoder/blob/master/LICENSE)\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.coveo/feign-error-decoder/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.coveo/feign-error-decoder)\n\n# [Feign](https://github.com/OpenFeign/feign) Reflection `ErrorDecoder`\n\nThis small library implements `ErrorDecoder` to provide a simple way to map a key returned on an API to a specific exception declared thrown on the [client interface](https://github.com/OpenFeign/feign#basics). \n\nIt's very useful in an application with many microservices calling each others when you want to handle specific checked or runtime exceptions on the client side.\n\n[Blog post](http://source.coveo.com/2016/02/19/microservices-and-exception-handling/) explaining more about the rationale of this library.\n\n# Maven\nThe plugin is available on Maven Central : \n\n```xml\n    \u003cdependency\u003e\n      \u003cgroupId\u003ecom.coveo\u003c/groupId\u003e\n      \u003cartifactId\u003efeign-error-decoder\u003c/artifactId\u003e\n      \u003cversion\u003e3.1.0\u003c/version\u003e\n    \u003c/dependency\u003e\n```\n\n# Usage\nA complete example is shown in this repo as the base setup for the unit tests.\n## Requirements\n### Runtime version\n11+\n### Base Exception class\nIn order to use this library, you need a base exception which all the exceptions declared thrown on the client interface will inherit from. This exception needs to provide a way to access a unique `String` key per subclass.\n```java\npublic abstract class ServiceException extends Exception {\n  private String errorCode;\n  //Constructors omitted\n  \n  public String getErrorCode() {\n    return errorCode;\n  }\n}\n```\n### Class for the error response\nA Class representing the body of the response sent on the API in case of error is also needed. This is the Class that will be instantiated by Feign `Decoder`. It needs a method to get the key that will be used to get the correct exception. It can also optionally have a message that will be injected in the `detailMessage` field of `Throwable`. \n```java\npublic class ErrorCodeAndMessage {\n  private String message;\n  private String errorCode;\n  //getters and setters omitted\n```\n\n## How to use\nWith these requirements met, all left to do is to extend `ReflectionErrorDecoder` and implement the abstract methods required like this : \n```java\nimport feign.Response;\nimport feign.codec.ErrorDecoder;\n\npublic class ServiceExceptionErrorDecoder\n    extends ReflectionErrorDecoder\u003cErrorCodeAndMessage, ServiceException\u003e {\n\n  public ServiceExceptionErrorDecoder(Class\u003c?\u003e apiClass) {\n    super(apiClass, ErrorCodeAndMessage.class, ServiceException.class);\n  }\n\n  @Override\n  protected String getKeyFromException(ServiceException exception) {\n    return exception.getErrorCode();\n  }\n\n  @Override\n  protected String getKeyFromResponse(ErrorCodeAndMessage apiResponse) {\n    return apiResponse.getErrorCode();\n  }\n\n  @Override\n  protected String getMessageFromResponse(ErrorCodeAndMessage apiResponse) {\n    return apiResponse.getMessage();\n  }\n}\n```\nUse the [Feign builder](https://github.com/OpenFeign/feign#customization) to inject the `ErrorDecoder` in your client.\n\n## Supported interface annotations\nThe supported annotations on the interfaces are Feign's `@RequestLine` and Spring `@RequestMapping`. As of version 1.2.0, it also supports `@GetMapping`, `@PostMapping`, `@PutMapping`, `@DeleteMapping` and `@PatchMapping`.\n# Optional customization\n## Throwable message handling\nIn versions 1.x, this library sets the `detailMessage` field of the `Throwable` instance via reflection using the message from the `ReflectionErrorDecoder::getMessageFromResponse` method. This is not supported anymore in JDK 16+ as it's considered an illegal reflective access.\n\nTo work around this, a new interface `ExceptionMessageSetter` has been introduced. It is meant to be used on the base exception class like this :\n```java\npublic abstract class ServiceException extends Exception implements ExceptionMessageSetter {\n  private String detailMessage;\n  \n  @Override\n  public String getMessage() {\n    return detailMessage == null ? super.getMessage() : detailMessage;\n  }\n\n  @Override\n  public void setExceptionMessage(String detailMessage) {\n    this.detailMessage = detailMessage;\n  }\n}\n```\n\nThis way, the `Throwable` message field will be gracefully set without using illegal reflective access. Having an interface instead of an abstract class was decided to make sure this library doesn't creep up an abstract class in your code. However, it has the tradeoff that you need to override the `Throwable::getMessage` yourself.\n\nAll the library dependencies have been made `\u003coptional\u003etrue\u003c/optional\u003e` so you can link on this library in your base exception package without having to transitively pull on Feign.\n\n## Exception inheritance support with classpath scanning\nA `ClassHierarchySupplier` interface is used to support classpath scanning to fetch the hierarchy of abstract exception classes. This allows you to declare a specific base exception as thrown on the client interface and let the interface scan all the possible exceptions that can be thrown.\n### With Spring\nAn *optional* dependency on [Spring Context](https://github.com/spring-projects/spring-framework/tree/master/spring-context) is included in the library to enable this. All you need to do is have Spring framework available in your project and the proper implementation will be instantiated. By default, it will scan the exception children in all packages. To restrict the base package to be scanned, simply use the constructor with the `basePackage` field.\n### Without Spring\nA default implementation is not provided at the moment. Feel free to submit a PR if you implement it!\n\n## Custom `Decoder`\nBy default, this project uses the `JacksonDecoder` implementation of Feign `Decoder` interface. A protected setter is available to use your own `Decoder`.\n\n## Custom fallback `ErrorDecoder`\n`ErrorDecoder.Default` is used by default when no exception is found in the scanned exceptions. A protected setter is available to use your own fallback `ErrorDecoder`.\n\n## Supported constructor arguments\nThe library has a default list of supported argument types for the exception constructors. It supports empty and constructors with any number of `String` or `Throwable` in any order. To extend supported exception types, just override the method `protected List\u003cObject\u003e getSupportedConstructorArgumentInstances()`. Just make sure to return the default types of `String` and `Throwable` if you still want them to be supported.\n\n# Contributing\nPR are always welcome and please open an issue if you find any bugs or wish to request an additional feature. \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoveooss%2Ffeign-error-decoder","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoveooss%2Ffeign-error-decoder","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoveooss%2Ffeign-error-decoder/lists"}