🟣 Opinionated Kotlin libs, DSLs and frameworks to build better web apps

Overview

Tegral logo Tegral

GitHub Workflow Status (CI) Apache 2 license Latest release ktlint

Tegral is an opinionated collection of Kotlin frameworks, libraries, helpers and DSLs that help you make awesome apps, from web back-ends and beyond!

DOCUMENTATION | CHANGELOG

Tegral is in an experimental status. Please report any issue you may find!

class HelloController : KtorController() {
    override fun Routing.install() {
        get("/") {
            call.respondText("Hello World!")
        }
    }
}

fun main() {
    tegral {
        put(::HelloController)
    }
}

Each Tegral library is reusable and extensible. Pick the most suitable libraries for your project, or maybe even all of them for a full Tegral-based application.

Comments
  • OpenApi + Ktor + Resources

    OpenApi + Ktor + Resources

    This PR introduces a new module which integrates tegral-openapi-ktor with type-safe routing. With this package, the OpenAPI descriptions can be part of the resource definition:

    @Resource("/hello/{name}")
    class Hello(val name: String) {
        companion object: OpenApiDescription {
            override val openApi = { 
                description = "Returns a greeting"
            }
        }
    }
    

    There's a bit of ceremony in making the companion object implement an interface, but I couldn't find a better way to attach a piece of static information to the class, while at the same time giving access to the whole OperationDsl.

    opened by serras 13
  • Published artifacts require Java 17

    Published artifacts require Java 17

    The artifacts published in Maven somehow make my projects require Java 17 to run. Although this is an LTS, it would be great if artifacts required only Java 11, broadening the user base.

    Pinging my colleague @nomisRev who's also interested in requiring a lesser version of the JDK.

    opened by serras 9
  • Apply default logging configuration to not spam console

    Apply default logging configuration to not spam console

    Fixes #8 Fixes #9 Fixes #28

    TODO

    • [x] Add tests to the configuration, if possible to the running phase
    • [x] Wait for potential resolution of the strict mode issue (see next comment)
    • [x] Update docs
    • [x] Update changelog
    • [x] ~~Wait for Hoplite release w/ patch included~~ Was released as 2.3.2
    opened by utybo 4
  • Add OpenAPI modules and features

    Add OpenAPI modules and features

    Fixes #31

    TODO

    • [x] Add missing hooks (this feature was very useful in Koa and should be imported here)
    • [x] Remove @KoaDsl annotations and put @TegralDsl annotations everywhere
    • [x] Update documentation
    • [x] Update changelog
    • [x] Fix order of "Tegral DI docs" (order was messed up in docs reorg)
    • [x] Improve coverage
    opened by utybo 3
  • Support Java 11 in published artifacts

    Support Java 11 in published artifacts

    Currently, artifacts require Java 17 (as noted in #44) because they are built with Java 17. Should be set to 11 instead with tests to ensure that that it can actually be used.

    Will fix #44

    TODO

    • [x] Ensure tests fail in CI
    • [x] Add Java 11 as a target version everywhere...
    • [x] ... and ensure the CI gets green after that
    • [x] Update changelog
    opened by utybo 2
  • Automatically stop the tegral environment on jvm shutdown hook

    Automatically stop the tegral environment on jvm shutdown hook

    Fixes #20

    TODO

    • [x] Ensure is removed when stopping the environment so that
      • [x] A) Functional when Ctrl+C-ing twice (might be handled by the JVM)
      • [x] B) Functional when programmatically stopping, then Ctrl+C-ing (shouldn't cause another complete stop)
    • [x] Update changelog
    • [x] Update docs
    opened by utybo 2
  • Add aliases & identifier resolvers

    Add aliases & identifier resolvers

    TODO

    • [x] Finish failing test
    • [x] Adapt factory to use scope() instead of scope.factory()
    • [x] Ensure that eager actually works with aliases and stuff, since resolution is done right away, should probably be done as a separate step?
    • [x] ~~Ensure that alias also works with the noUnused check (e.g. aliases are used and using an alias marks the target as used).~~ ~~Actually, I think the behavior of requiring both the alias and the aliased to be used is fine. Still need to check that it is the case.~~ Actually actually, in order to be more consistent, usage via an alias should be considered a usage regardless. This is to ensure using factories is not considered an unused thing (and any resolver that uses more "internal" object).
    • [x] Ensure that complete also checks for resolvability
    • [x] Ensure that noCycle also checks for cycles created by resolution
    • [ ] Deprecate wrapIn mechanism? Should probably be a separate issue
    • [x] Improve test coverage
    • [x] Update docs
    • [x] Update changelog
    opened by utybo 2
  • Add code coverage

    Add code coverage

    Fixes #18

    ⚠️ Inaccurate atm because not all projects even have tests, which makes them not included in the total calculation

    • [x] Update changelog
    • [x] Update documentation (add details on what the tegral block returns)
    opened by utybo 2
  • Add integration testing support

    Add integration testing support

    • [x] Update changelog
    • [x] Add documentaton on new AppTest module
    • [x] Add documentation on how to do integration testing
    • [x] Add new step in tutorial for testing the endpoint
    • [x] Improve coverage
    opened by utybo 2
  • Tegral DI: a more flexible approach for injection aliases

    Tegral DI: a more flexible approach for injection aliases

    Currently, Tegral DI uses a simple system for storing components: just a map from Identifier to anything they need (currently, all environments use a simple Map<Identifier<*>, Any>, where Any is the actual instance of the object we are interested in).

    While this is alright, it poses a problem for advanced scenarios. For example:

    • Factories, or anything that is wrapped via some injected helper object. This makes it impossible to use the by scope() mechanism to retrieve them, and alternatives must be used (e.g. by scope.factory())
    • Services cannot really rely on the actual type of the object, the only "stable", non-hacky typing information is contained in the identifier. Yet, the identifier is not always accurate w.r.t. the actual type of the object. For example, the following structure will not actually trigger the start() function:
    interface MyService {
        // ...
    }
    
    class MyServiceImpl : MyService, TegralDiService {
        // ...
    }
    
    val env = tegralDi {
        put<MyService>(::MyServiceImpl)
    }
    

    An alternative is supporting a standardized and more complete way to store identifiers, such as:

    typealias Declarations = Map<Identifier<*>, IdentifierResolver<*>>
    
    interface IdentifierResolver<T> {
        fun resolve(allDeclarations: Declarations): T
    }
    
    class SimpleIdentifierResolver<T>(
        val instance: T
    ) : IdentifierResolver<T> {
        override fun resolve(allDeclarations: Declarations): T {
            return instance
        }
    }
    
    class AliasIdentifierResolver<T>(
        val actualIdentifier: Identifier<T>
    ) : IdentifierResolver<T> {
        override fun resolve(allDeclarations: Declarations): T {
            return allDeclarations[actualIdentifier].resolve(allDeclarations)
        }
    }
    

    This is more flexible in pretty much every way.

    ⚠️ This would mean declarations would be part of the public API of all environments (including not extendable ones)

    opened by utybo 1
  • Explore the possibility of

    Explore the possibility of "functional definitions" in DI

    The idea is to be able to define DI components as functions. This would unlock more advanced use cases, an obvious one being easier definition of simple web controllers and Ktor modules.

    Usage

    Here's an example of what this could look like.

    Tegral Web Controllers

    For example:

    class GreeterService {
        fun greet(name: String): String {
            return "Hello, $name!"
        }
    }
    
    @TegralDiFundef
    fun Application.openApiModule() {
        describe {
            title = "My greeter API"
        }
    }
    
    @TegralDiFundef
    fun Routing.controller(gs: GreeterService) {
        get("/greet/{name}") {
            call.respondText(gs.greet(call.parameters["name"]!!))
        }
    }
    
    fun main() {
        tegral {
            install(OpenApiFeature)
            put(::openApiModule)
            put(::controller)
        }
    }
    

    Tegral DI

    
    class GreeterService {
        fun greet(name: String): String {
            return "Hello, $name!"
        }
    }
    
    @TegralDiFundef
    fun greetWorld(gs: GreeterService) {
        return gs.greet("World")
    }
    
    fun main() {
        val env = tegralDi {
            put(::GreterService)
            put(::greetWorld)
        }
        val fundef = env.getOrNull<Fundef>(ofFunction(::greetWorld))
        fundef.function // == ::greetWorld
        fundef() // == greetWorld(...)
    }
    

    Pros, cons and remarks

    Pros

    Indentiation

    Saves an indentation space for controllers and modules and significantly simplifies their definition.

    class HelloController : KtorController() {
        override fun Routing.install() {
            get("class") {
                call.respondText("Hello World!")
            }
        }
    }
    
    @TegralDiFundef
    fun Routing.helloController() {
        get("fun") {
            call.respondText("H:ello World!")
        }
    }
    
    fun main() {
        tegral {
            put(::GreterService)
            put(::HelloController)
            put(::helloController)
        }
    }
    

    Ktor modules

    • Is similar to what the Ktor docs recommend with Ktor modules. This could also make the transition from module-based Ktor to Tegral easier

    Misc.

    • Optional injection (scope.optional()) can easily be supported by using default parameters! (probably with nullable support, so A? = null in a parameter would be the same as env.getOrNull<A>())

    Cons

    Qualifiers

    • Retrieving qualified components becomes a huge mess
      • Either provide qualifier info via annotations. Not super feasible.
      • Maybe a special DSL for it?
    
    class GreeterService {
        fun greet(name: String): String {
            return "Hello, $name!"
        }
    }
    
    @TegralDiFundef
    fun greetWorld(gs: GreeterService) {
    
    }
    
    fun main() {
        val env = tegralDi {
            put(::GreterService, named("Hellofy"))
            put(
                (::greetWorld).toFundef {
                    qualifyParameter("gs", named("Hellofy"))
                }
            )
        }
    }
    
    • Collides with the current put syntax, becomes constructors are considered functions when using reflection. Either
      • Find a way to differentiate between functions and constructors: this is possible using <KFunction object>.javaConstructor != null.
      • Force the use of an annotation permanently for functions (there would still be annotations at first while this is an experiment)

    Remarks

    • In order to respect the "principal" of safe injections, functional definitions would have to retrieve all of the required objects within an init block.

    Todo list

    • [ ] Initial release
      • [ ] Implement basic support in Tegral DI
      • [ ] With experimental annotation
      • [ ] With a special function putFundef
    • [ ] v+1:
      • [ ] Support in Tegral Web Controllers
      • [ ] Merge putFundef into put
    • [ ] v+2:
      • [ ] Drop annotation requirement
      • [ ] Stabilization and GA
    experiments Module: tegral-web-controllers 
    opened by utybo 0
  • Use Netlify instead of Vercel

    Use Netlify instead of Vercel

    I'd like to migrate to Netlify instead of Vercel for personal reasons (and also because I have more experience with Netlify, and I suspect some SEO issues are either caused by Vercel or by #58)

    • [X] Produce builds for MRs and commits
    • [ ] Switch main production website to Netlify
    Module: docs 
    opened by utybo 2
  • Tegral Documentation : Add a more

    Tegral Documentation : Add a more "how to ..." documentation

    As we discussed, it may be interesting to have a tutorial-like documentation for some section of Tegral such as Tegral OpenAPI.

    For example in this screen, it's not completely clear as a new user, what is the script used in the second code block and how to get it.

    image

    Module: docs 
    opened by Kilehynn 0
  • ktor-resources: cannot describe multiple methods on single resource when using getD/postD/etc.

    ktor-resources: cannot describe multiple methods on single resource when using getD/postD/etc.

    I have an endpoint which can receive either a GET to retrieve the resource or a DELETE to delete it.

    Those methods should have different documentation (different response types, summary, response codes, etc.) but I don't see a way to do that using the resource companion object way.

    Right now I defined two objects Get and Delete in my resource instead of a companion object, and I use the normal get delete endpoint definition functions with describe MyResource.Get.openApi and describe MyResource.Delete.openApi, but it's not ideal as it's a different way to document endpoints than when the resource only has one method used, which makes it a little harder to understand for reviewers etc.

    Module: tegral-openapi-ktor-resources 
    opened by Ribesg 3
  • Add documentation for headers in response

    Add documentation for headers in response

    Having a HttpHeader in the response should be possible to add to the documentation. For example a HttpHeaders.Location which is often the case for HttpStatusCode.Created

    routing {
        post("/posts") {
            // create new post -> return ID in location header
            val postID = 1
            call.response.headers.append(HttpHeaders.Location, "/post/$postID")
            call.respond(HttpStatusCode.Created)
        } describe {
            summary = "Create a new post"
            201 response {
                description = "A new post has been created."
                "Location" headerParameter {
                    // see ParameterDsl
                }
            }
        }
    }
    
    Module: tegral-openapi-dsl 
    opened by thebino 1
Releases(v0.0.3)
  • v0.0.3(Oct 1, 2022)

    This update includes a new contributed feature for Ktor resources integration with OpenAPI as well as bug fixes.

    • 📣 Announcement post: https://tegral.zoroark.guru/blog/tegral-0-0-3-release
    • 📜 Changelog: https://github.com/utybo/Tegral/blob/main/CHANGELOG.md#003---2022-10-01

    This version is being released on Maven Central and will be available shortly.

    Source code(tar.gz)
    Source code(zip)
  • v0.0.2(Aug 13, 2022)

    This update includes new OpenAPI features, an overhaul to how dependency injection resolves components, integration testing support and much more!

    • 📣 Announcement post: https://tegral.zoroark.guru/blog/introducing-tegral-0-0-2
    • 📜 Changelog: https://github.com/utybo/Tegral/blob/main/CHANGELOG.md#002---2022-08-14
    Source code(tar.gz)
    Source code(zip)
  • v0.0.1(Jun 2, 2022)

    Welcome to Tegral!

    • Announcement blog post: https://tegral.zoroark.guru/blog/welcome-to-tegral-v0-0-1
    • Changelog: https://github.com/utybo/Tegral/blob/main/CHANGELOG.md

    Releases are available on Maven Central under the group ID guru.zoroark.tegral.

    Source code(tar.gz)
    Source code(zip)
Owner
Zoroark
EPITA student (4th yr, ING2), teaching assistant and developer @EPITA. @EpiLink dev. Make things simple or else bonk.
Zoroark
🌨️ Simple, intuitive, and opinionated command handling library for Kord

??️ Snow Simple, intuitive, and opinionated command handling library for Kord Why? Since I maintain two Discord bots, both in Kotlin, Nino and Noel (p

Noel ʕ •ᴥ•ʔ 1 Jan 16, 2022
QrPay - This section should list any major frameworks/libraries used to bootstrap your project

View Demo · Report Bug · Request Feature About The Project Very simple You register, the system generates a unique ID You login with your unique

Jeffrey Orazulike 3 May 19, 2022
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
Web Container: A simple web container library for Android to help fellow developer to open WebView easily

WebContainer Description Web Container is a simple web container library for And

Achmad Ichsan Thaib 8 Nov 22, 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
A podcast proxy that sits between itunes search api and android apps allowing normalization of rss feeds to standard Json format that can be consumed by apps.

Podcasts Rss Feeds Search Proxy A podcast proxy written using kotlin dsl that sits between itunes search api, podcasts rss feeds and android apps allo

8BitsLives .❤️ 2 Nov 27, 2022
Reach plc. Apps Team Exercise (Junior)Reach plc. Apps Team Exercise (Junior)

Reach plc. Apps Team Exercise (Junior) Description One of our magazines is looking for new sources of revenues and starts a few partnerships with beau

null 0 Nov 9, 2021
Saga pattern implementation in Kotlin build in top of Kotlin's Coroutines.

Module Saga Website can be found here Add in build.gradle.kts repositories { mavenCentral() } dependencies { implementation("io.github.nomisr

Simon Vergauwen 50 Dec 30, 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
An Android template you can use to build your project with gradle kotlin dsl

Android Gradle KTS An Android template you can use to build your project with gradle kotlin dsl Build.gradle.kts You can use your project's build.grad

Deep 17 Sep 12, 2022
Olx-workshop-gdsc - Build Classified Ads Application With Kotlin

Build Classified Ads Application Architecture Database : [Firebase Realtime Data

Raka Adi Nugroho 3 Jan 9, 2022
A starter project to build command-line tools in Kotlin Multiplatform

A starter project to build command-line tools in Kotlin Multiplatform Contains a re-implementation of a real world CLI tool: git-standup Installation

null 0 May 2, 2022
Project build to understand the concepts of Git and GitHub

Project build to understand the concepts of Git and GitHub. Summarizing the concepts learnt. Created a project in Android Studio Before installing And

Rifah A Khan 0 Oct 6, 2021
Use Android Jetpack libraries, Android Architecture Components, ViewModel and LiveData to build this app.

Unscramble App Starter code for Android Basics codelab - Store the data in a ViewModel Unscramble is a single player game app that displays scrambled

Shaima Alghamdi 2 Aug 18, 2022
Build with Jetpack Compose & all modern techniques and architecture of android app development

IMDB Movie App Build with Jetpack Compose & all modern techniques and architecture of android app development ScreenShots ?? Built With ?? Kotlin - Fi

Jayant Kumar 7 Dec 17, 2022
A sample skeleton backend app built using Spring Boot kotlin, Expedia Kotlin Graphql, Reactive Web that can be deployed to Google App Engine Flexible environmennt

spring-kotlin-gql-gae This is a sample skeleton of a backend app that was built using: Spring Boot(Kotlin) Reactive Web Sprinng Data R2DBC with MYSQL

Dario Mungoi 7 Sep 17, 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
Webclient-kotlin-sample - An example of using the http web client to promote synchronous and asynchronous https calls

Web Client Consumer Kotlin Sample The project is an example of using the http we

null 1 May 1, 2022