{"id":15043264,"url":"https://github.com/buremba/netty-rest","last_synced_at":"2025-04-10T00:40:58.585Z","repository":{"id":29675791,"uuid":"33218134","full_name":"buremba/netty-rest","owner":"buremba","description":"Yet another high performance REST server based on Netty \u0026 OpenAPI","archived":false,"fork":false,"pushed_at":"2022-11-16T08:26:55.000Z","size":460,"stargazers_count":116,"open_issues_count":9,"forks_count":42,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-04-10T00:40:56.251Z","etag":null,"topics":["high-performance","http-server","java-8","netty","rest-api"],"latest_commit_sha":null,"homepage":"","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/buremba.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}},"created_at":"2015-04-01T00:44:57.000Z","updated_at":"2025-02-07T11:42:55.000Z","dependencies_parsed_at":"2023-01-14T15:26:21.344Z","dependency_job_id":null,"html_url":"https://github.com/buremba/netty-rest","commit_stats":null,"previous_names":[],"tags_count":89,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buremba%2Fnetty-rest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buremba%2Fnetty-rest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buremba%2Fnetty-rest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buremba%2Fnetty-rest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/buremba","download_url":"https://codeload.github.com/buremba/netty-rest/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248137997,"owners_count":21053775,"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":["high-performance","http-server","java-8","netty","rest-api"],"created_at":"2024-09-24T20:48:46.914Z","updated_at":"2025-04-10T00:40:58.556Z","avatar_url":"https://github.com/buremba.png","language":"Java","funding_links":[],"categories":["网络编程"],"sub_categories":["Spring Cloud框架"],"readme":"Netty RESTful Server\n=======\nNetty-rest is a high performance HTTP and WebSocket server implementation based on Netty. It uses `javax.ws.rs` annotations and generates Java bytecode at runtime in order to provide best performance. It basically maps the java methods to endpoints and takes care of validation, serialization / deserialization, authentication and designed for minimum overhead and maximum performance. It can generate Swagger specification automatically so that you can generate client libraries, API documentation easily.\n\nHere is a simple example:\n\n```\nimport org.rakam.server.http.HttpServer;\nimport org.rakam.server.http.HttpServerBuilder;\nimport org.rakam.server.http.HttpService;\nimport org.rakam.server.http.annotations.*;\n\nimport javax.ws.rs.Path;\nimport java.util.Arrays;\nimport java.util.HashSet;\n\npublic class HttpServerTest {\n    public static void main(String[] args) throws Exception {\n        HttpServer build = new HttpServerBuilder()\n                .setHttpServices(new HashSet\u003c\u003e(Arrays.asList(new CustomHttpServer()))).build();\n\n        build.bindAwait(\"127.0.0.1\", 7847);\n    }\n\n    @Path(\"/\")\n    public static class CustomHttpServer extends HttpService {\n        @JsonRequest\n        @ApiOperation(value = \"Parameter demo endpoint\")\n        @Path(\"/parameter\")\n        public String testJsonParameter(@ApiParam(\"param1\") String param1, @ApiParam(\"param2\") int param2) {\n            return param1 + param2;\n        }\n    }\n}\n```\n\nAnd then run the following CURL command:\n\n```\ncurl -X POST http://127.0.0.1:7847/parameter \\\n    -H 'content-type: application/json' \\\n    -d '{\"param1\": \"Hello\", \"param2\": 2}'\n```\n\nIf you don't pass one of the parameters, the server will return `400` response, you can also use complex java beans in parameters and method return signature. The library uses Jackson for serialization of the object that you passed and deserialization of the JSON attributes. It will be mapped to the parameters and the method will be invoked for the API calls.\n\nHere is the complete list of examples for basic operations:\n\n```\nimport org.rakam.server.http.HttpServer;\nimport org.rakam.server.http.HttpServerBuilder;\nimport org.rakam.server.http.HttpService;\nimport org.rakam.server.http.annotations.*;\n\nimport javax.ws.rs.Path;\nimport java.util.Arrays;\nimport java.util.HashSet;\n\npublic class HttpServerTest {\n    public static void main(String[] args) throws Exception {\n        HttpServer build = new HttpServerBuilder()\n                .setHttpServices(new HashSet\u003c\u003e(Arrays.asList(new SimpleHttpService()))).build();\n\n        build.bindAwait(\"127.0.0.1\", 7847);\n    }\n\n    @Path(\"/\")\n    public static class SimpleHttpService extends HttpService {\n        @JsonRequest\n        @ApiOperation(value = \"Bean Demo endpoint\")\n        @Path(\"/bean\")\n        public String testJsonBean(@BodyParam DemoBean demo) {\n            return demo.toString();\n        }\n\n        @JsonRequest\n        @ApiOperation(value = \"Parameter demo endpoint\")\n        @Path(\"/parameter\")\n        public String testJsonParameter(@ApiParam(\"param1\") String param1, @ApiParam(\"param2\") int param2) {\n            return param1 + param2;\n        }\n\n        // You can also use CompletableFuture for async operations\n        @JsonRequest\n        @ApiOperation(value = \"Parameter demo endpoint\")\n        @Path(\"/future-parameter\")\n        public CompletableFuture\u003cString\u003e futureTestJsonParameter(@ApiParam(\"param1\") String param1, @ApiParam(\"param2\") Integer param2, @ApiParam(value = \"param3\", required = false) Long param3) {\n            CompletableFuture\u003cString\u003e future = new CompletableFuture\u003c\u003e();\n            future.complete(param1 + param2 + param3);\n            return future;\n        }\n\n        @JsonRequest\n        @ApiOperation(value = \"Parameter demo endpoint\")\n        @Path(\"/header-cookie-parameter\")\n        public CompletableFuture\u003cString\u003e futureTestJsonParameter(@HeaderParam(\"my-custom-header\") String param1, @CookieParam(\"my-cookie-param\") String param2) {\n            CompletableFuture\u003cString\u003e future = new CompletableFuture\u003c\u003e();\n            future.complete(param1 + param2);\n            return future;\n        }\n\n        @JsonRequest\n        @ApiOperation(value = \"Raw demo endpoint\")\n        @Path(\"/raw\")\n        public void testJsonParameter(RakamHttpRequest request) {\n            request.response(\"cool\").end();\n        }\n\n        public static class DemoBean {\n            public final String test;\n\n            @JsonCreator\n            public DemoBean(@JsonProperty(\"test\") String test) {\n                this.test = test;\n            }\n        }\n    }\n}\n```\n\n# Authentication\n\nYou can implement API key based authentification easily with custom parameters. Here is a simple example:\n\n```\npublic class HttpServerTest {\n    public static void main(String[] args) throws Exception {\n        HttpServer build = new HttpServerBuilder()\n                .setCustomRequestParameters(ImmutableMap.of(\"projectId\", method -\u003e (node, request) -\u003e {\n                    String apiKey = request.headers().get(\"api_key\");\n                    try {\n                        return apiKeyService.findProject(apiKey);\n                    } catch (NotFoundException e) {\n                        throw new HttpRequestException(\"API key is invalid\", HttpResponseStatus.FORBIDDEN);\n                    }\n                })).build();\n                .setHttpServices(new HashSet\u003c\u003e(Arrays.asList(new CustomHttpServer()))).build();\n\n        build.bindAwait(\"127.0.0.1\", 7847);\n    }\n\n    @Path(\"/\")\n    public static class CustomHttpServer extends HttpService {\n        @JsonRequest\n        @ApiOperation(value = \"Parameter demo endpoint\")\n        @Path(\"/list\")\n        public List\u003cString\u003e testJsonParameter(@Named(\"projectId\") int id) {\n            return db.getItemsForProject(id);\n        }\n    }\n}\n```\n\n\n# Request hooks\nYou can add hooks to API calls before the methods are executed and also after they're executed. Here is an example:\n\n```\nHttpServer build = new HttpServerBuilder()\n    .setHttpServices(new HashSet\u003c\u003e(Arrays.asList(new SimpleHttpService())))\n    .addJsonPreprocessor(new RequestPreprocessor() {\n        @Override\n        public void handle(RakamHttpRequest request) {\n            System.out.println(request.getUri());\n        }\n    }, (method) -\u003e true)\n    .addPostProcessor(new ResponsePostProcessor() {\n        @Override\n        public void handle(FullHttpResponse response) {\n            System.out.println(response.getStatus());\n        }\n    }, (method) -\u003e true).build();\n```\n\n# Websockets\nAlthough the library is designed for RESTFul APIs, it also has support for websockets:\n\n```\npublic class HttpServerTest {\n    public static void main(String[] args) throws Exception {\n        HttpServer build = new HttpServerBuilder()\n                .setWebsocketServices(new HashSet\u003c\u003e(Arrays.asList(new SimpleWebhookService()))).build();\n\n        build.bindAwait(\"127.0.0.1\", 7847);\n    }\n    \n    public class SimpleWebhookService extends WebSocketService {\n        private String id;\n\n        @Override\n        public void onOpen(WebSocketRequest request) {\n            id = UUID.randomUUID().toString();\n            System.out.println(String.format(\"%s: started\", id));\n        }\n\n        @Override\n        public void onMessage(ChannelHandlerContext ctx, String message) {\n            System.out.println(String.format(\"%s: sent %s\", id, message));\n        }\n\n        @Override\n        public void onClose(ChannelHandlerContext ctx) {\n            System.out.println(String.format(\"%s: closed\", id));\n        }\n    }\n}\n```\n\n# Exception handling\n\nException hooks are particularly useful for logging them to your API Exception tracker. If you throw `HttpRequestException` in your code, you can set the API call status code and error message but if the `Exception` is not an instance of `HttpRequestException`, the server will return `500` status code.\n\n```\nHttpServer build = new HttpServerBuilder()\n      .setHttpServices(new HashSet\u003c\u003e(Arrays.asList(new SimpleHttpService())))\n      .setExceptionHandler(new HttpServerBuilder.ExceptionHandler() {\n          @Override\n          public void handle(RakamHttpRequest request, Throwable e) {\n\n          }\n      }).build();\n```\n\n# Swagger\n\nThe library automatically generates the Swagger spec for you. You can see the specification in `/api/swagger.json` path. Here is a [real example](http://app.rakam.io/api/swagger.json). I also maintaion a [Slate documentation generator](https://github.com/buremba/swagger-slate) from Swagger specification. This library is compatible with the API documentation generator, [here is an example](http://api.rakam.io).\n\nYou can set your Swagger instance using `HttpServerBuilder.setSwagger`. Here is an example:\n\n```\nInfo info = new Info()\n        .title(\"My API Documentation\")\n        .version(\"0.1\")\n        .description(\"My great API\")\n        .contact(new Contact().email(\"contact@product.com\"))\n        .license(new License()\n                .name(\"Apache License 2.0\")\n                .url(\"http://www.apache.org/licenses/LICENSE-2.0.html\"));\n\nSwagger swagger = new Swagger().info(info)\n        .host(\"app.myapp.io\")\n        .basePath(\"/\")\n        .tags(ImmutableList.copyOf(tags))\n        .securityDefinition(\"api_key\", new ApiKeyAuthDefinition().in(In.HEADER).name(\"api_key\"));\n\nnew HttpServerBuilder().setSwagger(swagger).build()\n```\n\n# Misc\n\nIf you run the library on Linux, it will try to use [Epoll](http://netty.io/wiki/native-transports.html) but you can disable it with `HttpServerBuilder.setUseEpollIfPossible` \n\nYou can also use your own Jackson mapper with `HttpServerBuilder.setMapper`  if you have custom JSON serializers / deserializers.\n\nWe also support [Proxy Protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) if you run the HTTP server behind the load balancer. You can enable it with `HttpServerBuilder.setProxyProtocol`.\n\nYou can take a look at examples in Rakam which heavily uses netty-rest: https://github.com/rakam-io/rakam/blob/master/rakam/src/main/java/org/rakam/plugin/user/UserHttpService.java\n\n# Profiling\n\nThe library exposes an MBean called `org.rakam.server.http:name=SHttpServer`. If you attach the JVM instance you can call `getActiveClientCount` and `getActiveRequests` for the list of active request the execution time of each request.\n\n# To be done\n- Javadocs\n- API usage monitoring tool\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fburemba%2Fnetty-rest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fburemba%2Fnetty-rest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fburemba%2Fnetty-rest/lists"}