{"id":15180580,"url":"https://github.com/darkredz/zeko-restapi-framework","last_synced_at":"2025-10-14T05:23:21.514Z","repository":{"id":42204488,"uuid":"259352372","full_name":"darkredz/zeko-restapi-framework","owner":"darkredz","description":"Asynchronous web framework for Kotlin. Create REST APIs in Kotlin easily with automatic Swagger/OpenAPI doc generation","archived":false,"fork":false,"pushed_at":"2024-07-25T09:12:13.000Z","size":321,"stargazers_count":19,"open_issues_count":3,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-08T00:29:34.210Z","etag":null,"topics":["kotlin","kotlin-coroutines","microservice","mvc","openapi","rest-api","swagger","vertx","vertx-web","web-framework","zeko","zeko-restapi"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","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/darkredz.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":"2020-04-27T14:32:35.000Z","updated_at":"2024-09-01T10:37:58.000Z","dependencies_parsed_at":"2024-05-02T07:53:39.449Z","dependency_job_id":"4f4a009e-90d3-4a8b-b7e4-24be84128980","html_url":"https://github.com/darkredz/zeko-restapi-framework","commit_stats":null,"previous_names":[],"tags_count":56,"template":false,"template_full_name":null,"purl":"pkg:github/darkredz/zeko-restapi-framework","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darkredz%2Fzeko-restapi-framework","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darkredz%2Fzeko-restapi-framework/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darkredz%2Fzeko-restapi-framework/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darkredz%2Fzeko-restapi-framework/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/darkredz","download_url":"https://codeload.github.com/darkredz/zeko-restapi-framework/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darkredz%2Fzeko-restapi-framework/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264923154,"owners_count":23683717,"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":["kotlin","kotlin-coroutines","microservice","mvc","openapi","rest-api","swagger","vertx","vertx-web","web-framework","zeko","zeko-restapi"],"created_at":"2024-09-27T16:23:03.349Z","updated_at":"2025-10-14T05:23:16.480Z","avatar_url":"https://github.com/darkredz.png","language":"Kotlin","readme":"# Zeko Rest API Framework\n![alt Zeko RestAPI Framework](./logo.svg \"Zeko lightweight RESTful API framework for Kotlin\")\n\n\u003cp align=\"left\"\u003e\n    \u003ca href=\"https://search.maven.org/search?q=g:%22io.zeko%22\"\u003e\n        \u003cimg src=\"https://img.shields.io/maven-central/v/io.zeko/zeko-restapi.svg?label=Maven%20Central\" alt=\"Maven Central\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"LICENSE\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/license-Apache%202-blue.svg?maxAge=2592000\" alt=\"Apache License 2\" /\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://github.com/KotlinBy/awesome-kotlin\"\u003e\n        \u003cimg src=\"https://kotlin.link/awesome-kotlin.svg\" alt=\"Awesome Kotlin Badge\" /\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\nZeko Rest API Framework is an asynchronous web framework written for Kotlin language. \nCreate restful APIs in Kotlin easily with automatic Swagger/OpenAPI documentation generation.\nIt is built on top of [Vert.x event-driven toolkit](https://vertx.io) and designed to be simple \u0026 fun to use. \n\nThis library is open source and available under the Apache 2.0 license. Please leave a star if you've found this library helpful!\n\n## Features\n- No configuration files, no XML or YAML, lightweight, easy to use\n- Event driven \u0026 non-blocking built on top of [Vert.x 4.1.1](https://vertx.io) \n- Fast startup \u0026 performance\n- Supports Kotlin coroutines\n- Automatic Swagger/OpenAPI doc generation for your RESTful API\n- Code generation via Kotlin kapt\n- Largely reflection-free, consumes little memory\n- [Project creator](https://github.com/darkredz/zeko-restapi-examples#project-creator) included\n- Add endpoint validations easily\n- Run cron jobs easily!\n- Mail service with Sendgrid \u0026 Mandrill\n- Simple SQL builder \u0026 data mapper\n- Built with JVM 8, works fine with JVM 9/10 and above\n \n## Getting Started\nThis framework is very easy-to-use. After reading this short documentation, you will have learnt enough.\n\nOr look at the [example project](https://github.com/darkredz/zeko-restapi-examples) straight away! It's simple enough!\n\nThe example project includes a project creator tool which is the quickest way to create a new project (accessible at /project/create endpoint)\n\n## Installation\nAdd this to your maven pom.xml\n\n    \u003cdependency\u003e\n      \u003cgroupId\u003eio.zeko\u003c/groupId\u003e\n      \u003cartifactId\u003ezeko-restapi\u003c/artifactId\u003e\n      \u003cversion\u003e1.5.4\u003c/version\u003e\n    \u003c/dependency\u003e\n    \u003c!-- Jasync Mysql driver if needed --\u003e\n    \u003cdependency\u003e\n       \u003cgroupId\u003ecom.github.jasync-sql\u003c/groupId\u003e\n       \u003cartifactId\u003ejasync-mysql\u003c/artifactId\u003e\n       \u003cversion\u003e1.2.3\u003c/version\u003e\n    \u003c/dependency\u003e\n    \u003c!-- Hikari Mysql connection pool if needed --\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003ecom.zaxxer\u003c/groupId\u003e\n        \u003cartifactId\u003eHikariCP\u003c/artifactId\u003e\n        \u003cversion\u003e5.0.1\u003c/version\u003e\n    \u003c/dependency\u003e\n    \u003c!-- Vertx jdbc client if needed --\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003eio.vertx\u003c/groupId\u003e\n        \u003cartifactId\u003evertx-jdbc-client\u003c/artifactId\u003e\n        \u003cversion\u003e4.1.1\u003c/version\u003e\n    \u003c/dependency\u003e\n    \u003cdependency\u003e\n        \u003cgroupId\u003eorg.jetbrains.kotlinx\u003c/groupId\u003e\n        \u003cartifactId\u003ekotlinx-coroutines-core\u003c/artifactId\u003e\n        \u003cversion\u003e1.3.9\u003c/version\u003e\n    \u003c/dependency\u003e\n    \n### Enable Annotation Processor\nIn order to get your zeko app up and running, you would need to add annotation preprocessor to your maven pom.\nThis will automatically generates routes, cron and Swagger 2.0/OpenAPI documentation from your controllers.\nSet your kotlin.version accordingly for the KAPT to work. \n\n    \u003cplugin\u003e\n        \u003cartifactId\u003ekotlin-maven-plugin\u003c/artifactId\u003e\n        \u003cgroupId\u003eorg.jetbrains.kotlin\u003c/groupId\u003e\n        \u003cversion\u003e${kotlin.version}\u003c/version\u003e\n    \n        \u003cexecutions\u003e\n            \u003cexecution\u003e\n                \u003cid\u003ekapt\u003c/id\u003e\n                \u003cgoals\u003e\n                    \u003cgoal\u003ekapt\u003c/goal\u003e\n                \u003c/goals\u003e\n                \u003cconfiguration\u003e\n                    \u003csourceDirs\u003e\n                        \u003csourceDir\u003esrc/main/kotlin\u003c/sourceDir\u003e\n                    \u003c/sourceDirs\u003e\n    \n                    \u003cannotationProcessorPaths\u003e\n                        \u003cannotationProcessorPath\u003e\n                            \u003cgroupId\u003eio.zeko\u003c/groupId\u003e\n                            \u003cartifactId\u003ezeko-restapi\u003c/artifactId\u003e\n                            \u003cversion\u003e${zeko-restapi.version}\u003c/version\u003e\n                        \u003c/annotationProcessorPath\u003e\n                    \u003c/annotationProcessorPaths\u003e\n    \n                    \u003cannotationProcessors\u003e\n                        \u003cannotationProcessor\u003eio.zeko.restapi.annotation.codegen.RouteSchemaGenerator\u003c/annotationProcessor\u003e\n                    \u003c/annotationProcessors\u003e\n    \n                    \u003cannotationProcessorArgs\u003e\n                        \u003cprocessorArg\u003eswagger.apiVersion=1.0\u003c/processorArg\u003e\n                        \u003cprocessorArg\u003eswagger.title=Simple Rest API\u003c/processorArg\u003e\n                        \u003cprocessorArg\u003eswagger.description=This is a simple RESTful API demo\u003c/processorArg\u003e\n                        \u003cprocessorArg\u003eswagger.host=localhost\u003c/processorArg\u003e\n                        \u003cprocessorArg\u003eswagger.basePath=/\u003c/processorArg\u003e\n                        \u003cprocessorArg\u003eswagger.sampleResultDir=${project.basedir}/api-results\u003c/processorArg\u003e\n                        \u003cprocessorArg\u003eswagger.outputFile=${project.basedir}/api-doc/swagger.json\u003c/processorArg\u003e\n                        \u003cprocessorArg\u003eswagger.cmpSchemaDir=${project.basedir}/api-schemas\u003c/processorArg\u003e\n                        \u003cprocessorArg\u003edefault.produces=application/json\u003c/processorArg\u003e\n                        \u003cprocessorArg\u003edefault.consumes=application/x-www-form-urlencoded\u003c/processorArg\u003e\n                    \u003c/annotationProcessorArgs\u003e\n                \u003c/configuration\u003e\n            \u003c/execution\u003e\n            \n            //.... other execution ...\n        \u003c/executions\u003e\n    \u003c/plugin\u003e\n\n### Compile \u0026 Run\nCompile and run your vertx app:\n```\nmvn clean compile vertx:run -Dvertx.verticle=\"io.zeko.restapi.examples.BootstrapVerticle\"\n```\nYou should see the following output during compilation, after you have created and annotated your endpoints in controller classes\n```\n[INFO] --- vertx-maven-plugin:1.0.18:initialize (vmp) @ simple-api ---\n[INFO] \n[INFO] --- kotlin-maven-plugin:1.3.61:kapt (kapt) @ simple-api ---\n[INFO] Note: Writing controller schema /Users/leng/Documents/zeko-restapi-example/target/generated-sources/kaptKotlin/compile/UserControllerSchema.kt\n[INFO] Note: Writing route class /Users/leng/Documents/zeko-restapi-example/target/generated-sources/kaptKotlin/compile/GeneratedRoutes.kt\n[INFO] Note: Writing swagger file to /Users/leng/Documents/zeko-restapi-example/api-doc/swagger.json\n[INFO] Note: Writing cron class /Users/leng/Documents/zeko-restapi-example/target/generated-sources/kaptKotlin/compile/GeneratedCrons.kt\n[INFO] \n```\nNow you can view the swagger.json under the directory configured (swagger.outputFile) in any Swagger/OpenAPI UI tools or Postman\n\n\n## Bootstrapping\nZeko doesn't include a DI container, instead of reinventing the wheel, it is recommended to use something awesome like [Koin](https://insert-koin.io) \nor [Dagger](https://github.com/google/dagger) to manage your project's dependency injection. The following instructions will be using Koin DI framework.\n\nBootstrapping for Zeko rest framework is simple. If you would like to use the built-in SQL builder \u0026 client, you could follow the same structure as the \n[example project](https://github.com/darkredz/zeko-restapi-examples/tree/master/src/main/kotlin/io/zeko/restapi/examples)\n\n```\nBootstrapVerticle.kt\nKoinVerticleFactory.kt\nDB.kt\nAppDBLog.kt\t\nRestApiVerticle.kt\n```\nThe 5 Kotlin classes above are crucial for the app to run.\n#### BootstrapVerticle\n[BootstrapVerticle](https://github.com/darkredz/zeko-restapi-examples/blob/master/src/main/kotlin/io/zeko/restapi/examples/BootstrapVerticle.kt) is the main entry file of the app. \nSetup your DI here with Koin for most things that are shared globally such as logger, DB pool, web client pool, JWT auth configs, mail service, etc.\n\n#### DB class\nDB class is written to setup database connection pool using Jasync, Hikari-CP or Vert.x JDBC client.\nFrom your repository class, access the DB object via Koin DI container:\n```kotlin\nclass UserRepo(val vertx: Vertx) : KoinComponent {\n    val db: DB by inject()\n\n    suspend fun getActiveUser(id: Int): User? {\n        var user: User? = null\n        db.session().once { sess -\u003e\n            val sql = Query().fields(\"id\", \"first_name\", \"last_name\", \"email\", \"last_access_at\")\n                            .from(\"user\")\n                            .where((\"id\" eq id) and (\"status\" eq 1))\n                            .limit(1).toSql()\n\n            val rows = sess.query(sql, { User(it) }) as List\u003cUser\u003e\n            if (rows.isNotEmpty()) user = rows[0]\n        }\n        return user\n    }\n}\n```\n\n#### AppDBLog\nDuring development logging the SQL and prepared statement's parameters will be really useful.\nIn order to do so, call the setQueryLogger() method on DBSession after it is initialized.\n[AppDBLog](https://github.com/darkredz/zeko-restapi-examples/blob/master/src/main/kotlin/io/zeko/restapi/examples/AppDBLog.kt) \nis a simple implementation of DBLogger interface which prints out the logs with vert.x Logger\n\n```kotlin\nval dbLogger = AppDBLog(logger).setParamsLogLevel(DBLogLevel.ALL)\nJasyncDBSession(connPool, connPool.createConnection()).setQueryLogger(dbLogger) \n```\n\nImplement your own DBLogger for more advanced usage.\n\n\n#### RestApiVerticle\nThis would be the place where all the route and cronjob executions happen.\nYou do not have to define all your endpoints route here manually. \nIf they're annotated in the controllers, the routes code will be generated by Zeko KAPT.\n\nYour would just need to bind the generated routes by calling:\n```kotlin\nbindRoutes(\"your.name.controllers.GeneratedRoutes\", router, logger, true)\n// Or less overhead\nbindRoutes(your.name.controllers.GeneratedRoutes(vertx), router, logger, true)\n```\n\nIf you have controller classes in different packages, then it is required to call bindRoutes multiple times:\n```kotlin\nbindRoutes(\"your.name.controllers.GeneratedRoutes\", router, logger, true)\nbindRoutes(\"his.controllers.GeneratedRoutes\", router, logger, true)\n```\n\nThe same applies to generated cron jobs\n```kotlin\nstartCronJobs(\"my.example.jobs.GeneratedCrons\", logger)\n// Or\nstartCronJobs(my.example.jobs.GeneratedCrons(vertx, logger), logger)\n```\n\nDefault error handler, which will output message with status code 500 if any exception is thrown.\n503 for connection timeout if you use TimeoutHandler for the routes.\n```kotlin\nhandleRuntimeError(router, logger)\n```\n\n## Controllers\nFor any endpoint to work, you would need to create a class and extends ApiController.\n```kotlin\nimport io.zeko.restapi.annotation.http.*\nimport io.zeko.restapi.annotation.Params\nimport io.zeko.restapi.core.controllers.ApiController\nimport io.zeko.restapi.core.validations.ValidateResult\n\n@Routing(\"/user\")     // \u003c----- (1)\nclass UserController : ApiController {\n\n    constructor(vertx: Vertx, logger: Logger, context: RoutingContext) : super(vertx, logger, context)\n\n    @GetSuspend(\"/show-user/:user_id\", \"Show User profile data\")    // \u003c----- (2)\n    @Params([    // \u003c----- (3)\n        \"user_id =\u003e required, isInteger, min;1, max;99999999\",\n        \"country =\u003e inArray;MY;SG;CN;US;JP;UK\"\n    ])\n    suspend fun getUser(ctx: RoutingContext) {\n        val res = validateInput()   // \u003c----- (4)\n        if (!res.success) {   // \u003c----- (5)\n            return\n        }\n\n        val uid = res.values[\"user_id\"].toString().toInt()\n        // val user = \u003ccall your business logic bla...\u003e\n        endJson(user)      // \u003c----- (6)\n    }\n}\n```\n\n1. This Routing annotation will add a prefix to the endpoint URL for the entire class. Thus, the final URI for getUser() will be */user/show-user/123*\n\n2. GetSuspend defines an endpoint route, you should use *@Get* if it isn't a suspend function call. First parameter is the URI, second is the description which will be used to generate the Swagger documentation.\nList of routing annotations (add Suspend suffix if it is calling a suspend method):\n    \n        Get\n        Post\n        Delete\n        Put\n        Head\n        Patch\n        Options\n        Routing // define your own\n\n3. Params indicates that the parameters this endpoint requires. It accepts an array of strings which is the rule definitions for the fields needed.\n\n    The format can be explained as:\n    ```\n    \"field_name =\u003e required, rule1, rule2;rule2_param, rule3_param;rule3_param\"\n    ```\n    If required is not defined then the parameter would be optional. \n    Each rule is separated by a comma (,) while the rule's parameters are separated by semi-colon (;)\n    \n    ```\n    user_id =\u003e required, isInteger, min;1, max;99999999\n    ```\n    The rule definition above means that user_id field is required, should be an integer, minimum value of 1 and max of 99999999\n\n4. Calls the built in input validation which returns [ValidateResult](https://github.com/darkredz/zeko-restapi-framework/blob/master/src/main/kotlin/io/zeko/restapi/core/validations/ValidateResult.kt)\nres.values contains of the parameter values in a hash map.\n\n5. Check if the the validation is successful. If it failed, by default, ApiController will output the errors in JSON format with status code 400.\n    ```\n    {\n        \"error_code\": 400,\n        \"errors\": {\n            \"user_id\": [\n                \"User Id is not a valid integer value\",\n                \"User Id minimum value is 1\",\n                \"User Id maximum value is 99\"\n            ]\n        }\n    }\n    ```\n\n    You could override the status code and error messages by \n    defining a different status code \u0026 error messages in the form of Map\u003cString, String\u003e. \n    \n    Refer to [ValidationError.defaultMessages](https://github.com/darkredz/zeko-restapi-framework/blob/master/src/main/kotlin/io/zeko/restapi/core/validations/ValidationError.kt) on how to define your custom Rule's error messages\n    \n   ```kotlin\n    override fun inputErrorMessages() = ValidationError.defaultMessages\n    override fun validateInput(statusCode: Int): ValidateResult = super.validateInput(422)\n    ```\n   \n6. endJson() will convert the entity or any other object to JSON with Content-Type as application/json and status code 200.\nDo remember to define your Jackson [naming strategy](https://github.com/darkredz/zeko-restapi-examples/blob/master/src/main/kotlin/io/zeko/restapi/examples/BootstrapVerticle.kt#L33) in the bootstrap class\n\n\n## Validations\nFor the list of predefined rules, refer to keys of [ValidationError.defaultMessages](https://github.com/darkredz/zeko-restapi-framework/blob/master/src/main/kotlin/io/zeko/restapi/core/validations/ValidationError.kt)\nor [RuleSet](https://github.com/darkredz/Zeko-Validator/blob/master/src/main/java/io/zeko/validation/RuleSet.java) for all the rules method and its parameters.\n\n\n## Cron Jobs\nCron job would be similar to the controller routes. You would need to create a class and extends CronJob\n\n```kotlin\npackage my.example.jobs\n\nimport io.vertx.core.json.Json\nimport io.zeko.restapi.annotation.cron.Cron\nimport io.zeko.restapi.annotation.cron.CronSuspend\nimport io.zeko.restapi.core.cron.CronJob\n\nclass UserCronJob(vertx: Vertx, logger: Logger) : CronJob(vertx, logger), KoinComponent {\n\n    val userService: UserService by inject()\n\n    @CronSuspend(\"*/2 * * * *\")\n    suspend fun showUser() {\n        val user = userService.getProfileStatus(1)\n        logger.info(\"Cron showUser \" + Json.encode(user))\n    }\n\n    @Cron(\"*/1 * * * *\")\n    fun showUserNormal() {\n        val uid = 1\n        val user = User().apply {\n            id = uid\n            firstName = \"I Am\"\n            lastName = \"Mango\"\n        }\n        logger.info(\"Cron showUserNormal \" + Json.encode(user))\n    }\n\n}\n```\n@CronSuspend should be used on any suspend calls while @Cron should be used on method calls without Kotlin coroutine.\nThe annotation accepts a string value which should be your good old [UNIX cron expression](https://crontab.guru/)\n\nIn the sample cron job above, showUser will be executed in every 2 minute, and showUserNormal in every 1 minute.\n\nAll cron jobs in the same package will be aggregated into a GeneratedCrons class during kapt phase.\n\nStart the cron job from RestApiVerticle:\n```kotlin\nstartCronJobs(my.example.jobs.GeneratedCrons(vertx, logger), logger)\n```\n\n## Mail Service\nThe framework provides two mail service: [Sendgird](https://sendgrid.com/) and [Mandrill](https://mandrill.com/)\nThe mail service classes are using [Vert.x web client](https://vertx.io/docs/vertx-web-client/kotlin/) to call the service APIs.\n\nExample sending via SendGrid. First, create an instance of SendGridMail.\n```kotlin\nval webClient = SendGridMail.createSharedClient(vertx)\nval sendGridConfig = MailConfig(\n        \"Your Api Key\",\n        \"noreply@zeko.io\", \"Zeko\",\n        true, \"dev-app@gmail.com\"  // this confines the service to send all mails to this Dev email address, useful in dev mode\n)\nval mailService = SendGridMail(webClient, sendGridConfig, get())\n```\n\nCall sendEmail() method to send out emails.\n```kotlin\nval tags = listOf(\"super-duber-app-with-zeko.com\", \"register\")\nval res: MailResponse = mailService.send(\n        email, fullName,\n        \"Register Success\",\n        \"\u003ch2\u003eSuccess!\u003c/h2\u003e\u003cp\u003eYou are now a new member!\u003c/p\u003e\", \n        \"Success! You are now a new member!\",\n        tags\n)\n```\n\n#### Retries\nIt would be better if the email will be resent if the API call failed.\nThe following code will retry to send email 3 more times if the first call failed with a 2 second delay interval.\n```kotlin\nmailService.retry(3, 2000) {\n    it.send(email, fullName,\n            \"Register Success\",\n            \"\u003ch2\u003eSuccess!\u003c/h2\u003e\u003cp\u003eYou are now a new member!\u003c/p\u003e\", \n            \"Success! You are now a new member!\")\n}\n```\n\n#### Circuit Breaker\nAPI calls \u0026 email sending might fail, these faults can range in severity from a partial loss of connectivity to the complete failure of a service.\nFor some mission critical tasks, you might want to send emails with a circuit breaker pattern. \n\nTo do so with the mail service in Zeko:\n```kotlin\nval mailCircuitBreaker = SendGridMail.createCircuitBreaker(vertx)\n\nmailService.sendInCircuit(circuitBreaker, \n            email, fullName,\n            \"User Registration Success\",\n            \"\u003ch2\u003eSuccess!\u003c/h2\u003e\u003cp\u003eYou are now a new user!\u003c/p\u003e\",\n            \"Success! You are now a new user!\")\n```\nCircuit breaker instance should be better shared and not created on every email send, put it into your DI container instead.\n\nBy default, the createCircuitBreaker() method creates a circuit breaker with name of \"zeko.mail.sendgrid\" (or \"zeko.mail.mandrill\" for MandrillMailService),\n along with max failures of 5, and 8 maximum retries. Change the behaviour by providing your own [CircuitBreakerOptions](https://vertx.io/docs/apidocs/io/vertx/circuitbreaker/CircuitBreakerOptions.html)\n\n```kotlin\n// Unlimited retries\nval opt = CircuitBreakerOptions().apply { \n    maxFailures = 15\n    maxRetries = 0\n}\nSendGridMail.createCircuitBreaker(vertx, \"important.mailtask1\", opt)\n```\n\n## SQL Queries\nJust use any sql builder libraries or refer to [Zeko's SQL Builder](https://github.com/darkredz/Zeko-SQL-Builder)\n\n## Data Mapper\nDIY or refer to [Zeko Data Mapper](https://github.com/darkredz/Zeko-Data-Mapper)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdarkredz%2Fzeko-restapi-framework","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdarkredz%2Fzeko-restapi-framework","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdarkredz%2Fzeko-restapi-framework/lists"}