Code Monkey home page Code Monkey logo

kediatr's Introduction

kediatR Release kediatR-core Release kediatR-spring-starter codecov

Humus! The kediatr mascot

Mediator implementation in kotlin with native coroutine support.

Supports synchronous and async (using kotlin coroutines ) command and query handling, native kotlin implementation, spring-boot, quarkus and koin configurations.

After kediatr-core version 1.0.17 you can use any dependency injection framework by implementing DependencyProvider interface.

kediatR has multiple implementations: kediatR-core, kediatR-spring-starter, kediatR-koin-starter and kediatR-quarkus-starter.

kediatR-core

<dependency>
  <groupId>com.trendyol</groupId>
  <artifactId>kediatr-core</artifactId>
  <version>1.0.18</version>
</dependency>

kediatR-spring-starter

<dependency>
  <groupId>com.trendyol</groupId>
  <artifactId>kediatr-spring-starter</artifactId>
  <version>1.0.18</version>
</dependency>

kediatR-koin-starter

<dependency>
  <groupId>com.trendyol</groupId>
  <artifactId>kediatr-koin-starter</artifactId>
  <version>1.0.1</version>
</dependency>

kediatR-quarkus-starter

<dependency>
  <groupId>com.trendyol</groupId>
  <artifactId>kediatr-quarkus-starter</artifactId>
  <version>1.0.2</version>
</dependency>

Usage

  • add kediatr-core dependency to your POM

Command dispatching

class ManuelDependencyProvider(
    private val handlerMap: HashMap<Class<*>, Any>
) : DependencyProvider {
    override fun <T> getSingleInstanceOf(clazz: Class<T>): T {
        return handlerMap[clazz] as T
    }

    override fun <T> getSubTypesOf(clazz: Class<T>): Collection<Class<T>> {
        return handlerMap
            .filter { it.key.interfaces.contains(clazz) }
            .map { it.key as Class<T> }
    }
}

fun main() {
    val handler = MyCommandHandler()
    val handlers: HashMap<Class<*>, Any> = hashMapOf(Pair(MyCommandHandler::class.java, handler))
    val provider = ManuelDependencyProvider(handlers)
    val bus: CommandBus = CommandBusBuilder(provider).build()
    bus.executeCommand(HelloCommand("hello"))
}

class HelloCommand(val message: String) : Command

class HelloCommandHandler : CommandHandler<HelloCommand> {
    override fun handle(command: MyCommand) {
        println(command.message)
    }
}

Query dispatching

fun main() {
    val handler = GetSomeDataQueryHandler()
    val handlers: HashMap<Class<*>, Any> = hashMapOf(Pair(GetSomeDataQuery::class.java, handler))
    val provider = ManuelDependencyProvider(handlers)
    val bus: CommandBus = CommandBusBuilder(provider).build()
    val result: String = bus.executeQuery(GetSomeDataQuery(1))
    println(result)
}

class GetSomeDataQuery(val id: Int) : Query<String>

class GetSomeDataQueryHandler : QueryHandler<GetSomeDataQuery, String> {
    override fun handle(query: GetSomeDataQuery): String {
        // you can use properties in the query object to retrieve data from somewhere
        // val result = getDataFromSomewhere(query.id)
        // return result

        return "hello"
    }
}

Pipeline Behavior

class CommandProcessingPipeline : PipelineBehavior {
    override fun <TRequest> preProcess(request: TRequest) {
        println("Starting process.")
    }
    override fun <TRequest> postProcess(request: TRequest) {
        println("Ending process.")
    }
    override fun <TRequest, TException : Exception> handleExceptionProcess(request: TRequest, exception: TException) {
        println("Some exception occurred during process. Error: $exception")
    }
}

Usage with SpringBoot

  • add kediatr-spring dependency to your POM and enjoy yourself
@Service
class UserService(private val commandBus: CommandBus) {
    fun findUser(id: Long) {
        return commandBus.executeQuery(GetUserByIdQuery(id))
    }
}

class GetUserByIdQuery(private val id: Long) : Query<UserDto>

@Component
class GetUserByIdQueryHandler(private val userRepository: UserRepository) : QueryHandler<GetUserByIdQuery, UserDto> {
    fun handle(query: GetUserByIdQuery): UserDto {
        val user = userRepository.findById(query.id)
        // do some operation on user
        return UserDto(user.id, user.name, user.surname)
    }
}

Async Usage with Kotlin Coroutine Support

class UserService(private val commandBus: CommandBus) {
    suspend fun findUser(id: Long) {
        return commandBus.executeQueryAsync(GetUserByIdQuery(id))
    }
}

class GetUserByIdQuery(private val id: Long) : Query<UserDto>

class GetUserByIdQueryHandler(private val userRepository: UserRepository) : AsyncQueryHandler<GetUserByIdQuery, UserDto> {
    suspend fun handleAsync(query: GetUserByIdQuery): UserDto {
        val user = userRepository.findByIdAsync(query.id)
        // do some operation on user
        return UserDto(user.id, user.name, user.surname)
    }
}

class AsyncCommandProcessingPipeline : AsyncPipelineBehavior {
    override suspend fun <TRequest> preProcess(request: TRequest) {
        println("Starting process.")
    }
    override suspend fun <TRequest> postProcess(request: TRequest) {
        println("Ending process.")
    }
    override suspend fun <TRequest, TException : Exception> handleException(request: TRequest, exception: TException) {
        println("Some exception occurred during process. Error: $exception")
    }
}

Usage with Koin

Simply inject kediatr as a singleton dependency with any module and inject handler instances. KediatrKoin.getCommandBus() must be in the same module with at least one Handler to get correct package name for reflection. Please note that this is an experimental release and reflection strategy with koin is a little wonky. Please open a pull request if you think there is a better implementation.

val kediatrModule = module {
    single { KediatrKoin.getCommandBus() }
    single { GetUserByIdQueryHandler(get()) }
}

class UserService(private val commandBus: CommandBus) {
    fun findUser(id: Long) {
        return commandBus.executeQuery(GetUserByIdQuery(id))
    }
}

class GetUserByIdQuery(private val id: Long) : Query<UserDto>

class GetUserByIdQueryHandler(private val userRepository: UserRepository) : QueryHandler<GetUserByIdQuery, UserDto> {
    fun handle(query: GetUserByIdQuery): UserDto {
        val user = userRepository.findById(query.id)
        // do some operation on user
        return UserDto(user.id, user.name, user.surname)
    }
}

Usage with Quarkus

  • Add kediatr-quarkus-starter dependency to your POM
  • Quarkus does not index 3rd party libraries unless you explicitly indicate. Add this configuration to application.properties file.
  quarkus:
    index-dependency:
      kediatr:
        group-id: com.trendyol
        artifact-id: kediatr-quarkus-starter
  • Add @Startup annotation for every handler so that kediatr can prepare queries and commands on beginning of the application.
class UserService(private val commandBus: CommandBus) {
    fun findUser(id: Long) {
        return commandBus.executeQuery(GetUserByIdQuery(id))
    }
}

class GetUserByIdQuery(private val id: Long) : Query<UserDto>

@ApplicationScoped
@Startup
class GetUserByIdQueryHandler(private val userRepository: UserRepository) : QueryHandler<GetUserByIdQuery, UserDto> {
    fun handle(query: GetUserByIdQuery): UserDto {
        val user = userRepository.findById(query.id)
        // do some operation on user
        return UserDto(user.id, user.name, user.surname)
    }
}

Review Our IntelliJ Plugin

https://plugins.jetbrains.com/plugin/16017-kediatr-helper

Screencast 1

Screencast 2

Source: https://github.com/bilal-kilic/kediatr-helper

kediatr's People

Contributors

bilal-kilic avatar canerpatir avatar mhmtszr avatar hcelaloner avatar yigit-darcin avatar dependabot[bot] avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.