{"id":16633174,"url":"https://github.com/be-hase/honoumi","last_synced_at":"2025-06-25T08:07:02.715Z","repository":{"id":16196485,"uuid":"18943187","full_name":"be-hase/honoumi","owner":"be-hase","description":"Simple and lightweight RESTful framework which can be monitored in real time the content of the request.","archived":false,"fork":false,"pushed_at":"2016-09-24T14:33:52.000Z","size":91,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-11T21:43:29.511Z","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":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/be-hase.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":"2014-04-19T14:47:10.000Z","updated_at":"2016-09-24T14:32:51.000Z","dependencies_parsed_at":"2022-09-11T15:23:21.779Z","dependency_job_id":null,"html_url":"https://github.com/be-hase/honoumi","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/be-hase/honoumi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/be-hase%2Fhonoumi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/be-hase%2Fhonoumi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/be-hase%2Fhonoumi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/be-hase%2Fhonoumi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/be-hase","download_url":"https://codeload.github.com/be-hase/honoumi/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/be-hase%2Fhonoumi/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261832679,"owners_count":23216497,"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-10-12T05:12:23.662Z","updated_at":"2025-06-25T08:07:02.681Z","avatar_url":"https://github.com/be-hase.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Honoumi\nHonoumi is a RESTful Micro-framework (for JSON).\n\n## Feature\n\n* Network / Socket\n\t* Netty. (support async response)\n* Dependency injection\n\t* Google Guice\n* Logging\n\t* logback\n* JSON\n\t* Jackson (faster ver)\n* Utility Library\n\t* Guava\n\t* joda-time\n\t* apache commons\n* Monitoring\n\t* Esper (Can write query by runtime)\n\nCaution: multipart/form-data is not yet supported.\n\n## How to use ??\n\n### 1. Install\n\nWrite your pom.xml.\n\n```xml\n  \u003crepositories\u003e\n    \u003crepository\u003e\n      \u003cid\u003ehonoumi-repo\u003c/id\u003e\n      \u003curl\u003ehttps://raw.githubusercontent.com/be-hase/maven-repo/honoumi-0.1.5\u003c/url\u003e\n    \u003c/repository\u003e\n  \u003c/repositories\u003e\n\n  \u003cdependencies\u003e\n    \u003cdependency\u003e\n      \u003cgroupId\u003ecom.be-hase\u003c/groupId\u003e\n      \u003cartifactId\u003ehonoumi\u003c/artifactId\u003e\n      \u003cversion\u003e0.1.5\u003c/version\u003e\n    \u003c/dependency\u003e\n  \u003c/dependencies\u003e\n```\n\n### 2. Write in main(end-point) method.\n\n```java\npublic static void main(String[] args) {\n\tRouter router = new Router();\n\t// setting your router\n\tRouter router = new Router();\n\trouter.GET().route(\"/blog/{id}\").with(Controller.class, \"show\");\n\n\t// create server and start !\n\tServer server = Server.create(\"main\", router);\n\tserver.start();\n}\n```\n\n## Basic Usage\n\n### Routing\n\nCreate a Router instance, write a set of routing. \nPlease pass parameters when you start the server this Router. (See below)\n\n```java\n//create router\nRouter mainRouter = new Router();\nmainRouter.GET().route(\"/v1/user/{userId}\").with(UserController.class, \"show\");\nmainRouter.POST().route(\"/v1/user\").with(UserController.class, \"new\");\nmainRouter.POST().route(\"/v1/user/{userId}/edit\").with(UserController.class, \"edit\");\n\nmainRouter.GET().route(\"/healthcheck\").with(HelthCheckController.class, \"index\");\n\n```\n\n### Controller\n\n#### Simple Controller\n\nIf you want to response OK.\n\n```java\npublic class HelthCheckController {\n\t\n\tpublic void index(\n\t\t\tMessageEvent evt\n\t\t\t) {\t\t\n\t\tResponse.execute(evt, HttpResponseStatus.OK, null, \"OK\");\n\t}\n}\n```\n\n#### Getting Basic parameters into your controllers\n\nBy using the annotations, you can get the basic parameters.\n\n```java\npublic class HogeController {\n\tprivate static Logger logger = LoggerFactory.getLogger(HogeController.class);\n\n\tpublic void formPost(\n\t\t\tMessageEvent evt,\n\t\t\t@Body String body,\n\t\t\t@FormParam(\"formParam\") String formParam,\n\t\t\t@FormParams Map\u003cString, String\u003e formParams,\n\t\t\t@Header(\"X-Real-IP\") String header,\n\t\t\t@Headers Map\u003cString, String\u003e headers,\n\t\t\t@PathParam(\"hoge\") String pathParam,\n\t\t\t@PathParams Map\u003cString, String\u003e pathParams,\n\t\t\t@QueryParam(\"bar\") String queryParam,\n\t\t\t@QueryParams Map\u003cString, String\u003e queryParams\n\t\t\t) {\n\t\t\t\n\t\tResponse.execute(evt, HttpResponseStatus.OK, null, \"OK\"); //async response.\n\t\t\t\n\t\tlogger.debug(\"body : {}\", body);\n\t\tlogger.debug(\"formParam : {}\", formParam);\n\t\tlogger.debug(\"formParams : {}\", formParams);\n\t\tlogger.debug(\"header : {}\", header);\n\t\tlogger.debug(\"headers : {}\", headers);\n\t\tlogger.debug(\"pathParam : {}\", pathParam);\n\t\tlogger.debug(\"pathParams : {}\", pathParams);\n\t\tlogger.debug(\"queryParam : {}\", queryParam);\n\t\tlogger.debug(\"queryParams : {}\", queryParams);\n\t}\n}\n\n```\n\n#### Use Argument Resolver\n\nIt also allows that if you create an Argument Resolver, to get the controller to any parameter. \n\nFirst, I want to create a Resolve.\n\n```java\n@Singleton\npublic class LogginedUserResolver implements ArgumentResolver\u003cLogginedUser\u003e{\n\t\n\t\n\tpublic LogginedUser resolveArgument(ChannelHandlerContext ctx, MessageEvent evt) {\n\t\tLogginedUser user = new LogginedUser();\n\t\t\n\t\t//user.setName...etc;\n\t\t\n\t\treturn user;\n\t}\n\n\tpublic boolean supportedType(Class\u003c?\u003e klass) {\n\t\treturn klass.isAssignableFrom(LogginedUser.class);\n\t}\n}\n```\n\nTo create annotation of Resolver that you created.\n\n```java\n@WithArgumentResolver(LogginedUserResolver.class)\n@Retention(RetentionPolicy.RUNTIME)\n@Target({ElementType.PARAMETER})\npublic @interface LogginedUserAnnotation {\n\n}\n\n```\n\nAfter you create the file of the above two, written controller as follows.\n\n\n```java\npublic class TestController {\n\n    public void index(\n            @LoggedInUser LogginedUser loggedInUser\n            ) {\n\n        //do something with the parameters...\n    }\n\n}\n```\n\n#### Use Filter\n\nIf you want to write a common processed by the controller, using the Filter. \n\nFirst of all, create a class that implement the Filter. \nby the filer method returns true, continue processing of the controller or the subsequent filter. \nOn the other hand, end with this method in the case of false. \nSo, to response properly in this case.\n\n```java\n@Singleton\npublic class CheckHttpHeaderFilter implements Filter {\n\n\tpublic boolean filter(ChannelHandlerContext ctx, MessageEvent evt) {\n\t\tHttpRequest request = (HttpRequest)evt.getMessage();\n\t\t\n\t\tfinal HttpHeaders httpHeaders = request.headers();\n\t\t\n\t\tif (!httpHeaders.contains(\"X-HOGE\")) {\n\t\t\tResponse.execute(evt, HttpResponseStatus.BAD_REQUEST, null, \"INVALID HEADER\");\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\treturn true;\n\t}\n}\n\n```\n\nPlease to grant annotation to the controller. \nEither is fine in the method in the class. \nYou can also be more than one grant. \nIn that case, filter is called in the order in which they were granted. \n(class filter → method filter → controller method)\n\n```java\npublic class TestController {\n\n    @WithFilter({CheckHttpHeaderFilter.class})\n    public void index(MessageEvent evt) {\t\t\n\t\t    Response.execute(evt, HttpResponseStatus.OK, null, \"OK\");\n    }\n}\n```\n\n### Dependency injection\n\nYou can use the Google Guice.\nGoogle guice document is here.\n\nhttps://code.google.com/p/google-guice/wiki/Motivation?tm=6\n\n```java\npublic class MyModule extends AbstractModule {\n\n\t@Override\n\tprotected void configure() {\n\t\tbind(UserService.class).to(UserServiceImpl.class).in(Singleton.class);\n\n\t\tValidatorFactory factory = Validation.buildDefaultValidatorFactory();\n\t\tValidator validator = factory.getValidator();\n\t\tbind(Validator.class).toInstance(validator);;\n\t}\n}\n\n```\n\nPlease pass this Module as parameters when you start the server. (See below)\n\n\n### Configuration Properties\n\nYou might have properties which writed as follows.\n\n```\nbar.int=1234\nbar.string=string\nbar.boolean=true\n\nhoge=hoge\n%local.hoge=localHoge\n%release.hoge=releaseHoge\n\n```\n\nIf you want to get the property, do the following:\n\n```java\n//string\nString barString = ApplicationProperties.get(\"bar.string\", \"\");\n\n//int\nInteger barInt = ApplicationProperties.getInt(\"bar.int\", 0);\n\n//boolean\nBoolean barBoolean = ApplicationProperties.getBoolean(\"bar.boolean\", false);\n\n```\n\nIn addition, if you put a \"%\" in the prefix, the value can be retrieved in response to the activation mode will change. \nIf there is no key for the mode corresponding, that nothing sticks will be selected.\n\n```java\n//when local mode, return \"localHoge\"\nString localHoge = ApplicationProperties.get(\"hoge\", \"\");\n\n//when release mode, return \"releaseHoge\"\nString releaseHoge = ApplicationProperties.get(\"hoge\", \"\");\n\n//when dev mode, return \"local\"\nString devHoge = ApplicationProperties.get(\"hoge\", \"\");\n\n```\n\nYou can also get the value of a different mode if you specify the full name.\n\n```java\nString releaseHoge = ApplicationProperties.get(\"%release.hoge\", \"\");\n```\n\n### Start Server\n\nPlease, start the server method which is the end point. \nThis is the main method of the Main class in general.\n\n```java\npublic class Main {\n\tprivate static final Logger logger = LoggerFactory.getLogger(Main.class);\n\t\n\tpublic static void main(String[] args) {\n\t\t//create router\n    Router mainRouter = new Router();\n    mainRouter.GET().route(\"/v1/user/{userId}\").with(UserController.class, \"show\");\n    mainRouter.POST().route(\"/v1/user\").with(UserController.class, \"new\");\n    mainRouter.POST().route(\"/v1/user/{userId}/edit\").with(UserController.class, \"edit\");\n    \n    mainRouter.GET().route(\"/healthcheck\").with(HelthCheckController.class, \"index\");\n\t\t\n\t\t//create guice module for DI (option)\n\t\tList\u003cAbstractModule\u003e modules = Lists.newArrayList();\n\t\tmodules.add(new MyModule());\n\t\t\n\t\t//create server and start\n\t\tServer mainServer = Server.create(\"mainServer\", mainRouter, modules);\n\t\tmainServer.start();\n\t}\n}\n\n```\n\nFirst argument of Server.create is the name of the server. \n\nYou can also take advantage of this name, to set and port of server, the option of netty to properties.\n\n```\n\nmainServer.bind.port=21014\nmainServer.http.encoding=UTF-16\nmainServer.http.keepAlive=false\nmainServer.http.chunkAggregate=true\nmainServer.http.chunkAggregate.maxContentLength=65535\nmainServer.http.contentCompress=true\nmainServer.netty.options.reuseAddress=true\nmainServer.netty.options.child.reuseAddress=true\nmainServer.netty.options.child.keepAlive=true\nmainServer.netty.options.child.tcpNoDelay=true\n\n```\n\nIn addition, you can also pass a ServerSocketChannelFactory of netty to create method. \nWe will use the create method of this place if you want to change the thread pool.\n\n### Start JAR\n\nWhen you start server, please specify application.environment (required) application.properties (Optional).\n\n```\nex: \n-Dapplication.environment=local -Dapplication.properties=application.properties\n```\n\n※ application.properties allows you to specify multiple comma-separated.\n\n## Monitoring\n\nHonoumi incorporates a esper inside.  \nSo, by registering a query freely, it is possible to do such monitoring what you want. (In real time)\n\nPlease see also this page.  \nhttps://github.com/be-hase/honoumi-monitoring-admin\n\n## What 'Honoumi' means?\n\nThis name is derived from the character of Honoka and Umi of Love Live(Japanese animation).\n\n\n## Want to know more information?\n\nI am currently creating a detailed document page.  \nI'm sorry, please wait a while longer.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbe-hase%2Fhonoumi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbe-hase%2Fhonoumi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbe-hase%2Fhonoumi/lists"}