Hexagon is a microservices toolkit written in Kotlin. Its purpose is to ease the building of services (Web applications, APIs or queue consumers) that run inside a cloud platform.

Overview

Hexagon
Hexagon

The atoms of your platform

GitHub Actions Coverage Maven Central Repository

Home Site | Quick Start | Developer Guide


What is Hexagon

Hexagon is a microservices' toolkit (not a framework) written in Kotlin. Its purpose is to ease the building of server applications (Web applications, APIs or queue consumers) that run inside a cloud platform.

The Hexagon Toolkit provides several libraries to build server applications. These libraries provide single standalone features and are referred to as "Ports".

The main ports are:

  • The HTTP server: supports HTTPS, HTTP/2, mutual TLS, static files (serve and upload), forms processing, cookies, sessions, CORS and more.
  • The HTTP client: which supports mutual TLS, HTTP/2, cookies, form fields and files among other features.
  • Template Processing: allows template processing from URLs (local files, resources or HTTP content) binding name patterns to different engines.

Each of these features or ports may have different implementations called "Adapters".

Hexagon is designed to fit in applications that conform to the Hexagonal Architecture (also called Clean Architecture or Ports and Adapters Architecture). Also, its design principles also fits in this architecture.

The Hexagon's goals and design principles are:

  • Put you in Charge: There is no code generation, no runtime annotation processing, no classpath based logic, and no implicit behaviour. You control your tools, not the other way around.

  • Modular: Each feature (Port) or adapter is isolated in its own module. Use only the modules you need without carrying unneeded dependencies.

  • Pluggable Adapters: Every Port may have many implementations (Adapters) using different technologies. You can swap adapters without changing the application code.

  • Batteries Included: It contains all the required pieces to make production-grade applications: logging utilities, serialization, resource handling and build helpers.

  • Kotlin First: Take full advantage of Kotlin instead of just calling Java code from Kotlin. The library is coded in Kotlin for coding with Kotlin. No strings attached to Java (as a Language).

  • Properly Tested: The project's coverage is checked in every Pull Request. It is also stress-tested at TechEmpower Frameworks Benchmark.

For more information check the Quick Start Guide or the Developer Guide.

Simple HTTP service

You can clone a starter project (Gradle Starter or Maven Starter). Or you can create a project from scratch following these steps:

  1. Configure Kotlin in Gradle or Maven.
  2. Add the dependency:
  • In Gradle. Import it inside build.gradle:

    repositories {
        mavenCentral()
    }
    
    implementation("com.hexagonkt:http_server_jetty:$hexagonVersion")
  • In Maven. Declare the dependency in pom.xml:

    <dependency>
      <groupId>com.hexagonkt</groupId>
      <artifactId>http_server_jetty</artifactId>
      <version>$hexagonVersion</version>
    </dependency>
  1. Write the code in the src/main/kotlin/Hello.kt file:
// hello
package com.hexagonkt.http.server.jetty

import com.hexagonkt.http.server.Server

lateinit var server: Server

/**
 * Start a Hello World server, serving at path "/hello".
 */
fun main() {
    server = serve {
        get("/hello") {
            ok("Hello World!")
        }
    }
}
// hello
  1. Run the service and view the results at: http://localhost:2010/hello

Examples

Books Example

A simple CRUD example showing how to manage book resources. Here you can check the full test.

// books
data class Book(val author: String, val title: String)

private val books: MutableMap<Int, Book> = linkedMapOf(
    100 to Book("Miguel de Cervantes", "Don Quixote"),
    101 to Book("William Shakespeare", "Hamlet"),
    102 to Book("Homer", "The Odyssey")
)

val server: Server = Server(adapter) {
    post("/books") {
        // Require fails if parameter does not exists
        val author = queryParameters.require("author")
        val title = queryParameters.require("title")
        val id = (books.keys.maxOrNull() ?: 0) + 1
        books += id to Book(author, title)
        send(201, id)
    }

    get("/books/{id}") {
        val bookId = pathParameters.require("id").toInt()
        val book = books[bookId]
        if (book != null)
            // ok() is a shortcut to send(200)
            ok("Title: ${book.title}, Author: ${book.author}")
        else
            send(404, "Book not found")
    }

    put("/books/{id}") {
        val bookId = pathParameters.require("id").toInt()
        val book = books[bookId]
        if (book != null) {
            books += bookId to book.copy(
                author = queryParameters["author"] ?: book.author,
                title = queryParameters["title"] ?: book.title
            )

            ok("Book with id '$bookId' updated")
        }
        else {
            send(404, "Book not found")
        }
    }

    delete("/books/{id}") {
        val bookId = pathParameters.require("id").toInt()
        val book = books[bookId]
        books -= bookId
        if (book != null)
            ok("Book with id '$bookId' deleted")
        else
            send(404, "Book not found")
    }

    // Matches path's requests with *any* HTTP method as a fallback (return 404 instead 405)
    any("/books/{id}") { send(405) }

    get("/books") { ok(books.keys.joinToString(" ", transform = Int::toString)) }
}
// books
Session Example

Example showing how to use sessions. Here you can check the full test.

// session
val server: Server = Server(adapter, ServerSettings(features = setOf(SESSIONS))) {
    path("/session") {
        get("/id") { ok(session.id ?: "null") }
        get("/access") { ok(session.lastAccessedTime?.toString() ?: "null") }
        get("/new") { ok(session.isNew()) }

        path("/inactive") {
            get { ok(session.maxInactiveInterval ?: "null") }

            put("/{time}") {
                session.maxInactiveInterval = pathParameters.require("time").toInt()
            }
        }

        get("/creation") { ok(session.creationTime ?: "null") }
        post("/invalidate") { session.invalidate() }

        path("/{key}") {
            put("/{value}") {
                session.set(pathParameters.require("key"), pathParameters.require("value"))
            }

            get { ok(session.get(pathParameters.require("key")).toString()) }
            delete { session.remove(pathParameters.require("key")) }
        }

        get {
            val attributes = session.attributes
            val attributeTexts = attributes.entries.map { it.key + " : " + it.value }

            response.headers["attributes"] = attributeTexts.joinToString(", ")
            response.headers["attribute values"] = attributes.values.joinToString(", ")
            response.headers["attribute names"] = attributes.keys.joinToString(", ")

            response.headers["creation"] = session.creationTime.toString()
            response.headers["id"] = session.id ?: ""
            response.headers["last access"] = session.lastAccessedTime.toString()

            response.status = 200
        }
    }
}
// session
Error Handling Example

Code to show how to handle callback exceptions and HTTP error codes. Here you can check the full test.

// errors
class CustomException : IllegalArgumentException()

val server: Server = Server(adapter) {
    error(UnsupportedOperationException::class) {
        response.headers["error"] = it.message ?: it.javaClass.name
        send(599, "Unsupported")
    }

    error(IllegalArgumentException::class) {
        response.headers["runtimeError"] = it.message ?: it.javaClass.name
        send(598, "Runtime")
    }

    // Catching `Exception` handles any unhandled exception before (it has to be the last)
    error(Exception::class) { send(500, "Root handler") }

    // It is possible to execute a handler upon a given status code before returning
    error(588) { send(578, "588 -> 578") }

    get("/exception") { throw UnsupportedOperationException("error message") }
    get("/baseException") { throw CustomException() }
    get("/unhandledException") { error("error message") }

    get("/halt") { halt("halted") }
    get("/588") { halt(588) }
}
// errors
Filters Example

This example shows how to add filters before and after route execution. Here you can check the full test.

// filters
private val users: Map<String, String> = mapOf(
    "Turing" to "London",
    "Dijkstra" to "Rotterdam"
)

private val server: Server = Server(adapter) {
    before { attributes["start"] = nanoTime() }

    before("/protected/*") {
        val authorization = request.headers["Authorization"] ?: halt(401, "Unauthorized")
        val credentials = authorization.removePrefix("Basic ")
        val userPassword = String(Base64.getDecoder().decode(credentials)).split(":")

        // Parameters set in call attributes are accessible in other filters and routes
        attributes["username"] = userPassword[0]
        attributes["password"] = userPassword[1]
    }

    // All matching filters are run in order unless call is halted
    before("/protected/*") {
        if(users[attributes["username"]] != attributes["password"])
            halt(403, "Forbidden")
    }

    get("/protected/hi") { ok("Hello ${attributes["username"]}!") }

    // After filters are run even if request was halted before
    after { response.headers["time"] = nanoTime() - attributes["start"] as Long }
}
// filters
Files Example

The following code shows how to serve resources and receive files. Here you can check the full test.

// files
private val server: Server = Server(adapter) {
    path("/static") {
        get("/files/*", URL("classpath:assets")) // Serve `assets` resources on `/html/*`
        get("/resources/*", File(directory)) // Serve `test` folder on `/pub/*`
    }

    get("/html/*", URL("classpath:assets")) // Serve `assets` resources on `/html/*`
    get("/pub/*", File(directory)) // Serve `test` folder on `/pub/*`
    get(URL("classpath:public")) // Serve `public` resources folder on `/*`

    post("/multipart") { ok(request.parts.keys.joinToString(":")) }

    post("/file") {
        val part = request.parts.values.first()
        val content = part.inputStream.reader().readText()
        ok(content)
    }

    post("/form") {
        fun serializeMap(map: Map<String, List<String>>): List<String> = listOf(
            map.map { "${it.key}:${it.value.joinToString(",")}}" }.joinToString("\n")
        )

        val queryParams = serializeMap(queryParametersValues)
        val formParams = serializeMap(formParametersValues)

        response.headersValues["queryParams"] = queryParams
        response.headersValues["formParams"] = formParams
    }
}
// files

You can check more sample projects and snippets at the examples page.

Thanks

This project is supported by:

Status

The toolkit is properly tested. This is the coverage report:

Coverage

Performance is not the primary goal, but it is taken seriously. You can check performance numbers in the TechEmpower Web Framework Benchmarks.

Contribute

If you like this project and want to support it, the easiest way is to give it a star ✌️ .

If you feel like you can do more. You can contribute to the project in different ways:

To know what issues are currently open and be aware of the next features you can check the Project Board and the Organization Board at GitHub.

You can ask any question, suggestion or complaint at the project's Slack channel. You can be up to date of project's news following @hexagon_kt on Twitter.

Thanks to all project's contributors!

CodeTriage

License

The project is licensed under the MIT License. This license lets you use the source for free or commercial purposes as long as you provide attribution and don’t hold any project member liable.

Comments
  • Fix API documentation edit link

    Fix API documentation edit link

    Edit link doesn't lead to the file with the documentation and title is always Home.

    Take this generated page as an example: https://hexagonkt.com/port_http_server/com.hexagonkt.http.server The edit button (the one with a pencil icon on top right position) doesn't take you to the correct file to edit that documentation.

    Also, the title of the page is Home where it should be the package name (and in the case of a class or a method, its name).

    This is a tricky issue and involves a little bit of research, and maybe requires some unavailable features in the tools used to generate the documentation Dokka, MkDocs and MkDocs Material Theme.

    To give a little bit of context: the site generation is done from source code files and extra Markdown files. Dokka generates the Markdown for API classes, packages and modules, these are processed to fit in MkDocs using Gradle build scripts, and finally the documentation is compiled using the MkDocs Material Theme to a static site. This processing is done in the hexagon_site module (check the module for further reference).

    The purpose of this process is to keep the source of the documentation close to the code and with the bare minimum number of files to be able to keep it up to date with the minimum effort.

    To fix this issue, I haven't got a good solution yet, but a proposal would be:

    1. Check if MkDocs allows front matter data (key/value pairs in .md files) passed to the rendering engine.
    2. Find out if MkDocs Material Theme checks one of those keys to render the edit button.
    3. If so, add Kotlin or Gradle code in the build logic to obtain the class file to which the .md belongs and set it in the .md file (maybe Dokka can do this though).
    4. Check everything works smoothly and go for a beer.

    If you read this issue and you came up with a better solution... I'm all ears!

    help wanted hacktoberfest 
    opened by jaguililla 21
  • Simple command line arguments parsing

    Simple command line arguments parsing

    The purpose of this task would be to implement a minimum set of features to handle command line arguments properly without having to rely on a third party library like picocli or jopt-simple.

    The goal would be to provide the most used features to be used out of the box. Users who need all features, could go for an external library, but at Hexagon core there should be a minimum to parse arguments and display help messages and errors.

    The features would be:

    • Allow the definition of cli arguments. I.e., data class Option<T : Any>(val shortName: Char?, val longName: String?, val description: String, val optional: Boolean, val type: KClass<T> = String::class, val defaultValue: T)
    • A function to parse an array of arguments with a given array of options: fun parse(options: List<Option<*>>, vararg args: String): Map<Option, List<*>).
    • Parse should fail if unkown parameter is passed.
    • Another function to generate a help message based on the defined options (maybe on a class with the function described above).
    • The allowed options format would be a subset of posix standard
      • Long parameters with values: --name value or --name
      • Short parameters clustered: -alts > -a -l -t -s
      • Short parameters with values: -a value

    Things to consider:

    • Does the OS takes care of the parameters scaping always? I.e., 'value with spaces', "another value with $variable"?

    Previous work:

    • In the settings processing, there was a very limited parameter parsing. You can check it out here.

    Requirements:

    • No external libraries.
    • Short and simple (3 or 4 classes in a package at most).
    • Extensive test set to cover all cases (there is a lot of corner cases).

    If requirements are too complex to achieve, we can always discard this task and don't provide that functionality. I'm not sure 100% if the toolkit should including this. Trade offs are:

    • Allow minimum features to develop a wide range of programs but adding more complexity and not being able to provide a viable alternative to 3rd party libraries.
    • Focus on do the least features (don't be a bloated toolkit) and let the user select other specialized libraries for things not covered by Hexagon.

    What do you think?

    help wanted 
    opened by jaguililla 19
  • Upgrade MkDocs Material

    Upgrade MkDocs Material

    Upgrade to MkDocs Material 5. To do so, you can check the theme's documentation: https://squidfunk.github.io/mkdocs-material/upgrading/

    We can take advantage of the new version to add Dev.to link as blog/news using this icon: https://fontawesome.com/icons/dev?style=brands

    Use also a Web app manifest and service worker may be another improvement.

    help wanted hacktoberfest 
    opened by jaguililla 12
  • Port Gradle build scripts to Kotlin

    Port Gradle build scripts to Kotlin

    Build logic is written in Groovy (all *.gradle files).

    The goal of this task is to port those build scripts to Gradle kotlin DSL (*.gradle.kts).

    This task can be completed with different PRs (one by each .gradle file migrated).

    EDIT: The missing scripts right now are:

    • Helper scripts located inside gradle directory. These ones should be ported in a kts folder before deleting the Groovy ones.
    help wanted 
    opened by jaguililla 10
  • Develop Twitter clone example

    Develop Twitter clone example

    This could be a perfect task to start working on the project. If you would like to get involved or just play with a different toolkit for HTTP services, keep reading!

    Your task will be to code a Twitter clone example following the very same Spark tutorial.

    To get familiar with the project and set things up, you should read the contributing document first. If something is not clear or doesn't work right, don't worry and post a comment, I will help you with that (and fix the document for the next one :wink:).

    This exercise will give you a grasp on the project to further propose or develop improvements (if you are willing to continue committing code).

    To complete this task:

    • [ ] Code the service following this Spark tutorial
    • [ ] Create a Pull Request to https://github.com/hexagonkt/twitter_clone from your project
    • [ ] As an optional addition, you can add Codecov test coverage report inside the Travis CI pipeline

    For reference, you can check this other example: https://github.com/hexagonkt/real_world. And of course, I will help you with it if you ask me (as I already did developments like this).

    Have fun, and happy coding!

    help wanted easy 
    opened by jaguililla 9
  • Add application structure example

    Add application structure example

    This could be a perfect task to start working on the project. If you would like to get involved or just play with a different toolkit for HTTP services, keep reading!

    Your task will be to code an example demonstrating the structure of a simple application following this Spark tutorial.

    To get familiar with the project and set things up, you should read the contributing document first. If something is not clear or doesn't work right, don't worry and post a comment, I will help you with that (and fix the document for the next one :wink:).

    This exercise will give you a grasp on the project to further propose or develop improvements (if you are willing to continue committing code).

    To complete this task:

    • [ ] Code the service following this Spark tutorial
    • [ ] Create a Pull Request to https://github.com/hexagonkt/application_structure from your project
    • [ ] As an optional addition, you can add Codecov test coverage report inside the Travis CI pipeline

    For reference, you can check this other example: https://github.com/hexagonkt/real_world. And of course, I will help you with it if you ask me (as I already did developments like this).

    Have fun, and happy coding!

    help wanted wontdo easy 
    opened by jaguililla 9
  • Add compression support

    Add compression support

    Implement compression support in port_http_server and port_http_client.

    The goal would be to add a configuration parameter in the (Server|Client)Settings classes and force the compression headers to be sent accordingly.

    The proper encoding and sending/receiving bodies must be checked by tests in the Ports' tests suites (the test classes used to validate adapters modules).

    As a reference, you can check the fabulous MDN documentation regarding the subject:

    • https://developer.mozilla.org/en-US/docs/Web/HTTP/Compression
    • https://developer.mozilla.org/es/docs/Web/HTTP/Headers/Content-Encoding
    help wanted 
    opened by jaguililla 9
  • Add XML serialization format

    Add XML serialization format

    As Jackson supports the XML datatype: https://github.com/FasterXML/jackson-dataformat-xml , the scope of this task would be to create a Content Format module to support it.

    As a reference you can check the YAML Content format implementation in the serialization_yaml module.

    help wanted 
    opened by jaguililla 8
  • WebSockets support

    WebSockets support

    When completed, create an example project like this one: http://sparkjava.com/tutorials/websocket-chat to show the feature.

    Check Javalin implementation: https://javalin.io/documentation#websockets

    This task is composed of two big areas:

    1. Define the DSL to handle Websockets

    The DSL will implement methods to add routes of WS type inside the router. I.e.:

    Router {
        webSocket("/path") {
            onConnect {
                send("Message back")
            }
            onError {
                send("Message back")
            }
            onMessage {
                send("Message back")
            }
            onClose {
                send("Message back")
            }
        }
    }
    

    All callbacks will have a context to send/receive data to the client. This context will hold methods to get/set attributes, headers, etc.

    2. Implement the routes on adapters

    The above step will add a list of routes to the router. On the adapters implementations, these routes will be converted into the adapter's library format in the fun startup(server: Server) method.

    You can check the implementation of this method on the http_server_jetty/src/main/kotlin/JettyServletAdapter.kt file, but the actual logic is also on the http_server_servlet/src/main/kotlin/ServletFilter.kt file.

    hacktoberfest 
    opened by jaguililla 8
  • Error parsing query parameters

    Error parsing query parameters

    If a query parameter is defined with an empty value (I.e.: ?status=) a 500 error is returned.

    In that scenario we should assume it is a single element list with an empty string (as if you pass ?status).

    bug help wanted hacktoberfest 
    opened by jaguililla 7
  • Benchmark multiple configurations in single JVM [#97]

    Benchmark multiple configurations in single JVM [#97]

    This way one server can be used to test against different database and template engines and doesn't need to be restarted to test a different engine.

    Remove unnecessary combinations of docker based benchmark servers, it is now enough to have one per web engine (Resin, Jetty, Undertow). Also remove links definitions as they are not needed in compose v2+ (services in a stack are by default addressable by their name).

    Close #97

    opened by jitakirin 7
  • Complete SSE implementation

    Complete SSE implementation

    Partially implemented.

    Check https://www.baeldung.com/jetty-reactivestreams-http-client for client side implementation.

    Check the feature/sse branch.


    Detailed description.

    Reason for the change or new development.

    Acceptance criteria to verify the development. A list of requirements with the following format:

    When *action* then *result*

    For example:

    When this is done then that other thing should happen

    opened by jaguililla 0
  • Add Netty HTTP client

    Add Netty HTTP client

    Implement a HTTP client adapter using Netty.

    The http_client_jetty module can be used as a guide.

    http_client_jetty integration tests are located in http_test/src/test/kotlin/com/hexagonkt/http/test/AdapterExamplesTest.kt, the Netty adapter should copy them into its module tests and make them pass with the new adapter.

    help wanted good first issue 
    opened by jaguililla 6
  • Add HTTP server cheat sheet to documentation

    Add HTTP server cheat sheet to documentation

    Create a cheat sheet like: https://gist.github.com/jaguililla/ff8e671bb770478253553f5fb7a8ff5d

    Link it to the project site on the main menu (below HTTP server reference).

    opened by jaguililla 0
  • Support h2c (http/2 plain) protocol in Netty

    Support h2c (http/2 plain) protocol in Netty

    Add support for h2c protocol in Netty.

    The protocol is set on the HttpServerSettings instance passed to the server.

    All integration tests for the adapter must pass with this protocol.

    Check the following Netty examples for reference/examples:

    • https://netty.io/4.1/api/io/netty/handler/codec/http2/CleartextHttp2ServerUpgradeHandler.html
    • https://github.com/netty/netty/blob/4.1/example/src/main/java/io/netty/example/http2/helloworld/server/Http2ServerInitializer.java
    help wanted good first issue 
    opened by jaguililla 0
Releases(2.3.1)
  • 2.3.1(Dec 30, 2022)

  • 2.3.0(Dec 28, 2022)

    What's Changed

    • Add TOML serialization format
    • Add maps merge functionality
    • Add checking utilities in core
    • Move Handlers to its own module
    • Add CI action to mark stale issues

    Full Changelog: https://github.com/hexagonkt/hexagon/compare/2.2.8...2.3.0

    Source code(tar.gz)
    Source code(zip)
Owner
Hexagon
Hexagon Microservices Toolkit
Hexagon
Kotlin microservices with REST, and gRPC using BFF pattern. This repository contains backend services. Everything is dockerized and ready to "Go" actually "Kotlin" :-)

Microservices Kotlin gRPC Deployed in EC2, Check it out! This repo contains microservices written in Kotlin with BFF pattern for performing CRUD opera

Oguzhan 18 Apr 21, 2022
In this Repo i create public apis to serve apps, like muslim apps using Spring, kotlin, and microservices

spring-freelance-apis-kotlin In this Repo i create public apis to serve apps, like muslim apps using Spring, kotlin, and microservices This repo for l

null 6 Feb 13, 2022
☁️ cloud.sh is a lightweight self-hosted cloud for your home lab.

DISCLAIMER: cloud.sh is under development. We do not recommend you to use it in a production environment for now. The storage could be corrupted when

Quentin Guidée 13 Nov 24, 2022
Building Web Applications with React and Kotlin JS Hands-On Lab

Building Web Applications with React and Kotlin JS Hands-On Lab This repository is the code corresponding to the hands-on lab Building Web Application

Brian Donnoe 0 Nov 13, 2021
This repository contains RabbitMQ Protobuf starters with its usage samples for spring-rabbit and spring-cloud-starter-stream-rabbit modules

This repository contains RabbitMQ Protobuf starters with its usage samples for spring-rabbit and spring-cloud-starter-stream-rabbit modules

Maksim Kostromin 2 Nov 29, 2021
FirestoreCleanArchitectureApp is an app built with Kotlin and Firestore that displays data in real-time using the MVVM Architecture Pattern. For the UI it uses Jetpack Compose, Android's modern toolkit for building native UI.

FirestoreCleanArchitectureApp FirestoreCleanArchitectureApp is an app built with Kotlin and Cloud Firestore that displays data in real-time using Andr

Alex 66 Dec 15, 2022
Bukkit library written in Kotlin to make with compatibility and ease non-playable-character (NPC)

mc-npk Easy to use, fast and efficient library to make non-playable-characters (

Luiz Otávio 3 Aug 4, 2022
Server & Web App of Tolgee localization toolkit

Server & Web App of Tolgee localization toolkit

Tolgee 534 Jan 8, 2023
The queue you've always wanted to be in.

Georgian Queue GeorgianQueue is a queue data structure on steroids. The queue you've always wanted to be in. Implemented using singly linked list and

Merab Tato Kutalia 12 Jan 18, 2022
Curso microservices kotlin micronaut

Arquitetura de Microserviços Instruções Criando rede no docker: docker network create micronaut-net Criando imagem Postgresql no Docker: docker run -

null 0 Oct 20, 2021
Microservices with Ktor and Nomad

Microserviços com Ktor e Nomad Esse projeto é um teste prático de microserviços usando o framework Ktor, o banco de dados Postgres, o orquestrador de

Ederson Ferreira 3 Sep 16, 2022
Team management service is a production ready and fully tested service that can be used as a template for a microservices development.

team-mgmt-service Description Team management service is a production ready and fully tested service that can be used as a template for a microservice

Albert Llousas Ortiz 18 Oct 10, 2022
A project to learn about Reactive Microservices experimenting with architectures and patterns

reactive-microservices-workshop Copyright © 2021 Aleix Morgadas - Licenced under CC BY-SA 4.0 A project to learn about Reactive Microservices experime

Aleix Morgadas 7 Feb 21, 2022
Proof-of-Concept messaging and "voice over IP" server that uses microservices

bullets THIS IS A WIP PROJECT. Proof-of-Concept messaging and "voice over IP" server that uses microservices. The project uses many technologies. Such

Paulo Elienay II 0 Jan 2, 2022
This is a template to help you get started building amazing Kotlin applications and libraries.

Welcome to the Starter This is a template to help you get started building amazing Kotlin applications and libraries. Over time, examples will be comp

Backbone 8 Nov 4, 2022
This is the interpreter of Hime language, a dialect of Lisp, run on JVM platform.

Hime Language About This is the interpreter of Hime language, a dialect of Lisp, running on JVM platform. Once a feature is finished and tested, and n

Hime Programming Language 8 Jul 12, 2022
Jetpack Compose for Desktop and Web, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.

Jetpack Compose for Desktop and Web, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.

JetBrains 10k Jan 7, 2023
KVision allows you to build modern web applications with the Kotlin language

KVision allows you to build modern web applications with the Kotlin language, without any use of HTML, CSS or JavaScript. It gives you a rich hierarchy of ready to use GUI components, which can be used as builder blocks for the application UI.

Robert Jaros 985 Jan 1, 2023
This is a sample app to demonstrate the power of using EventSourced models and the ease with which these can be modelled using Kotlin.

Lego 4 Rent This is a sample app to demonstrate the power of using EventSourced models and the ease with which these can be modelled using Kotlin. To

Nico Krijnen 4 Jul 28, 2022