{"id":23122812,"url":"https://github.com/folio-org/folio-sample-modules","last_synced_at":"2025-08-17T03:30:55.961Z","repository":{"id":10911471,"uuid":"62135900","full_name":"folio-org/folio-sample-modules","owner":"folio-org","description":"Examples of FOLIO modules","archived":false,"fork":false,"pushed_at":"2024-10-22T11:47:25.000Z","size":357,"stargazers_count":16,"open_issues_count":0,"forks_count":10,"subscribers_count":23,"default_branch":"master","last_synced_at":"2025-04-04T23:11:18.053Z","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":null,"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":"2016-06-28T11:35:59.000Z","updated_at":"2025-03-29T22:20:13.000Z","dependencies_parsed_at":"2024-12-17T07:40:47.161Z","dependency_job_id":null,"html_url":"https://github.com/folio-org/folio-sample-modules","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/folio-org/folio-sample-modules","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/folio-org%2Ffolio-sample-modules","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/folio-org%2Ffolio-sample-modules/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/folio-org%2Ffolio-sample-modules/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/folio-org%2Ffolio-sample-modules/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/folio-org","download_url":"https://codeload.github.com/folio-org/folio-sample-modules/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/folio-org%2Ffolio-sample-modules/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270802799,"owners_count":24648648,"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","status":"online","status_checked_at":"2025-08-17T02:00:09.016Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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:37.728Z","updated_at":"2025-08-17T03:30:55.614Z","avatar_url":"https://github.com/folio-org.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Folio-Sample-Modules\n\nCopyright (C) 2016-2022 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\nThis project contains examples of FOLIO modules (currently a server-side\nVert.x-based module, but more, e.g. a UI/front-end module will come later),\nand some general information about writing, packaging and describing modules.\n\n\u003c!-- TODO: Add a few words about what FOLIO is, for new readers. Keep it short! --\u003e\n\nFor background understanding, see the\n[Okapi Guide and Reference](https://github.com/folio-org/okapi/blob/master/doc/guide.md).\n\n\u003c!-- ../okapi/doc/md2toc -l 2 -h 4 README.md --\u003e\n* [What is a module](#what-is-a-module)\n    * [Module descriptor](#module-descriptor)\n        * [Module tags](#module-tags)\n        * [Handlers](#handlers)\n* [Server-side modules](#server-side-modules)\n    * [Deployment and discovery](#deployment-and-discovery)\n    \u003c!-- TODO: * [Logging, Health, and Metrics](#logging-health-and-metrics) --\u003e\n    * [Writing a module](#writing-a-module)\n        * [Java/Vert.x and Node.js](#javavertx-and-nodejs)\n        * [Development environment](#development-environment)\n        * [Setting things up](#setting-things-up)\n        * [Sample module: hello-vertx](#sample-module-hello-vertx)\n        * [Sample module: hello-spring](#sample-module-hello-spring)\n        * [Sample module: mod-spring-petstore](#sample-module-mod-spring-petstore)\n        * [Sample module: simple-vertx](#sample-module-simple-vertx)\n        * [Sample module: simple-perl](#sample-module-simple-perl)\n        * [Utility libraries](#utility-libraries)\n        * [Starting your own module](#starting-your-own-module)\n    * [Running your module](#running-your-module)\n        * [Run it yourself](#run-it-yourself)\n        * [Let Okapi start the module](#let-okapi-start-the-module)\n        * [Run in a Docker](#run-in-a-docker)\n* [UI modules](#ui-modules)\n* [Virtual modules](#virtual-modules)\n* [Further reading](#further-reading)\n\n## What is a module\n\nA module is a stand-alone unit of functionality that follows FOLIO's ecosystem\nguidelines (interfaces and schemas) and conventions; so that Okapi\n(FOLIO's middleware/API gateway) can forward requests to it and Stripes\n(FOLIO's UI Toolkit) can produce a user interface for it.\n\nAt the moment we support several types of modules:\n\n  * Server-side modules\n  * User-interface modules\n  * Virtual modules, with only dependencies and other metadata\n\n\u003c!--- TODO: We have not yet done anything about virtual modules,\nbut I believe such ought to work already. Sooner or later\nwe will need to pay more attention to those. The text is\ngood enough as it stands --\u003e\n\nFOLIO is an open-ended system and we may end up adding more module types later.\n\n\n### Module descriptor\n\nA module must come with a JSON file that contains a descriptor for the module.\nTypically it is called `ModuleDescriptor.json`. This will tell what services\nthe module provides, if it depends on some other services (and their versions),\nwhat permissions are needed to use the module, and a number of other things.\n\nFor exact definitions, see the RAML from the Okapi-core project. The various\nexample modules in this project may be helpful too.\n\nThe main parts of a ModuleDescriptor are:\n* id -- Primary key, uniquely identifying this module.\n* name -- A short name to be used in logs and some administrative UIs.\n* tags -- A set of short strings that tell something about the module. See below.\n* provides -- A set of interfaces, and their versions, that the module provides.\n* requires -- A set of interfaces, and their versions, that the module requires.\n* handlers -- Tells which HTTP requests the module is serving, and which\npermissions are needed to make such a request.\n* uiModuleDescriptor -- Placeholder for module-specific configuration for the UI\nmodules.\n* deploymentDescriptor -- Tells how the module is to be deployed (started).\n\n#### Module tags\n\nWe have not really started to use module tags in the system, but we are likely\nto end up with at least the following:\n* ServerModule -- Tells that this is a server side module.\n* UiModule -- Tells that this is a UI module.\n* VirtualModule -- Tells that this module is purely virtual, no code involved.\n\nWe may later add tags for various other purposes.\n\n#### Handlers\n\nThe handlers array tells Okapi which requests should be routed to the module\n(for example, a GET request to /hello), in what order various modules should\nbe invoked for that path (so that we can invoke an authentication check before\nthe module itself, and a logging module after it), and what permission bits\nwill be needed for making this request.\n\n\n## Server-side modules\n\nThe server-side modules are typically something Okapi deploys on various nodes\non the cluster where it runs. Each of those is a separate process, offering\nan HTTP endpoint that serves web service requests that conform to these guidelines.\n\n(Side note: Okapi is designed to be quite flexible, so it does not have to be\nused for deploying the modules, if the cluster management system provides\nbetter tools for such. Nor does the thing have to live in a cluster at all, it\nis quite possible to have a complete system on a single workstation, for example\nfor development work.)\n\nIn order to avoid problems with system-level dependencies, we have adopted a\npolicy of running modules in Docker containers. This way, each container can\nhave all the stuff the module needs, nicely isolated from the node itself, and\nfrom other modules. But this is not a hard requirement, especially when\ndeveloping modules it is possible to run them as standard processes on\na workstation.\n\n\n### Deployment and discovery\n\nOkapi can deploy modules in several ways:\n\n  * Exec'ing a given program (and killing its PID when undeploying).\n  * By use of command lines for starting and stopping a service.\n  * Using Docker API calls.\n\nOkapi knows what it has deployed on each node, and will route requests to\none of those. It is also possible to tell Okapi's discovery about processes\ndeployed directly, either on the cluster, or even externally.\n\nThe deployment options are specified in the DeploymentDescriptor.\n\nOnce deployed, Okapi's proxy part must be informed about the module, and then\nthe module can be enabled for tenants to use.\n\n\u003c!-- TODO\n### Logging, Health, and Metrics\nWrite something about these\n--\u003e\n\n\n### Writing a module\n\nFOLIO is designed so that different modules can be written in different\nlanguages with different tools.\n\n#### Language Choice\n\nWithin FOLIO, server-side modules are primarily written in Java (with some\nin Node.js).  These are used a lot within FOLIO, therefore, we have build\nlibraries and utilities to work with them (especially for standard scaffolding\nand boiler-plate code).\n\nCurrently, a lot of these modules are written in Java using Vert.x. FOLIO has two Vert.x based frameworks:\n* [raml-module-builder](https://github.com/folio-org/raml-module-builder) for RAML files\n* [folio-vertx-lib](https://github.com/folio-org/folio-vertx-lib) for OpenAPI files\n\nSome newer modules are written with the\n[Spring Way](https://docs.google.com/presentation/d/1YgDCBimLTQ1ou-fPhvyKbWpVkec3Goa8lyJJe2hcLHk/edit)\nphilosophy.  This uses Spring Boot, a more popular Java framework, as well as\nopenapi, making it easier to take advantage of more modern Java features.\nIf you are looking to start a new FOLIO module, you will probably want to\nuse this methodology and framework as opposed to something RMB/Vert.x based.\n\nFOLIO is language agnostic because modules and Okapi communicate over APIs only.\n\nHowever, FOLIO has implemented a\n[Technical Designs and Decisions](https://wiki.folio.org/display/DD/Technical+Designs+and+Decisions)\nprocess to provide consistency in FOLIO and to minimize the use of alternative tech stacks.\n\n#### Development environment\n\nThese are some notes to assist developers to prepare for their local development.\n\nTo build and run the local instance of Okapi, see the\n[Okapi Guide and Reference](https://github.com/folio-org/okapi/blob/master/doc/guide.md)\nand the\n[Contribution guidelines for Okapi](https://github.com/folio-org/okapi/blob/master/CONTRIBUTING.md).\n\nSo that will require:\n * Apache Maven 3.3.1 or later.\n * Java 11 JDK\n\nAs shown in the Okapi Guide and these samples, the command-line http client\n`curl` is used extensively for demonstration and development.\n\nAs explained above, using Docker is not necessary, but certainly is useful,\nand these samples do use it. So take the plunge. Okapi cleans up its own\ndeployments, but be sure to keep the docker space clean.\n\nBoth Docker and Maven can utilise a local repository, to enable faster\nand more reliable turnaround.\n\nFor development machines using \"Docker Toolbox\" (instead of native)\nsee our [FAQ](FAQ.md#docker-toolbox-and-localhost-ports) about \"localhost\" ports.\n\nAs explained in the Okapi Guide, Okapi uses HTTP 1.1 with\nchunked encoding to make the connections to the modules.\n\n(See notes below for additional requirements for developing UI modules.)\n\n#### Setting things up\nThere is a little bit that needs to be set up, depending on what kind of\nsystem you are working on.\n\nIt may be necessary to tell the Docker daemon to listen on\na HTTP port, and not just a local socket, since the vertx HTTP client we use\nfor talking to Docker can not talk to local sockets.\n\nWe need to specify how the modules may talk back to Okapi. Especially if they\nrun in Docker containers (as we do in most examples) some tricks may be needed,\nsince the default address `http://localhost:9130/` does not work from inside a\nDocker container.\n\nSpeaking of docker, the example scripts create new docker images freely. At\nsome point you need to clean them up. A quick command to do that (at least on\nLinux) is `docker images -q |xargs docker rmi`. This tries to remove all docker\nimages, but fails on some of the more important ones (since we did not specify\n`-f` for the `docker rmi` command). Docker may need to do some extra work next\ntime you build images, but not too much.\n\n\u003c!--  TODO - this does not seem to belong here, but on some more high-level\ndocument on module development.\n\n Although these examples are meant to be run locally, at some point we wish\nto keep our Docker images in a repository. Obviously you will need login\ncredentials for the repository before you can push your modules there. The\nrelevant commands are\n```\n - docker login # once on every new machine\n - docker images -q |xargs docker rmi  # Kill lots of old images\n - docker build -t folio-hello-module  # Build the image\n - docker tag a31a1b728e79 folio-hello-module:v1.1.1  # Local tag\n - docker tag a31a1b728e79 folio-docker-registry.indexdata.com/folio-hello-module:v1.1.1\n - docker push folio-docker-registry.indexdata.com/folio-hello-module:v1.1.1\n```\n--\u003e\n\nSee notes about\n[configuring Docker](https://docs.docker.com/engine/installation/#platform-support-matrix)\nfor all operating systems.\n\n##### Linux\n\nWith recent versions of Linux using 'systemd'\n(e.g. from Debian 8 Jessie, Ubuntu 15.04, etc.)\n[configure](https://docs.docker.com/engine/installation/#platform-support-matrix) the Docker daemon:\n\n  * Edit the file\n`/etc/systemd/system/multi-user.target.wants/docker.service`\n  * Locate the line that says\n`#ExecStart=/usr/bin/docker -d -H fd:// $DOCKER_OPTS`\n  * Edit it to say `ExecStart=/usr/bin/dockerd -H tcp://127.0.0.1:4243 -H fd://`\n  * `sudo systemctl daemon-reload`\n  * `sudo service docker restart`\n\nDebian is a bit behind with the latest versions of Docker. You may want to follow\nthe instruction at https://docs.docker.com/engine/installation/linux/debian/ to\nget the latest and finest. Especially if you plan to be pushing docker images\nto a repository. The one in Debian should be enough to work through these\nexamples.\n\nOne good way to start Okapi is with:\n```\n   cd .../okapi\n   export OKAPIHOST=`hostname`\n   java  \\\n      -Dokapiurl=\"http://$OKAPIHOST:9130\" \\\n      -Dloglevel=DEBUG \\\n      -jar okapi-core/target/okapi-core-fat.jar dev\n```\n\nOther ways to get a value for OKAPIHOST are:\n  * `export OKAPIHOST=$(ifconfig docker0 | awk '/inet addr:/ { print $2 }' | cut -d: -f 2)`\n  * On many Debian installations it may be 172.17.0.1 or 172.17.41.1\n  * Use the IP address of the public interface of your workstation with something\nlike `ip addr show eth0`\n\n\u003c!-- TODO: Check what works on a Mac, and document here\n##### Mac\nTODO: What about the Docker daemon on a Mac?\n\nThere is a known problem with Docker on Mac, the docker images can not talk to\nthe host machine. One possible solution is to define a new IP for the loopback\ninterface, for example 10.99.88.77 (How to do that on a Mac). There can also be\nissues with the firewall...\n```\n   cd .../okapi\n   export OKAPIHOST=\"10.99.88.77\"\n   java  \\\n      -Dokapiurl=\"http://$OKAPIHOST:9130\" \\\n      -Dloglevel=DEBUG \\\n      -jar okapi-core/target/okapi-core-fat.jar dev\n```\n\n--\u003e\n\n\u003c!-- TODO - What is needed on other Linuxes, Mac, Windows, others --\u003e\n\n#### Sample module: hello-vertx\n\nThere is a very minimal \"hello, world\" module in the hello-vertx directory.\nWritten as an educational example, it may serve as a starting point for a\nserver-side FOLIO module.\nIts README has some information about its structure and how to run it in a\nDocker container.\n\nThe sample module uses Apache Log4j for its logging, the same way as Okapi itself\ndoes, so its logs should be compatible.\n\n#### Sample module: hello-spring\n\nThis is a reimplementation of hello-vertx, but using the Java Spring Boot\nframework and OpenAPI specification.\n\n#### Sample module: mod-spring-petstore\n\nThis is an example of the FOLIO backend module built using folio-spring-base library.\nThe module has been created using the mod-spring-template.\nPlease find all the details regarding creating new folio Spring based modules using mod-spring-template at https://github.com/folio-org/mod-spring-template\n\n#### Sample module: simple-vertx\n\nThis is a slightly more complex example, again based on Java and vert.x. It has\na little bit more structure, and it uses the hello-vertx module to demonstrate\nhow to make calls to other modules.\n\n#### Sample module: simple-perl\nThis is another very simple module, written in Perl, just to show that everything\ndoes not have to be Java.\n\u003c!-- TODO - At some point we need to have a more complex example in Perl, with\npermissions, logging, instrumentation, and all possible bells and whistles --\u003e\n\n#### Utility libraries\n\nThere are several useful classes and utilities for writing modules in Okapi\nand the core Domain Models project. We have started to extract some of them\ninto a separate module, okapi-common, for easier reuse.\n\n#### Starting your own module\n\nAssume that you want to write your own module. Here is one way to get started.\nWe take the hello-vertx (or hello-spring) module as a starting point, and\nproduce a new module that we call my-module. These examples are written for\nLinux, but something similar ought to work on any other platform.\n\nFirst, make sure you have all the development tools you need. Check out Okapi\nitself, and these folio-sample-modules. We assume all your projects live under\na projects directory, here denoted by .../proj. For convenience we keep the\nroot directory in an environment variable $ROOTDIR.\n\n```\n  cd .../proj\n  export ROOTDIR=`pwd`\n  git clone --recursive https://github.com/folio-org/okapi.git\n```\n\nNext build Okapi itself:\n\n```\n  cd $ROOTDIR/okapi\n  mvn install\n```\n\nCheck that you see the `BUILD SUCCESS` line near the end of the output. Next\ncheck out the folio-sample-modules to get the module we want to\nstart from, and make a new copy of it:\n\n```\n  cd $ROOTDIR\n  git clone https://github.com/folio-org/folio-sample-modules.git\n  cp -a folio-sample-modules/hello-spring/ mymodule # spring way\n  cp -a folio-sample-modules/hello-vertx/ mymodule # vert.x\n```\n\nOpen the project in your favourite IDE, in this example NetBeans. Use its\nrename function to rename the display name and ArtifactId to \"mymodule\".\nYou should probably rename the source package to something else like\n\"org.foo.mymopdule\", unless you are starting up a new FOLIO sample module.\n\nNow you can compile the module in your IDE or with `mvn install`. Again,\ncheck for the \"BUILD SUCCESS\" message.\n\nNext, edit the `ModuleDescriptor.json`. Find all occurrences of \"hello\" and\nchange them to \"mymodule\".\n\nEdit also the Dockerfile. If you are using `hello-vertx`, change the\n`ENV VERTICLE_FILE` line to refer to `mymodule-fat.jar` and edit the comments\nin the beginning.  If you are using `hello-spring`, modify the `APP_FILE ENV`.\n\nNow you can walk through the examples in README.md, substituting \"mymodule\" for\n\"hello\" where proper. You should be able to create the docker image, see that\nit can run in isolation, start Okapi, launch the module and access it.\n\nCongratulations, you have your own module! Now you just need to make it do\nwhat ever you want it to do, and for that we can not give detailed instructions.\nSome useful hints:\n  * You probably want to make the module respond to some other path(s) than\n`/hello`. Change the `RoutingEntries` in the ModuleDescriptor, and, for vert.x,\nthe vertx router in the MainVerticle.java file.  For spring, modify the `api.yaml`\nper openapi specifications.\n  * You probably should move the actual processing methods away from the current\nmain class, likely into a class of its own, and make the routes/controller point\nto it.  Most likely you will create other classes to support your operations.\n  * Rewrite most of the README to reflect _your_ module.\n\n### Running your module\nThere are three different ways to run your module. They differ in the way that\nthe module is started up, everything else is the same. In all cases you need\nto declare the module to Okapi and enable it for your test tenant, who has to\nexist. The methods differ in the LaunchDescriptor you give to Okapi. This can\nbe done in two ways, either inside the ModuleDescriptor, as we did in the\nhello-vertx module, or in the DeploymentDescriptor, as we did in simple-perl\nmodule. Where ever the LaunchDescriptor comes from, it needs to specify how\nthe module gets started.\n\n#### Run it yourself\nYou are responsible for starting and stopping the module, possibly from your\nIDE or a separate console window. You can choose the port yourself, usually\n8080 is a good default. You should not provide a LaunchDescriptor at all, since\nOkapi is not launching the service for you. Instead you need to provide the\nURL where your module can be reached, often something like `http://localhost:8080`\n\nThis is a good way while you are working with your module. You set Okapi up once\nand leave it running. You can start and stop your module as many times as you\nlike, and see all its debug output.\n\n#### Let Okapi start the module\nIf you put a LaunchDescriptor in your ModuleDescriptor, Okapi will start the\nmodule for you, every time you request it to be deployed. This way, you can\nwrite a small curl script to get everything up and running. If you do this\nkind of thing in production environment, you probably have the modules running\nat some fixed location, and can put an absolute path in the LaunchDescriptor.\nBut while developing, it is nicer to be flexible, and use relative paths, so\neverything can be run under your home directory. That is no problem, if Okapi\nand your module are running under the same project directory. Then you can\nspecify something like \"../folio-sample-modules/simple-perl/simple.pl\" as the\nexec line, and Okapi will find the module all right.\n\n#### Run in a Docker\nIn a cloud based production environment, we recommend running all modules\nin their own Docker containers. That way, there is no need to be precise with\nthe paths. You can distribute modules as Docker images, maybe using a public\n(or your own private) Docker repository. The drawback is that you need to\ncreate the Docker image. See the hello-vertx module for a simple example of\nhow this works.\n\n## UI modules\n\nThe UI modules are quite different from the server-side modules, and rely\non the browser technology stack (React/Redux). The system's API is\nstill under development. Refer to the FOLIO user-interface toolkit,\ncalled [Stripes](http://dev.folio.org/doc/#user-interface).\n\n\u003c!-- TODO - Describe the way UI modules are written, and bundled --\u003e\n\n## Virtual modules\n\nVirtual modules are pure metadata, with no code to write. All that is needed is\nto create a good ModuleDescriptor, e.g. one that lists dependencies of other,\nconcrete modules.\n\n## Further reading\n\nFor more about Okapi, refer to its documentation and even the source code at\nhttps://github.com/folio-org/okapi\n\nAlso consult the README for the\n[hello-vertx](https://github.com/folio-org/folio-sample-modules/tree/master/hello-vertx)\nexample which covers some useful ground.\n\nAside from the sample modules in this repository, there are\nvarious other\n[server-side](http://dev.folio.org/source-code/#server-side) modules and\n[client-side](http://dev.folio.org/source-code/#client-side) UI modules,\nwhich would also be instructive to browse.\n\nConsult the individual repositories' documentation for the status of\nthe code in these modules.\n\nSee project [OKAPI](https://issues.folio.org/browse/OKAPI)\nat the [FOLIO issue tracker](http://dev.folio.org/community/guide-issues).\n\nOther FOLIO Developer documentation is at [dev.folio.org](http://dev.folio.org/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffolio-org%2Ffolio-sample-modules","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffolio-org%2Ffolio-sample-modules","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffolio-org%2Ffolio-sample-modules/lists"}