{"id":23122814,"url":"https://github.com/folio-org/folio-vertx-lib","last_synced_at":"2025-05-07T05:04:50.012Z","repository":{"id":37802741,"uuid":"431140819","full_name":"folio-org/folio-vertx-lib","owner":"folio-org","description":"Lightweight FOLIO module development library for Vert.x that supports OpenAPI","archived":false,"fork":false,"pushed_at":"2025-03-12T13:20:35.000Z","size":256,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-05-07T05:04:25.415Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":false,"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/folio-org.png","metadata":{"files":{"readme":"README.md","changelog":"NEWS.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":"2021-11-23T14:53:17.000Z","updated_at":"2025-03-12T08:46:37.000Z","dependencies_parsed_at":"2024-02-23T20:23:31.627Z","dependency_job_id":"5cbcd0f9-25bd-483a-99e8-f4ff6867052f","html_url":"https://github.com/folio-org/folio-vertx-lib","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/folio-org%2Ffolio-vertx-lib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/folio-org%2Ffolio-vertx-lib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/folio-org%2Ffolio-vertx-lib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/folio-org%2Ffolio-vertx-lib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/folio-org","download_url":"https://codeload.github.com/folio-org/folio-vertx-lib/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252817010,"owners_count":21808705,"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-12-17T07:30:38.614Z","updated_at":"2025-05-07T05:04:50.006Z","avatar_url":"https://github.com/folio-org.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# folio-vertx-lib\n\nCopyright (C) 2021-2025 The Open Library Foundation\n\nThis software is distributed under the terms of the Apache License,\nVersion 2.0. See the file \"[LICENSE](LICENSE)\" for more information.\n\n## Introduction\n\n[folio-vertx-lib](https://github.com/folio-org/folio-vertx-lib)\nis a library for developing FOLIO modules based on Vert.x. This is a\nlibrary, not a framework, with utilities such as:\n\n * OpenAPI support\n * Tenant API 2.0 support\n * PostgreSQL utilities\n * CQL support\n\n## Main Verticle\n\nThe [Vert.x OpenAPI](https://vertx.io/docs/vertx-web-openapi/java/) unlike\nmany OpenAPI implementations does not generate any code for you. Everything\nhappens at run-time. Only requests are validated, not responses.\n\nPlace your OpenAPI specification and auxiliary files somewhere in `resources`,\nsuch as `resources/openapi`.\n\nIn the following example, we will\nuse OpenAPI spec\n[books-1.0.yaml](mod-example/src/main/resources/openapi/books-1.0.yaml).\nThe code snippets shown are from:\n[MainVerticle](mod-example/src/main/java/org/folio/tlib/example/MainVerticle.java)\n,\n[BookService](mod-example/src/main/java/org/folio/tlib/example/service/BookService.java)\nand\n[BookStorage](mod-example/src/main/java/org/folio/tlib/example/storage/BookStorage.java).\n\nUnlike\n[RMB](https://github.com/folio-org/raml-module-builder), you define\nMainVerticle yourself - no fancy initializers - you decide.\n\nExample:\n```\npublic class MainVerticle extends AbstractVerticle {\n  @Override\n  public void start(Promise\u003cVoid\u003e promise) {\n    TenantPgPool.setModule(\"mod-mymodule\"); // PostgreSQL - schema separation\n\n    final int port = Integer.parseInt( // listening port\n        Config.getSysConf(\"http.port\", \"port\", \"8081\", config()));\n\n    MyApi myApi = new MyApi(); // your API, construct the way you like\n    // routes for your stuff, tenant API and health\n    RouterCreator [] routerCreators = {\n        myApi,\n        new Tenant2Api(myApi),\n        new HealthApi(),\n    };\n    HttpServerOptions so = new HttpServerOptions()\n        .setHandle100ContinueAutomatically(true);\n    // combine all routes and start server\n    RouterCreator.mountAll(vertx, routerCreators, \"mod-mymodule\")\n        .compose(router -\u003e\n            vertx.createHttpServer(so)\n                .requestHandler(router)\n                .listen(port).mapEmpty())\n        .\u003cVoid\u003emapEmpty()\n        .onComplete(promise);\n  }\n}\n```\n\n## Your API\n\nYour API must implement [RouterCreator](core/src/main/java/org/folio/tlib/RouterCreator.java)\nand, optionally, [TenantInitHooks](core/src/main/java/org/folio/tlib/TenantInitHooks.java)\nif your implementation has storage and that storage must be prepared for a\ntenant.\n\nWith the API there is a corresponding OpenAPI specification.\n\nThe `RouterCreator` interface has just one method `createRouter` where you\nreturn a Router for your implementation. Normally that's created for you by the\nOpenAPI library, but you can also define it yourself.\n\nFor an OpenAPI based implementation it could look as follows:\n\n```\npublic MyApi implements RouterCreator, TenantInitHooks {\n  @Override\n  public Future\u003cRouter\u003e createRouter(Vertx vertx) {\n    return RouterBuilder.create(vertx, \"openapi/myapi-1.0.yaml\")\n        .map(routerBuilder -\u003e {\n          handlers(vertx, routerBuilder);\n          return routerBuilder.createRouter();\n        });\n  }\n\n  private void handlers(Vertx vertx, RouterBuilder routerBuilder) {\n    routerBuilder\n        .operation(\"postTitles\") // operationId in spec\n        .handler(ctx -\u003e {\n          // doesn't do anything at the moment!\n          ctx.response().setStatusCode(204);\n          ctx.response().end();\n        });\n    routerBuilder\n        .operation(\"getTitles\")\n        .handler(ctx -\u003e getTitles(vertx, ctx)\n            .onFailure(cause -\u003e {\n              ctx.response().setStatusCode(500);\n              ctx.response().end(cause.getMessage());\n            }));\n  }\n}\n```\n\nTo support tenant init, your module should implement `preInit` and `postInit`.\n\nThese methods takes tenant ID and\n[tenant attributes object](core/src/main/resources/openapi/schemas/tenantAttributes.json).\n\nThe `preInit` job should be \"fast\" and is a way for the module to check if the\noperation can be started.. (\"pre-check\"). The postInit should perform the\nactual migration.\n\nThe Tenant2Api implementation deals with purge (removes schema with cascade).\nYour implementation should only consider upgrade/downgrade. On purge,\n`preInit` is called, but `postInit` is not.\n\n## PostgreSQL\n\nThe PostgreSQL support is minimal. There's just enough to perform tenant\nseparation and most\n[`DB_` environment variables that are also recognized by RMB](https://github.com/folio-org/raml-module-builder#environment-variables)\nsuch as `DB_HOST`, `DB_PORT`, `DB_USERNAME`, `DB_PASSWORD`, `DB_DATABASE`,\n`DB_MAXPOOLSIZE`, `DB_RECONNECTATTEMPTS`, `DB_RECONNECTINTERVAL`, `DB_SERVER_PEM`.\n\nThe class [TenantPgPool](core/src/main/java/org/folio/tlib/postgres/TenantPgPool.java) is\na small extension to the PgPool interface. The key method is `TenantPgPool.pool`\nfor constructing a pool for the current tenant. From that point, rest is plain\nVert.x pg client. However, the schema should be used when referring to tables, etc.\nUse the `getSchema` method for that.\n\nThe `TenantPgPool.setModule` *must* be called before first use as is done in\nMainVerticle example earlier.\n\nTo illustrate these things, consider a module that prepares a table in\ntenant init.\n\n```\n  @Override\n  public Future\u003cVoid\u003e postInit(Vertx vertx, String tenant, JsonObject tenantAttributes) {\n    if (!tenantAttributes.containsKey(\"module_to\")) {\n      return Future.succeededFuture(); // doing nothing for disable\n    }\n    TenantPgPool pool = TenantPgPool.pool(vertx, tenant);\n    return pool.query(\n            \"CREATE TABLE IF NOT EXISTS \" + pool.getSchema() + \".mytable \"\n                + \"(id UUID PRIMARY key, title text)\")\n        .execute().mapEmpty();\n  }\n```\n\n## CQL\n\nFor CQL support *all* fields recognized must be explicitly defined.\nUndefined CQL fields are rejected.\n\nExample definition:\n\n```\n    PgCqlDefinition pgCqlDefinition = PgCqlDefinition.create();\n    pgCqlDefinition.addField(\"cql.allRecords\", new PgCqlFieldAlwaysMatches());\n    pgCqlDefinition.addField(\"id\", new PgCqlFieldUuid());\n    pgCqlDefinition.addField(\"title\", new PgCqlFieldText().withFullText());\n```\n\nThis definition can then be used in a handler to get books:\n\n```\n private Future\u003cVoid\u003e getBooks(Vertx vertx, RoutingContext ctx) {\n    RequestParameters params = ctx.get(ValidationHandler.REQUEST_CONTEXT_KEY);\n    String tenant = params.headerParameter(XOkapiHeaders.TENANT).getString();\n    RequestParameter query = params.queryParameter(\"query\");\n    PgCqlQuery pgCqlQuery = pgCqlDefinition.parse(query == null ? null : query.getString());\n\n    TenantPgPool pool = TenantPgPool.pool(vertx, tenant);\n    String sql = \"SELECT * FROM \" + pool.getSchema() + \".mytable\";\n    String where = pgCqlQuery.getWhereClause();\n    if (where != null) {\n      sql = sql + \" WHERE \" + where;\n    }\n    String orderBy = pgCqlQuery.getOrderByClause();\n    if (orderBy != null) {\n      sql = sql + \" ORDER BY \" + orderBy;\n    }\n    return pool.query(sql).execute().onSuccess(rows -\u003e {\n      RowIterator\u003cRow\u003e iterator = rows.iterator();\n      JsonArray books = new JsonArray();\n      while (iterator.hasNext()) {\n        Row row = iterator.next();\n        books.add(new JsonObject()\n            .put(\"id\", row.getUUID(\"id\").toString())\n            .put(\"title\", row.getString(\"title\"))\n        );\n      }\n      ctx.response().putHeader(\"Content-Type\", \"application/json\");\n      ctx.response().setStatusCode(200);\n      JsonObject result = new JsonObject().put(\"books\", books);\n      ctx.response().end(result.encode());\n    }).mapEmpty();\n  }\n```\n\nCQL queries of the form `FIELD=\"\"` have a special meaning; they find all records where the named field is NOT NULL. (This behaviour is the same as in the old RAML Module Builder.) To search for records where the field is present but empty, the double-equal operator can be used: `FIELD==\"\"`.\n\n## Additional information\n\n### Issue tracker\n\nSee project [VERTXLIB](https://issues.folio.org/browse/VERTXLIB)\nat the [FOLIO issue tracker](https://dev.folio.org/guidelines/issue-tracker).\n\n### Code of Conduct\n\nRefer to the Wiki [FOLIO Code of Conduct](https://wiki.folio.org/display/COMMUNITY/FOLIO+Code+of+Conduct).\n\n### API documentation\n\nAPI descriptions:\n\n * [OpenAPI](core/src/main/resources/openapi/)\n * [Schemas](core/src/main/resources/openapi/schemas/)\n\nGenerated [API documentation](https://dev.folio.org/reference/api/#folio-vertx-lib).\n\n### Code analysis\n\n[SonarQube analysis](https://sonarcloud.io/project/overview?id=org.folio%3Afolio-vertx-lib)\n\n### Download and configuration\n\nThe built artifacts for this module are available.\nSee [configuration](https://dev.folio.org/download/artifacts) for repository access.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffolio-org%2Ffolio-vertx-lib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffolio-org%2Ffolio-vertx-lib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffolio-org%2Ffolio-vertx-lib/lists"}