Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add koin #6

Merged
merged 1 commit into from
Jun 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ For more information on how to this works with other frontends/backends, head ov
- [hikari](https://github.com/brettwooldridge/HikariCP) as JDBC connection pool
- [Exposed](https://github.com/JetBrains/Exposed/) as Kotlin SQL Framework
- [Jackson](https://github.com/FasterXML/jackson) for handling JSON
- [Koin](https://insert-koin.io/) for dependency injection

# Getting started

Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ dependencies {
implementation(Deps.exposedJdbc)
implementation(Deps.exposedJavaTime)
implementation(Deps.hikari)
implementation(Deps.koin)

testImplementation(Deps.ktorTests)
}
2 changes: 2 additions & 0 deletions buildSrc/src/main/kotlin/Deps.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const val logbackVersion = "1.2.3"
const val h2Version = "1.4.200"
const val exposedVersion = "0.32.1"
const val hikariVersion = "4.0.3"
const val koinVersion = "3.1.0"

object Deps {
const val kotlinLib = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
Expand All @@ -21,4 +22,5 @@ object Deps {
const val exposedJdbc = "org.jetbrains.exposed:exposed-jdbc:$exposedVersion"
const val exposedJavaTime = "org.jetbrains.exposed:exposed-java-time:$exposedVersion"
const val hikari = "com.zaxxer:HikariCP:$hikariVersion"
const val koin = "io.insert-koin:koin-ktor:$koinVersion"
}
18 changes: 15 additions & 3 deletions src/Application.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
package com.nooblabs

import com.fasterxml.jackson.databind.SerializationFeature
import com.nooblabs.service.DatabaseFactory
import com.nooblabs.service.IDatabaseFactory
import config.api
import config.cors
import config.jwt
import config.statusPages
import io.ktor.application.Application
import io.ktor.application.install
import io.ktor.auth.Authentication
import io.ktor.features.*
import io.ktor.features.CORS
import io.ktor.features.CallLogging
import io.ktor.features.ContentNegotiation
import io.ktor.features.DefaultHeaders
import io.ktor.features.StatusPages
import io.ktor.jackson.jackson
import io.ktor.routing.routing
import org.koin.ktor.ext.Koin
import org.koin.ktor.ext.inject
import org.slf4j.event.Level

fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)
Expand All @@ -37,7 +43,13 @@ fun Application.module() {
}
}

DatabaseFactory.init()
install(Koin) {
modules(serviceKoinModule)
modules(databaseKoinModule)
}

val factory: IDatabaseFactory by inject()
factory.init()

routing {
install(StatusPages) {
Expand Down
10 changes: 7 additions & 3 deletions src/api/ArticleResource.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.nooblabs.api
import com.nooblabs.models.MultipleArticlesResponse
import com.nooblabs.models.NewArticle
import com.nooblabs.models.UpdateArticle
import com.nooblabs.service.ArticleService
import com.nooblabs.service.IArticleService
import com.nooblabs.util.param
import com.nooblabs.util.userId
import io.ktor.application.call
Expand All @@ -13,9 +13,13 @@ import io.ktor.auth.principal
import io.ktor.http.HttpStatusCode
import io.ktor.request.receive
import io.ktor.response.respond
import io.ktor.routing.*
import io.ktor.routing.Route
import io.ktor.routing.delete
import io.ktor.routing.get
import io.ktor.routing.post
import io.ktor.routing.put

fun Route.article(articleService: ArticleService) {
fun Route.article(articleService: IArticleService) {

authenticate {

Expand Down
4 changes: 2 additions & 2 deletions src/api/AuthResource.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import com.nooblabs.models.LoginUser
import com.nooblabs.models.RegisterUser
import com.nooblabs.models.UpdateUser
import com.nooblabs.models.UserResponse
import com.nooblabs.service.AuthService
import com.nooblabs.service.IAuthService
import com.nooblabs.util.SimpleJWT
import com.nooblabs.util.userId
import io.ktor.application.call
Expand All @@ -16,7 +16,7 @@ import io.ktor.routing.get
import io.ktor.routing.post
import io.ktor.routing.put

fun Route.auth(authService: AuthService, simpleJWT: SimpleJWT) {
fun Route.auth(authService: IAuthService, simpleJWT: SimpleJWT) {

/*
Registration:
Expand Down
4 changes: 2 additions & 2 deletions src/api/CommentResource.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.nooblabs.api

import com.nooblabs.models.PostComment
import com.nooblabs.service.CommentService
import com.nooblabs.service.ICommentService
import com.nooblabs.util.param
import com.nooblabs.util.userId
import io.ktor.application.call
Expand All @@ -16,7 +16,7 @@ import io.ktor.routing.delete
import io.ktor.routing.get
import io.ktor.routing.post

fun Route.comment(commentService: CommentService) {
fun Route.comment(commentService: ICommentService) {

authenticate {

Expand Down
4 changes: 2 additions & 2 deletions src/api/ProfileResource.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.nooblabs.api

import com.nooblabs.service.ProfileService
import com.nooblabs.service.IProfileService
import com.nooblabs.util.param
import com.nooblabs.util.userId
import io.ktor.application.call
Expand All @@ -13,7 +13,7 @@ import io.ktor.routing.delete
import io.ktor.routing.get
import io.ktor.routing.post

fun Route.profile(profileService: ProfileService) {
fun Route.profile(profileService: IProfileService) {

authenticate(optional = true) {

Expand Down
18 changes: 12 additions & 6 deletions src/config/Api.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,25 @@ import com.nooblabs.api.article
import com.nooblabs.api.auth
import com.nooblabs.api.comment
import com.nooblabs.api.profile
import com.nooblabs.service.*
import com.nooblabs.service.IArticleService
import com.nooblabs.service.IAuthService
import com.nooblabs.service.ICommentService
import com.nooblabs.service.IDatabaseFactory
import com.nooblabs.service.IProfileService
import io.ktor.application.call
import io.ktor.response.respond
import io.ktor.routing.Route
import io.ktor.routing.get
import io.ktor.routing.route
import org.koin.ktor.ext.inject

fun Route.api() {

val authService = AuthService()
val profileService = ProfileService()
val articleService = ArticleService()
val commentService = CommentService()
val authService: IAuthService by inject()
val profileService: IProfileService by inject()
val articleService: IArticleService by inject()
val commentService: ICommentService by inject()
val databaseFactory: IDatabaseFactory by inject()

route("/api") {

Expand All @@ -30,7 +36,7 @@ fun Route.api() {
comment(commentService)

get("/drop") {
DatabaseFactory.drop()
databaseFactory.drop()
call.respond("OK")
}
}
Expand Down
24 changes: 24 additions & 0 deletions src/koin.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.nooblabs

import com.nooblabs.service.ArticleService
import com.nooblabs.service.AuthService
import com.nooblabs.service.CommentService
import com.nooblabs.service.DatabaseFactory
import com.nooblabs.service.IArticleService
import com.nooblabs.service.IAuthService
import com.nooblabs.service.ICommentService
import com.nooblabs.service.IDatabaseFactory
import com.nooblabs.service.IProfileService
import com.nooblabs.service.ProfileService
import org.koin.dsl.module

val serviceKoinModule = module {
single<IArticleService> { ArticleService(get()) }
single<IAuthService> { AuthService(get()) }
single<ICommentService> { CommentService(get()) }
single<IProfileService> { ProfileService(get()) }
}

val databaseKoinModule = module {
single<IDatabaseFactory> { DatabaseFactory() }
}
53 changes: 35 additions & 18 deletions src/service/ArticleService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,35 @@ import com.nooblabs.models.TagResponse
import com.nooblabs.models.Tags
import com.nooblabs.models.UpdateArticle
import com.nooblabs.models.User
import com.nooblabs.service.DatabaseFactory.dbQuery
import com.nooblabs.util.ArticleDoesNotExist
import com.nooblabs.util.AuthorizationException
import org.jetbrains.exposed.sql.Op
import org.jetbrains.exposed.sql.SizedCollection
import org.jetbrains.exposed.sql.SortOrder
import java.time.Instant

class ArticleService {
interface IArticleService {
suspend fun createArticle(userId: String, newArticle: NewArticle): ArticleResponse

suspend fun createArticle(userId: String, newArticle: NewArticle): ArticleResponse {
return dbQuery {
suspend fun updateArticle(userId: String, slug: String, updateArticle: UpdateArticle): ArticleResponse

suspend fun getArticle(slug: String): ArticleResponse

suspend fun getArticles(userId: String? = null, filter: Map<String, String?>): List<ArticleResponse.Article>

suspend fun getFeedArticles(userId: String, filter: Map<String, String?>): List<ArticleResponse.Article>

suspend fun changeFavorite(userId: String, slug: String, favorite: Boolean): ArticleResponse

suspend fun deleteArticle(userId: String, slug: String)

suspend fun getAllTags(): TagResponse
}

class ArticleService(private val databaseFactory: IDatabaseFactory) : IArticleService {

override suspend fun createArticle(userId: String, newArticle: NewArticle): ArticleResponse {
return databaseFactory.dbQuery {
val user = getUser(userId)
val article = Article.new {
title = newArticle.article.title
Expand All @@ -35,8 +52,8 @@ class ArticleService {
}
}

suspend fun updateArticle(userId: String, slug: String, updateArticle: UpdateArticle): ArticleResponse {
return dbQuery {
override suspend fun updateArticle(userId: String, slug: String, updateArticle: UpdateArticle): ArticleResponse {
return databaseFactory.dbQuery {
val user = getUser(userId)
val article = getArticleBySlug(slug)
if (!isArticleAuthor(article, user)) throw AuthorizationException()
Expand All @@ -49,15 +66,15 @@ class ArticleService {
}
}

suspend fun getArticle(slug: String): ArticleResponse {
return dbQuery {
override suspend fun getArticle(slug: String): ArticleResponse {
return databaseFactory.dbQuery {
val article = getArticleBySlug(slug)
getArticleResponse(article)
}
}

suspend fun getArticles(userId: String? = null, filter: Map<String, String?>): List<ArticleResponse.Article> {
return dbQuery {
override suspend fun getArticles(userId: String?, filter: Map<String, String?>): List<ArticleResponse.Article> {
return databaseFactory.dbQuery {
val user = if (userId != null) getUser(userId) else null
getAllArticles(
currentUser = user,
Expand All @@ -70,8 +87,8 @@ class ArticleService {
}
}

suspend fun getFeedArticles(userId: String, filter: Map<String, String?>): List<ArticleResponse.Article> {
return dbQuery {
override suspend fun getFeedArticles(userId: String, filter: Map<String, String?>): List<ArticleResponse.Article> {
return databaseFactory.dbQuery {
val user = getUser(userId)
getAllArticles(
currentUser = user,
Expand All @@ -82,8 +99,8 @@ class ArticleService {
}
}

suspend fun changeFavorite(userId: String, slug: String, favorite: Boolean): ArticleResponse {
return dbQuery {
override suspend fun changeFavorite(userId: String, slug: String, favorite: Boolean): ArticleResponse {
return databaseFactory.dbQuery {
val user = getUser(userId)
val article = getArticleBySlug(slug)
if (favorite) {
Expand All @@ -95,17 +112,17 @@ class ArticleService {
}
}

suspend fun deleteArticle(userId: String, slug: String) {
dbQuery {
override suspend fun deleteArticle(userId: String, slug: String) {
databaseFactory.dbQuery {
val user = getUser(userId)
val article = getArticleBySlug(slug)
if (!isArticleAuthor(article, user)) throw AuthorizationException()
article.delete()
}
}

suspend fun getAllTags(): TagResponse {
return dbQuery {
override suspend fun getAllTags(): TagResponse {
return databaseFactory.dbQuery {
val tags = Tag.all().map { it.tag }
TagResponse(tags)
}
Expand Down
Loading