{"id":20650931,"url":"https://github.com/coolsamson7/service","last_synced_at":"2026-02-26T06:01:55.081Z","repository":{"id":198513641,"uuid":"700938199","full_name":"coolsamson7/service","owner":"coolsamson7","description":"microservice and microfrontend framework","archived":false,"fork":false,"pushed_at":"2025-04-28T17:17:19.000Z","size":5110,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-28T18:28:26.223Z","etag":null,"topics":["angular","kotlin","microfrontend","microservices","module-federation","service-discovery"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/coolsamson7.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,"zenodo":null}},"created_at":"2023-10-05T15:29:43.000Z","updated_at":"2025-04-28T17:17:24.000Z","dependencies_parsed_at":"2023-10-11T20:29:43.410Z","dependency_job_id":"aeec56f7-a630-4cec-87e5-6eed138ae7f6","html_url":"https://github.com/coolsamson7/service","commit_stats":null,"previous_names":["coolsamson7/service"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/coolsamson7/service","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolsamson7%2Fservice","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolsamson7%2Fservice/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolsamson7%2Fservice/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolsamson7%2Fservice/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coolsamson7","download_url":"https://codeload.github.com/coolsamson7/service/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolsamson7%2Fservice/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267107962,"owners_count":24037350,"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-07-26T02:00:08.937Z","response_time":62,"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":["angular","kotlin","microfrontend","microservices","module-federation","service-discovery"],"created_at":"2024-11-16T17:24:35.853Z","updated_at":"2025-10-03T12:56:40.040Z","avatar_url":"https://github.com/coolsamson7.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Java CI with Maven](https://github.com/coolsamson7/service/actions/workflows/maven.yml/badge.svg)](https://github.com/coolsamson7/service/actions/workflows/maven.yml)\n# Service\n\nThis Kotlin library is based on spring ( core, mvc, cloud ) and tries to simplify the approach for typical architectures with distributed (micro)services that need to discover and communicate with each other in a dynamic environment.\n\nBy coincidence 😄 while i was busy working on an integrated administrative Angular UI, i thought that refactoring the framework part including a complete dynamic microfrontend  approach based on module federation would be cool as well...\n\nCheck the associated [Wiki](https://github.com/coolsamson7/service/wiki/Microfrontends) for details...\n\n## Motivation and goals\n\nWhile there are a number of - mostly spring - libraries\navailable that help to solve most of the low-level problems in a distributed microservice based architecture like\n- registries ( consul, etc. ) and\n- loadbalancing mechanisms\n\nthe result from a developer perspective in my mind is still too poor and also has some major shortcomings.\n\nLet's look at an example ( in Java ) \n\n```java\n@Configuration\npublic class MyConfiguration {\n   @Bean\n   @LoadBalanced\n   public WebClient.Builder loadBalancedWebClientBuilder() {\n      return WebClient.builder();\n   }\n}\n\npublic class MyClass {\n   @Autowired\n   private WebClient.Builder webClientBuilder;\n\n   public Mono\u003cString\u003e doOtherStuff() {\n        return webClientBuilder.build()\n            .get().uri(\"http://stores/stores\")\n            .retrieve().bodyToMono(String.class);\n    }\n}\n```\n\nWhat's wrong?\n- the code assumes that the called service is remote in the first place which is a totally unnecessary restriction\n- we have to commit to a specific protocol and take care of technical details on protocol level ( e.g.  loadbalancing )\n- we have to write technical boilerplate webclient code\n\nThis is _clumsy_ and contradicts some major architectural principles like separation of concern, etc.\n\nTalking about modularization: Spring assumes that the basis for clustering services is an application which is _wrong_ in my mind. Teams split up work\nby working on different modules. It should be a deployment aspect at the very end how modules are mapped to processes. So we bascially need a smaller building block! \n\nThe following design ideas or principles where the basis of the implemented architecture: \n\n- we want to program against simple interfaces and are not interested in protocol level details\n- we don't want to care where the implementation is. It could be remote, but it could be local as well.\n- depending on a specific deployment scenarios - e.g class path - different remoting situations should be possible.\n- remote service calls are transparently routed based on a central registry that keeps track of running services\n- services allow different protocols for remoting, which they expose as meta-data\n- typical health checks are executed in order to validate the health of individual services\n- changes in the topology - due to died or newly started services - should be handled transparently\n- every component is able to compute and return the full meta-data concerning its hosted services ( service-signatures, model-information, etc. )\n\n## Sample\n\nLet's look at a simple example at a final result. Let's declare a service interface first\n```kotlin\n@ServiceInterface(name = \"TestService\")\ninterface TestService : Service {\n    @GetMapping(\"/hello\")\n    @ResponseBody\n    fun hello(): String\n}\n```\nBy coincidence, it declares all the necessary annotations for spring! The framework only cares about the - tagging - interface and the annotation.\n\nServices are bundled by a _component_\n```kotlin\n@ComponentInterface(name = \"TestComponent\", services = [TestService::class])\ninterface TestRemoteComponent : Component\n```\nThe service implementation is a normal rest controller\n```kotlin\n@RestController\nclass TestServiceImpl : TestService {\n    override fun hello(): String {\n        return \"foo\"\n    }\n}\n```\nThe component implementation adds the necessary details in order to establish a remote connection, by\n* referencing a channel type ( here \"rest\" )\n* the address\n* and http health endpoints that are usually called by different kind of registries\n\n```kotlin\n@ComponentHost(health = \"/api/health\")\n@RestController\n@RequestMapping(\"/api\")\nclass TestComponentImpl : AbstractComponent(), TestComponent {\n    // override AbstractComponent\n\n    @ResponseBody\n    @GetMapping(\"/health\")\n    override val health: ComponentHealth\n        get() = ComponentHealth.UP\n\n    override val addresses: List\u003cChannelAddress\u003e\n        get() = listOf(\n            ChannelAddress(\"rest\", URI.create(\"http://$host:$port\")) // local host and port in this case!\n        )\n}\n```\nAs we can see here, we utilize the normal spring mechanisms to expose the health method :-) \n\nAssuming that a channel of type \"rest\" is known ( we will come back to that later ), we can now call\nservice methods easily.\n```kotlin\n  // get the manager from spring\n  \n  val context : ApplicationContext  = ... \n  val manager = context.getBean(ServiceManager::class.java)\n\n  // fetch the service ( proxy )  \n            \n  val service = manager.acquireService(TestService::class.java)\n\n  // go forrest\n  \n  service.hello()\n    \n```\nAn alternative approach would be to use annotations\n```kotlin\nclass Foo {\n   // inject services\n   \n   @InjectService\n   val service : TestService\n   @InjectService(preferLocal=true)\n   val localService : TestService // works if the implementation lives in teh same VM\n   ...\n}\n```\n\nVoila, easy, eh?\n\n## Basic concepts\n\nAs we have already seen, there are four different basic building blocks\n* Service\n* Component\n* Component Registry\n* Channel\n\n### Service\n\nA service is represented by an annotated ( in order to be scanned by spring ) interface extending the tagging interface `Service` . \nThere are no other restrictions except that it should contain all the necessary information so that the communication channels are able to do the remoting.\nIn our example we simply added the spring mvc annotations knowing that spring will take care of the rest.\n\nThe service implementation is any spring bean. \n\n### Component\n\nThe purpose of a component interface is to bundle a list of services that share the same channel\n\nThe implementation takes care of\n* lifecycle of the component ( e.g. startup and shutdown methods )\n* registration with a component registry\n* providing a health endpoint\n\n### Component Registry\n\nA component registry is a central registry that knows about all active component implementations and their supported channels\n\n### Channel\n\nA channel implements the technical remoting protocol whenever remote services are executed.\nResolving a proper channel is done lazily based on the available information from the component registry\nwhich return a list of service instances and supported channels.\n\nIt is up to a concrete channel if ( client side ) load-balancing is supported or not.\n\nChannels will automatically adjust to changes in the topology which is detected by failing heartbeats.\n\n## Features\n\nThe framework offers the following features\n\n### Backend\n\n* first component registry implementation based on spring consul\n* rest channel based on `WebClient` supporting the _basic_ annotations\n* injection possibilities for services\n* central exception handling mechanisms\n* full introspection possibilities of the meta-data of components and services with respect to the interfaces as well as model classes\n\n### Web\n\nAn administration ui has been implemented in Angular that is able to\n* see the list of running components \u0026 services\n* see the service catalog of every component with respect to service interfaces and models\n* see details of the running infrastructure in terms of processes and the current inter-process communication flows\n* run service methods\n\nThe ui is secured by an OpenID Connect mechanism in combination with an external server ( e.g. Keycloak ) \n\nLet's look at some screenshots\n\nHere you see the registered instances for a particular component including the current health state\n\n![image](https://github.com/coolsamson7/service/assets/19403960/69c4159b-dba4-4538-a9db-23a06f130aae)\n\nAll aspects of a component can be viewed here. \n\n![image](https://github.com/coolsamson7/service/assets/19403960/656cb434-4160-4cd6-b474-1673286f2fda)\n\nIn addition to simply viewing, executing services is supported as well. As the meta-data is available all input parameters are validated.\n\n![image](https://github.com/coolsamson7/service/assets/19403960/9e8256cd-4e4b-4f93-a842-c9fcf5f46cb9)\n\nThe current state of the infrastructure can be viewed in form of a graph that shows running processes, the hosted components, and the current communication flows.\n\n![image](https://github.com/coolsamson7/service/assets/19403960/ebb190c1-31e0-480d-85e6-592b800c4241)\n\n## Getting started\n\nIts always good the check the `JUnit` tests which are available for \n* the core module\n* the rest module\n\n* Both make use of a local component registry\n\nTwo demo applications are available under `demo`\n* app1\n* app2\n\nWhile both host a set of common services, app2 calls services hosted by app1.\nBoth applications assume a running consul server under the typical port.\n \nThe Kotlin API can be found [here](http://ernstandreas.de/service/)\n\nCheck the corresponding [Wiki](https://github.com/coolsamson7/service/wiki) for detailed information.\n\nHave fun!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoolsamson7%2Fservice","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoolsamson7%2Fservice","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoolsamson7%2Fservice/lists"}