├── ktor-2.x
├── settings.gradle.kts
├── .gitignore
├── src
│ ├── main
│ │ ├── resources
│ │ │ ├── static
│ │ │ │ └── index.html
│ │ │ ├── db
│ │ │ │ └── migration
│ │ │ │ │ ├── changesets
│ │ │ │ │ └── changeset-202102281045.sql
│ │ │ │ │ └── migrations.xml
│ │ │ ├── application.conf
│ │ │ ├── doc
│ │ │ │ ├── index.html
│ │ │ │ └── swagger.yml
│ │ │ ├── swagger
│ │ │ │ └── swagger.yml
│ │ │ └── logback.xml
│ │ └── kotlin
│ │ │ └── com
│ │ │ └── prof18
│ │ │ └── ktor
│ │ │ └── chucknorris
│ │ │ └── sample
│ │ │ ├── database
│ │ │ ├── DatabaseFactory.kt
│ │ │ └── DatabaseFactoryImpl.kt
│ │ │ ├── features
│ │ │ └── jokes
│ │ │ │ ├── data
│ │ │ │ ├── JokeLocalDataSource.kt
│ │ │ │ ├── JokeLocalDataSourceImpl.kt
│ │ │ │ └── dao
│ │ │ │ │ └── Joke.kt
│ │ │ │ ├── domain
│ │ │ │ ├── model
│ │ │ │ │ └── JokeDTO.kt
│ │ │ │ ├── JokeRepository.kt
│ │ │ │ └── mapper
│ │ │ │ │ └── DTOMapper.kt
│ │ │ │ └── resource
│ │ │ │ └── JokeResource.kt
│ │ │ ├── jobs
│ │ │ ├── JobFactory.kt
│ │ │ ├── RandomJokeJob.kt
│ │ │ └── JobSchedulerManager.kt
│ │ │ ├── di
│ │ │ └── AppModule.kt
│ │ │ └── config
│ │ │ └── AppConfig.kt
│ └── test
│ │ ├── kotlin
│ │ └── com
│ │ │ └── prof18
│ │ │ └── ktor
│ │ │ └── chucknorris
│ │ │ └── sample
│ │ │ ├── testutils
│ │ │ └── database
│ │ │ │ ├── SchemaDefinition.kt
│ │ │ │ ├── DatabaseFactoryForUnitTest.kt
│ │ │ │ └── DatabaseFactoryForServerTest.kt
│ │ │ └── features
│ │ │ └── jokes
│ │ │ └── resource
│ │ │ └── JokeResourceTest.kt
│ │ └── resources
│ │ └── logback-test.xml
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradle.properties
├── local.properties
└── README.md
├── part1
├── settings.gradle.kts
├── .gitignore
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── src
│ ├── main
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── prof18
│ │ │ │ └── ktor
│ │ │ │ └── chucknorris
│ │ │ │ └── sample
│ │ │ │ ├── features
│ │ │ │ └── jokes
│ │ │ │ │ ├── data
│ │ │ │ │ ├── dao
│ │ │ │ │ │ └── Joke.kt
│ │ │ │ │ ├── JokeLocalDataSource.kt
│ │ │ │ │ └── JokeLocalDataSourceImpl.kt
│ │ │ │ │ ├── domain
│ │ │ │ │ ├── mapper
│ │ │ │ │ │ └── DTOMapper.kt
│ │ │ │ │ ├── model
│ │ │ │ │ │ └── JokeDTO.kt
│ │ │ │ │ ├── JokeRepository.kt
│ │ │ │ │ └── JokeRepositoryImpl.kt
│ │ │ │ │ └── resource
│ │ │ │ │ └── JokeResource.kt
│ │ │ │ ├── database
│ │ │ │ ├── DatabaseFactory.kt
│ │ │ │ └── DatabaseFactoryImpl.kt
│ │ │ │ ├── di
│ │ │ │ └── AppModule.kt
│ │ │ │ ├── config
│ │ │ │ └── AppConfig.kt
│ │ │ │ └── Application.kt
│ │ └── resources
│ │ │ ├── application.conf
│ │ │ └── logback.xml
│ └── test
│ │ └── kotlin
│ │ └── com
│ │ └── prof18
│ │ └── ktor
│ │ └── chucknorris
│ │ └── sample
│ │ ├── features
│ │ └── jokes
│ │ │ ├── fake
│ │ │ └── JokeRepositoryFake.kt
│ │ │ └── resource
│ │ │ └── JokeResourceTest.kt
│ │ └── testutils
│ │ └── TestServer.kt
├── README.md
└── build.gradle.kts
├── part2
├── settings.gradle.kts
├── .gitignore
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── src
│ ├── main
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── prof18
│ │ │ │ └── ktor
│ │ │ │ └── chucknorris
│ │ │ │ └── sample
│ │ │ │ ├── features
│ │ │ │ └── jokes
│ │ │ │ │ ├── data
│ │ │ │ │ ├── dao
│ │ │ │ │ │ └── Joke.kt
│ │ │ │ │ ├── JokeLocalDataSource.kt
│ │ │ │ │ └── JokeLocalDataSourceImpl.kt
│ │ │ │ │ ├── domain
│ │ │ │ │ ├── mapper
│ │ │ │ │ │ └── DTOMapper.kt
│ │ │ │ │ ├── model
│ │ │ │ │ │ └── JokeDTO.kt
│ │ │ │ │ ├── JokeRepository.kt
│ │ │ │ │ └── JokeRepositoryImpl.kt
│ │ │ │ │ └── resource
│ │ │ │ │ └── JokeResource.kt
│ │ │ │ ├── database
│ │ │ │ ├── DatabaseFactory.kt
│ │ │ │ └── DatabaseFactoryImpl.kt
│ │ │ │ ├── di
│ │ │ │ └── AppModule.kt
│ │ │ │ ├── config
│ │ │ │ └── AppConfig.kt
│ │ │ │ └── Application.kt
│ │ └── resources
│ │ │ ├── application.conf
│ │ │ └── logback.xml
│ └── test
│ │ ├── kotlin
│ │ └── com
│ │ │ └── prof18
│ │ │ └── ktor
│ │ │ └── chucknorris
│ │ │ └── sample
│ │ │ ├── features
│ │ │ └── jokes
│ │ │ │ ├── fake
│ │ │ │ └── JokeRepositoryFake.kt
│ │ │ │ └── resource
│ │ │ │ └── JokeResourceTest.kt
│ │ │ └── testutils
│ │ │ └── TestServer.kt
│ │ └── resources
│ │ └── logback-test.xml
├── README.md
└── build.gradle.kts
├── part3
├── settings.gradle.kts
├── .gitignore
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── src
│ ├── main
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── prof18
│ │ │ │ └── ktor
│ │ │ │ └── chucknorris
│ │ │ │ └── sample
│ │ │ │ ├── database
│ │ │ │ ├── DatabaseFactory.kt
│ │ │ │ └── DatabaseFactoryImpl.kt
│ │ │ │ ├── features
│ │ │ │ └── jokes
│ │ │ │ │ ├── data
│ │ │ │ │ ├── JokeLocalDataSource.kt
│ │ │ │ │ ├── JokeLocalDataSourceImpl.kt
│ │ │ │ │ └── dao
│ │ │ │ │ │ └── Joke.kt
│ │ │ │ │ ├── domain
│ │ │ │ │ ├── model
│ │ │ │ │ │ └── JokeDTO.kt
│ │ │ │ │ ├── JokeRepository.kt
│ │ │ │ │ ├── mapper
│ │ │ │ │ │ └── DTOMapper.kt
│ │ │ │ │ └── JokeRepositoryImpl.kt
│ │ │ │ │ └── resource
│ │ │ │ │ └── JokeResource.kt
│ │ │ │ ├── di
│ │ │ │ └── AppModule.kt
│ │ │ │ ├── config
│ │ │ │ └── AppConfig.kt
│ │ │ │ └── Application.kt
│ │ └── resources
│ │ │ ├── db
│ │ │ └── migration
│ │ │ │ ├── changesets
│ │ │ │ └── changeset-202102281045.sql
│ │ │ │ └── migrations.xml
│ │ │ ├── application.conf
│ │ │ └── logback.xml
│ └── test
│ │ ├── kotlin
│ │ └── com
│ │ │ └── prof18
│ │ │ └── ktor
│ │ │ └── chucknorris
│ │ │ └── sample
│ │ │ ├── testutils
│ │ │ ├── database
│ │ │ │ ├── SchemaDefinition.kt
│ │ │ │ ├── DatabaseFactoryForUnitTest.kt
│ │ │ │ └── DatabaseFactoryForServerTest.kt
│ │ │ └── TestServer.kt
│ │ │ └── features
│ │ │ └── jokes
│ │ │ ├── domain
│ │ │ └── JokeRepositoryImplTest.kt
│ │ │ └── resource
│ │ │ └── JokeResourceTest.kt
│ │ └── resources
│ │ └── logback-test.xml
├── gradle.properties
├── local.properties
├── README.md
└── build.gradle.kts
├── part4
├── settings.gradle.kts
├── .gitignore
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── src
│ ├── main
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── prof18
│ │ │ │ └── ktor
│ │ │ │ └── chucknorris
│ │ │ │ └── sample
│ │ │ │ ├── database
│ │ │ │ ├── DatabaseFactory.kt
│ │ │ │ └── DatabaseFactoryImpl.kt
│ │ │ │ ├── features
│ │ │ │ └── jokes
│ │ │ │ │ ├── data
│ │ │ │ │ ├── JokeLocalDataSource.kt
│ │ │ │ │ ├── JokeLocalDataSourceImpl.kt
│ │ │ │ │ └── dao
│ │ │ │ │ │ └── Joke.kt
│ │ │ │ │ ├── domain
│ │ │ │ │ ├── model
│ │ │ │ │ │ └── JokeDTO.kt
│ │ │ │ │ ├── JokeRepository.kt
│ │ │ │ │ ├── mapper
│ │ │ │ │ │ └── DTOMapper.kt
│ │ │ │ │ └── JokeRepositoryImpl.kt
│ │ │ │ │ └── resource
│ │ │ │ │ └── JokeResource.kt
│ │ │ │ ├── di
│ │ │ │ └── AppModule.kt
│ │ │ │ ├── config
│ │ │ │ └── AppConfig.kt
│ │ │ │ └── Application.kt
│ │ └── resources
│ │ │ ├── db
│ │ │ └── migration
│ │ │ │ ├── changesets
│ │ │ │ └── changeset-202102281045.sql
│ │ │ │ └── migrations.xml
│ │ │ ├── application.conf
│ │ │ └── logback.xml
│ └── test
│ │ ├── kotlin
│ │ └── com
│ │ │ └── prof18
│ │ │ └── ktor
│ │ │ └── chucknorris
│ │ │ └── sample
│ │ │ ├── testutils
│ │ │ ├── database
│ │ │ │ ├── SchemaDefinition.kt
│ │ │ │ ├── DatabaseFactoryForUnitTest.kt
│ │ │ │ └── DatabaseFactoryForServerTest.kt
│ │ │ └── TestServer.kt
│ │ │ └── features
│ │ │ └── jokes
│ │ │ ├── domain
│ │ │ └── JokeRepositoryImplTest.kt
│ │ │ └── resource
│ │ │ └── JokeResourceTest.kt
│ │ └── resources
│ │ └── logback-test.xml
├── gradle.properties
├── local.properties
└── README.md
├── part5
├── settings.gradle.kts
├── .gitignore
├── src
│ ├── main
│ │ ├── resources
│ │ │ ├── static
│ │ │ │ └── index.html
│ │ │ ├── db
│ │ │ │ └── migration
│ │ │ │ │ ├── changesets
│ │ │ │ │ └── changeset-202102281045.sql
│ │ │ │ │ └── migrations.xml
│ │ │ ├── application.conf
│ │ │ ├── doc
│ │ │ │ ├── index.html
│ │ │ │ └── swagger.yml
│ │ │ ├── swagger
│ │ │ │ └── swagger.yml
│ │ │ └── logback.xml
│ │ └── kotlin
│ │ │ └── com
│ │ │ └── prof18
│ │ │ └── ktor
│ │ │ └── chucknorris
│ │ │ └── sample
│ │ │ ├── database
│ │ │ ├── DatabaseFactory.kt
│ │ │ └── DatabaseFactoryImpl.kt
│ │ │ ├── features
│ │ │ └── jokes
│ │ │ │ ├── data
│ │ │ │ ├── JokeLocalDataSource.kt
│ │ │ │ ├── JokeLocalDataSourceImpl.kt
│ │ │ │ └── dao
│ │ │ │ │ └── Joke.kt
│ │ │ │ ├── domain
│ │ │ │ ├── model
│ │ │ │ │ └── JokeDTO.kt
│ │ │ │ ├── JokeRepository.kt
│ │ │ │ ├── mapper
│ │ │ │ │ └── DTOMapper.kt
│ │ │ │ └── JokeRepositoryImpl.kt
│ │ │ │ └── resource
│ │ │ │ └── JokeResource.kt
│ │ │ ├── di
│ │ │ └── AppModule.kt
│ │ │ └── config
│ │ │ └── AppConfig.kt
│ └── test
│ │ ├── kotlin
│ │ └── com
│ │ │ └── prof18
│ │ │ └── ktor
│ │ │ └── chucknorris
│ │ │ └── sample
│ │ │ ├── testutils
│ │ │ ├── database
│ │ │ │ ├── SchemaDefinition.kt
│ │ │ │ ├── DatabaseFactoryForUnitTest.kt
│ │ │ │ └── DatabaseFactoryForServerTest.kt
│ │ │ └── TestServer.kt
│ │ │ └── features
│ │ │ └── jokes
│ │ │ ├── domain
│ │ │ └── JokeRepositoryImplTest.kt
│ │ │ └── resource
│ │ │ └── JokeResourceTest.kt
│ │ └── resources
│ │ └── logback-test.xml
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradle.properties
├── local.properties
└── README.md
├── part6
├── settings.gradle.kts
├── .gitignore
├── src
│ ├── main
│ │ ├── resources
│ │ │ ├── static
│ │ │ │ └── index.html
│ │ │ ├── db
│ │ │ │ └── migration
│ │ │ │ │ ├── changesets
│ │ │ │ │ └── changeset-202102281045.sql
│ │ │ │ │ └── migrations.xml
│ │ │ ├── application.conf
│ │ │ ├── doc
│ │ │ │ ├── index.html
│ │ │ │ └── swagger.yml
│ │ │ ├── swagger
│ │ │ │ └── swagger.yml
│ │ │ └── logback.xml
│ │ └── kotlin
│ │ │ └── com
│ │ │ └── prof18
│ │ │ └── ktor
│ │ │ └── chucknorris
│ │ │ └── sample
│ │ │ ├── database
│ │ │ ├── DatabaseFactory.kt
│ │ │ └── DatabaseFactoryImpl.kt
│ │ │ ├── features
│ │ │ └── jokes
│ │ │ │ ├── data
│ │ │ │ ├── JokeLocalDataSource.kt
│ │ │ │ ├── JokeLocalDataSourceImpl.kt
│ │ │ │ └── dao
│ │ │ │ │ └── Joke.kt
│ │ │ │ ├── domain
│ │ │ │ ├── model
│ │ │ │ │ └── JokeDTO.kt
│ │ │ │ ├── JokeRepository.kt
│ │ │ │ ├── mapper
│ │ │ │ │ └── DTOMapper.kt
│ │ │ │ └── JokeRepositoryImpl.kt
│ │ │ │ └── resource
│ │ │ │ └── JokeResource.kt
│ │ │ ├── jobs
│ │ │ ├── JobFactory.kt
│ │ │ ├── RandomJokeJob.kt
│ │ │ └── JobSchedulerManager.kt
│ │ │ ├── di
│ │ │ └── AppModule.kt
│ │ │ └── config
│ │ │ └── AppConfig.kt
│ └── test
│ │ ├── kotlin
│ │ └── com
│ │ │ └── prof18
│ │ │ └── ktor
│ │ │ └── chucknorris
│ │ │ └── sample
│ │ │ └── testutils
│ │ │ └── database
│ │ │ ├── SchemaDefinition.kt
│ │ │ ├── DatabaseFactoryForUnitTest.kt
│ │ │ └── DatabaseFactoryForServerTest.kt
│ │ └── resources
│ │ └── logback-test.xml
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradle.properties
├── local.properties
└── README.md
├── ktor-1.6.x
├── settings.gradle.kts
├── .gitignore
├── src
│ ├── main
│ │ ├── resources
│ │ │ ├── static
│ │ │ │ └── index.html
│ │ │ ├── db
│ │ │ │ └── migration
│ │ │ │ │ ├── changesets
│ │ │ │ │ └── changeset-202102281045.sql
│ │ │ │ │ └── migrations.xml
│ │ │ ├── application.conf
│ │ │ ├── doc
│ │ │ │ ├── index.html
│ │ │ │ └── swagger.yml
│ │ │ ├── swagger
│ │ │ │ └── swagger.yml
│ │ │ └── logback.xml
│ │ └── kotlin
│ │ │ └── com
│ │ │ └── prof18
│ │ │ └── ktor
│ │ │ └── chucknorris
│ │ │ └── sample
│ │ │ ├── database
│ │ │ ├── DatabaseFactory.kt
│ │ │ └── DatabaseFactoryImpl.kt
│ │ │ ├── features
│ │ │ └── jokes
│ │ │ │ ├── data
│ │ │ │ ├── JokeLocalDataSource.kt
│ │ │ │ ├── JokeLocalDataSourceImpl.kt
│ │ │ │ └── dao
│ │ │ │ │ └── Joke.kt
│ │ │ │ ├── domain
│ │ │ │ ├── model
│ │ │ │ │ └── JokeDTO.kt
│ │ │ │ ├── JokeRepository.kt
│ │ │ │ ├── mapper
│ │ │ │ │ └── DTOMapper.kt
│ │ │ │ └── JokeRepositoryImpl.kt
│ │ │ │ └── resource
│ │ │ │ └── JokeResource.kt
│ │ │ ├── jobs
│ │ │ ├── JobFactory.kt
│ │ │ ├── RandomJokeJob.kt
│ │ │ └── JobSchedulerManager.kt
│ │ │ ├── di
│ │ │ └── AppModule.kt
│ │ │ └── config
│ │ │ └── AppConfig.kt
│ └── test
│ │ ├── kotlin
│ │ └── com
│ │ │ └── prof18
│ │ │ └── ktor
│ │ │ └── chucknorris
│ │ │ └── sample
│ │ │ └── testutils
│ │ │ └── database
│ │ │ ├── SchemaDefinition.kt
│ │ │ ├── DatabaseFactoryForUnitTest.kt
│ │ │ └── DatabaseFactoryForServerTest.kt
│ │ └── resources
│ │ └── logback-test.xml
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradle.properties
├── local.properties
└── README.md
├── .gitignore
└── README.md
/ktor-2.x/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "ktor-chuck-norris-sample"
--------------------------------------------------------------------------------
/part1/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "ktor-chuck-norris-sample"
--------------------------------------------------------------------------------
/part2/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "ktor-chuck-norris-sample"
--------------------------------------------------------------------------------
/part3/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "ktor-chuck-norris-sample"
--------------------------------------------------------------------------------
/part4/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "ktor-chuck-norris-sample"
--------------------------------------------------------------------------------
/part5/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "ktor-chuck-norris-sample"
--------------------------------------------------------------------------------
/part6/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "ktor-chuck-norris-sample"
--------------------------------------------------------------------------------
/ktor-1.6.x/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "ktor-chuck-norris-sample"
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle
2 | /.idea
3 | /out
4 | /build
5 | *.iml
6 | *.ipr
7 | *.iws
8 | .DS_Store
9 |
--------------------------------------------------------------------------------
/ktor-2.x/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle
2 | /.idea
3 | /out
4 | /build
5 | *.iml
6 | *.ipr
7 | *.iws
8 | .DS_Store
9 |
--------------------------------------------------------------------------------
/part1/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle
2 | /.idea
3 | /out
4 | /build
5 | *.iml
6 | *.ipr
7 | *.iws
8 | .DS_Store
9 |
--------------------------------------------------------------------------------
/part2/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle
2 | /.idea
3 | /out
4 | /build
5 | *.iml
6 | *.ipr
7 | *.iws
8 | .DS_Store
9 |
--------------------------------------------------------------------------------
/part3/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle
2 | /.idea
3 | /out
4 | /build
5 | *.iml
6 | *.ipr
7 | *.iws
8 | .DS_Store
9 |
--------------------------------------------------------------------------------
/part4/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle
2 | /.idea
3 | /out
4 | /build
5 | *.iml
6 | *.ipr
7 | *.iws
8 | .DS_Store
9 |
--------------------------------------------------------------------------------
/part5/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle
2 | /.idea
3 | /out
4 | /build
5 | *.iml
6 | *.ipr
7 | *.iws
8 | .DS_Store
9 |
--------------------------------------------------------------------------------
/part6/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle
2 | /.idea
3 | /out
4 | /build
5 | *.iml
6 | *.ipr
7 | *.iws
8 | .DS_Store
9 |
--------------------------------------------------------------------------------
/ktor-1.6.x/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle
2 | /.idea
3 | /out
4 | /build
5 | *.iml
6 | *.ipr
7 | *.iws
8 | .DS_Store
9 |
--------------------------------------------------------------------------------
/part5/src/main/resources/static/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hello Ktor!
6 |
7 |
8 |
--------------------------------------------------------------------------------
/part6/src/main/resources/static/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hello Ktor!
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/resources/static/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hello Ktor!
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ktor-2.x/src/main/resources/static/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hello Ktor!
6 |
7 |
8 |
--------------------------------------------------------------------------------
/part1/gradle.properties:
--------------------------------------------------------------------------------
1 | ktor_version=1.6.3
2 | kotlin_version=1.5.30
3 | logback_version=1.2.6
4 | kotlin.code.style=official
5 | koin_version=3.1.2
--------------------------------------------------------------------------------
/part1/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/ktor-chuck-norris-sample/HEAD/part1/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/part2/gradle.properties:
--------------------------------------------------------------------------------
1 | ktor_version=1.6.3
2 | kotlin_version=1.5.30
3 | logback_version=1.2.6
4 | kotlin.code.style=official
5 | koin_version=3.1.2
--------------------------------------------------------------------------------
/part2/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/ktor-chuck-norris-sample/HEAD/part2/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/part3/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/ktor-chuck-norris-sample/HEAD/part3/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/part4/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/ktor-chuck-norris-sample/HEAD/part4/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/part5/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/ktor-chuck-norris-sample/HEAD/part5/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/part6/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/ktor-chuck-norris-sample/HEAD/part6/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/ktor-2.x/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/ktor-chuck-norris-sample/HEAD/ktor-2.x/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/ktor-1.6.x/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/ktor-chuck-norris-sample/HEAD/ktor-1.6.x/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/part1/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/dao/Joke.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data.dao
2 |
3 |
4 |
5 | // TODO
--------------------------------------------------------------------------------
/part2/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/dao/Joke.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data.dao
2 |
3 |
4 |
5 | // TODO
--------------------------------------------------------------------------------
/part1/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/mapper/DTOMapper.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain.mapper
2 |
3 |
4 | // TODO
--------------------------------------------------------------------------------
/part2/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/mapper/DTOMapper.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain.mapper
2 |
3 |
4 | // TODO
--------------------------------------------------------------------------------
/part1/src/main/kotlin/com/prof18/ktor/chucknorris/sample/database/DatabaseFactory.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.database
2 |
3 | interface DatabaseFactory {
4 | // TODO
5 | }
--------------------------------------------------------------------------------
/part2/src/main/kotlin/com/prof18/ktor/chucknorris/sample/database/DatabaseFactory.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.database
2 |
3 | interface DatabaseFactory {
4 | // TODO
5 | }
--------------------------------------------------------------------------------
/ktor-2.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/database/DatabaseFactory.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.database
2 |
3 | interface DatabaseFactory {
4 | fun connect()
5 | fun close()
6 | }
--------------------------------------------------------------------------------
/part1/src/main/kotlin/com/prof18/ktor/chucknorris/sample/database/DatabaseFactoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.database
2 |
3 | class DatabaseFactoryImpl : DatabaseFactory {
4 | // TODO
5 | }
6 |
--------------------------------------------------------------------------------
/part2/src/main/kotlin/com/prof18/ktor/chucknorris/sample/database/DatabaseFactoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.database
2 |
3 | class DatabaseFactoryImpl : DatabaseFactory {
4 | // TODO
5 | }
6 |
--------------------------------------------------------------------------------
/part3/src/main/kotlin/com/prof18/ktor/chucknorris/sample/database/DatabaseFactory.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.database
2 |
3 | interface DatabaseFactory {
4 | fun connect()
5 | fun close()
6 | }
--------------------------------------------------------------------------------
/part4/src/main/kotlin/com/prof18/ktor/chucknorris/sample/database/DatabaseFactory.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.database
2 |
3 | interface DatabaseFactory {
4 | fun connect()
5 | fun close()
6 | }
--------------------------------------------------------------------------------
/part5/src/main/kotlin/com/prof18/ktor/chucknorris/sample/database/DatabaseFactory.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.database
2 |
3 | interface DatabaseFactory {
4 | fun connect()
5 | fun close()
6 | }
--------------------------------------------------------------------------------
/part6/src/main/kotlin/com/prof18/ktor/chucknorris/sample/database/DatabaseFactory.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.database
2 |
3 | interface DatabaseFactory {
4 | fun connect()
5 | fun close()
6 | }
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/database/DatabaseFactory.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.database
2 |
3 | interface DatabaseFactory {
4 | fun connect()
5 | fun close()
6 | }
--------------------------------------------------------------------------------
/part1/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/JokeLocalDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data
2 |
3 | interface JokeLocalDataSource {
4 | // TODO
5 | }
--------------------------------------------------------------------------------
/part2/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/JokeLocalDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data
2 |
3 | interface JokeLocalDataSource {
4 | // TODO
5 | }
--------------------------------------------------------------------------------
/part1/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/JokeLocalDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data
2 |
3 | class JokeLocalDataSourceImpl : JokeLocalDataSource {
4 | // TODO
5 | }
--------------------------------------------------------------------------------
/part2/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/JokeLocalDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data
2 |
3 | class JokeLocalDataSourceImpl : JokeLocalDataSource {
4 | // TODO
5 | }
--------------------------------------------------------------------------------
/part3/gradle.properties:
--------------------------------------------------------------------------------
1 | ktor_version=1.6.3
2 | kotlin_version=1.5.30
3 | logback_version=1.2.6
4 | kotlin.code.style=official
5 | exposed_version=0.35.1
6 | hikaricp_version=5.0.0
7 | mysql_connector_version=8.0.25
8 | h2_version=1.4.200
9 | koin_version=3.1.2
--------------------------------------------------------------------------------
/part1/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/part2/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/part3/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/part4/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/part5/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/part6/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/ktor-1.6.x/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/ktor-2.x/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/part1/src/main/resources/application.conf:
--------------------------------------------------------------------------------
1 | ktor {
2 | deployment {
3 | port = 8080
4 | port = ${?PORT}
5 | }
6 | application {
7 | modules = [com.prof18.ktor.chucknorris.sample.ApplicationKt.module]
8 | }
9 |
10 | server {
11 | isProd = false
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/part2/src/main/resources/application.conf:
--------------------------------------------------------------------------------
1 | ktor {
2 | deployment {
3 | port = 8080
4 | port = ${?PORT}
5 | }
6 | application {
7 | modules = [com.prof18.ktor.chucknorris.sample.ApplicationKt.module]
8 | }
9 |
10 | server {
11 | isProd = false
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/part4/gradle.properties:
--------------------------------------------------------------------------------
1 | ktor_version=1.6.3
2 | kotlin_version=1.5.30
3 | logback_version=1.2.6
4 | kotlin.code.style=official
5 | exposed_version=0.35.1
6 | hikaricp_version=5.0.0
7 | mysql_connector_version=8.0.25
8 | h2_version=1.4.200
9 | liquibase_core=4.4.3
10 | koin_version=3.1.2
11 | dbEnv=
--------------------------------------------------------------------------------
/part5/gradle.properties:
--------------------------------------------------------------------------------
1 | ktor_version=1.6.3
2 | kotlin_version=1.5.30
3 | logback_version=1.2.6
4 | kotlin.code.style=official
5 | exposed_version=0.35.1
6 | hikaricp_version=5.0.0
7 | mysql_connector_version=8.0.25
8 | h2_version=1.4.200
9 | liquibase_core=4.4.3
10 | koin_version=3.1.2
11 | dbEnv=
--------------------------------------------------------------------------------
/part6/gradle.properties:
--------------------------------------------------------------------------------
1 | ktor_version=1.6.3
2 | kotlin_version=1.5.30
3 | logback_version=1.2.6
4 | kotlin.code.style=official
5 | exposed_version=0.35.1
6 | hikaricp_version=5.0.0
7 | mysql_connector_version=8.0.25
8 | h2_version=1.4.200
9 | liquibase_core=4.4.3
10 | koin_version=3.1.2
11 | dbEnv=
--------------------------------------------------------------------------------
/ktor-1.6.x/gradle.properties:
--------------------------------------------------------------------------------
1 | ktor_version=1.6.3
2 | kotlin_version=1.5.30
3 | logback_version=1.2.6
4 | kotlin.code.style=official
5 | exposed_version=0.35.1
6 | hikaricp_version=5.0.0
7 | mysql_connector_version=8.0.25
8 | h2_version=1.4.200
9 | liquibase_core=4.4.3
10 | koin_version=3.1.2
11 | dbEnv=
--------------------------------------------------------------------------------
/ktor-2.x/gradle.properties:
--------------------------------------------------------------------------------
1 | ktor_version=2.3.0
2 | kotlin_version=1.8.20
3 | logback_version=1.4.7
4 | kotlin.code.style=official
5 | exposed_version=0.41.1
6 | hikaricp_version=5.0.1
7 | mysql_connector_version=8.0.33
8 | h2_version=2.1.214
9 | liquibase_core=4.21.1
10 | koin_version=3.4.0
11 | dbEnv=
--------------------------------------------------------------------------------
/part3/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/JokeLocalDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 |
5 | interface JokeLocalDataSource {
6 | fun getAllJokes(): List
7 | }
--------------------------------------------------------------------------------
/part4/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/JokeLocalDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 |
5 | interface JokeLocalDataSource {
6 | fun getAllJokes(): List
7 | }
--------------------------------------------------------------------------------
/part5/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/JokeLocalDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 |
5 | interface JokeLocalDataSource {
6 | fun getAllJokes(): List
7 | }
--------------------------------------------------------------------------------
/part6/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/JokeLocalDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 |
5 | interface JokeLocalDataSource {
6 | fun getAllJokes(): List
7 | }
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/JokeLocalDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 |
5 | interface JokeLocalDataSource {
6 | fun getAllJokes(): List
7 | }
--------------------------------------------------------------------------------
/ktor-2.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/JokeLocalDataSource.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 |
5 | interface JokeLocalDataSource {
6 | fun getAllJokes(): List
7 | }
--------------------------------------------------------------------------------
/ktor-2.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/model/JokeDTO.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain.model
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class JokeDTO(
7 | val jokeId: String,
8 | val jokeContent: String
9 | )
--------------------------------------------------------------------------------
/part1/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/model/JokeDTO.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain.model
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class JokeDTO(
7 | val jokeId: String,
8 | val jokeContent: String
9 | )
--------------------------------------------------------------------------------
/part2/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/model/JokeDTO.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain.model
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class JokeDTO(
7 | val jokeId: String,
8 | val jokeContent: String
9 | )
--------------------------------------------------------------------------------
/part3/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/model/JokeDTO.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain.model
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class JokeDTO(
7 | val jokeId: String,
8 | val jokeContent: String
9 | )
--------------------------------------------------------------------------------
/part4/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/model/JokeDTO.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain.model
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class JokeDTO(
7 | val jokeId: String,
8 | val jokeContent: String
9 | )
--------------------------------------------------------------------------------
/part5/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/model/JokeDTO.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain.model
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class JokeDTO(
7 | val jokeId: String,
8 | val jokeContent: String
9 | )
--------------------------------------------------------------------------------
/part6/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/model/JokeDTO.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain.model
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class JokeDTO(
7 | val jokeId: String,
8 | val jokeContent: String
9 | )
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/model/JokeDTO.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain.model
2 |
3 | import kotlinx.serialization.Serializable
4 |
5 | @Serializable
6 | data class JokeDTO(
7 | val jokeId: String,
8 | val jokeContent: String
9 | )
--------------------------------------------------------------------------------
/part1/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepository.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
4 |
5 | interface JokeRepository {
6 | suspend fun getRandomJoke(): JokeDTO
7 | }
--------------------------------------------------------------------------------
/part2/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepository.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
4 |
5 | interface JokeRepository {
6 | suspend fun getRandomJoke(): JokeDTO
7 | }
--------------------------------------------------------------------------------
/part3/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepository.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
4 |
5 | interface JokeRepository {
6 | suspend fun getRandomJoke(): JokeDTO
7 | }
--------------------------------------------------------------------------------
/part4/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepository.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
4 |
5 | interface JokeRepository {
6 | suspend fun getRandomJoke(): JokeDTO
7 | }
--------------------------------------------------------------------------------
/part5/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepository.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
4 |
5 | interface JokeRepository {
6 | suspend fun getRandomJoke(): JokeDTO
7 | }
--------------------------------------------------------------------------------
/part3/src/main/resources/db/migration/changesets/changeset-202102281045.sql:
--------------------------------------------------------------------------------
1 | # From https://github.com/chucknorris-io/chuck-db
2 |
3 | # Joke table
4 | CREATE TABLE IF NOT EXISTS joke
5 | (
6 | created_at TIMESTAMP NOT NULL ,
7 | joke_id VARCHAR(255) PRIMARY KEY,
8 | updated_at TIMESTAMP NOT NULL ,
9 | value TEXT NOT NULL
10 | );
--------------------------------------------------------------------------------
/part4/src/main/resources/db/migration/changesets/changeset-202102281045.sql:
--------------------------------------------------------------------------------
1 | # From https://github.com/chucknorris-io/chuck-db
2 |
3 | # Joke table
4 | CREATE TABLE IF NOT EXISTS joke
5 | (
6 | created_at TIMESTAMP NOT NULL ,
7 | joke_id VARCHAR(255) PRIMARY KEY,
8 | updated_at TIMESTAMP NOT NULL ,
9 | value TEXT NOT NULL
10 | );
--------------------------------------------------------------------------------
/part5/src/main/resources/db/migration/changesets/changeset-202102281045.sql:
--------------------------------------------------------------------------------
1 | # From https://github.com/chucknorris-io/chuck-db
2 |
3 | # Joke table
4 | CREATE TABLE IF NOT EXISTS joke
5 | (
6 | created_at TIMESTAMP NOT NULL ,
7 | joke_id VARCHAR(255) PRIMARY KEY,
8 | updated_at TIMESTAMP NOT NULL ,
9 | value TEXT NOT NULL
10 | );
--------------------------------------------------------------------------------
/part6/src/main/resources/db/migration/changesets/changeset-202102281045.sql:
--------------------------------------------------------------------------------
1 | # From https://github.com/chucknorris-io/chuck-db
2 |
3 | # Joke table
4 | CREATE TABLE IF NOT EXISTS joke
5 | (
6 | created_at TIMESTAMP NOT NULL ,
7 | joke_id VARCHAR(255) PRIMARY KEY,
8 | updated_at TIMESTAMP NOT NULL ,
9 | value TEXT NOT NULL
10 | );
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/resources/db/migration/changesets/changeset-202102281045.sql:
--------------------------------------------------------------------------------
1 | # From https://github.com/chucknorris-io/chuck-db
2 |
3 | # Joke table
4 | CREATE TABLE IF NOT EXISTS joke
5 | (
6 | created_at TIMESTAMP NOT NULL ,
7 | joke_id VARCHAR(255) PRIMARY KEY,
8 | updated_at TIMESTAMP NOT NULL ,
9 | value TEXT NOT NULL
10 | );
--------------------------------------------------------------------------------
/ktor-2.x/src/main/resources/db/migration/changesets/changeset-202102281045.sql:
--------------------------------------------------------------------------------
1 | # From https://github.com/chucknorris-io/chuck-db
2 |
3 | # Joke table
4 | CREATE TABLE IF NOT EXISTS joke
5 | (
6 | created_at TIMESTAMP NOT NULL ,
7 | joke_id VARCHAR(255) PRIMARY KEY,
8 | updated_at TIMESTAMP NOT NULL ,
9 | value TEXT NOT NULL
10 | );
--------------------------------------------------------------------------------
/part3/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Sat May 06 16:16:11 CEST 2023
8 | sdk.dir=/Users/mg/Library/Android/sdk
9 |
--------------------------------------------------------------------------------
/ktor-2.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepository.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
4 |
5 | interface JokeRepository {
6 | suspend fun getRandomJoke(): JokeDTO
7 | suspend fun watch(name: String)
8 | fun getChuckGreeting(name: String): String
9 | }
--------------------------------------------------------------------------------
/part6/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepository.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
4 |
5 | interface JokeRepository {
6 | suspend fun getRandomJoke(): JokeDTO
7 | suspend fun watch(name: String)
8 | fun getChuckGreeting(name: String): String
9 | }
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepository.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
4 |
5 | interface JokeRepository {
6 | suspend fun getRandomJoke(): JokeDTO
7 | suspend fun watch(name: String)
8 | fun getChuckGreeting(name: String): String
9 | }
--------------------------------------------------------------------------------
/part3/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/mapper/DTOMapper.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain.mapper
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
5 |
6 | fun Joke.toDTO(): JokeDTO {
7 | return JokeDTO(
8 | jokeId = this.id.value,
9 | jokeContent = this.value
10 | )
11 | }
--------------------------------------------------------------------------------
/part4/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/mapper/DTOMapper.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain.mapper
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
5 |
6 | fun Joke.toDTO(): JokeDTO {
7 | return JokeDTO(
8 | jokeId = this.id.value,
9 | jokeContent = this.value
10 | )
11 | }
--------------------------------------------------------------------------------
/part5/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/mapper/DTOMapper.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain.mapper
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
5 |
6 | fun Joke.toDTO(): JokeDTO {
7 | return JokeDTO(
8 | jokeId = this.id.value,
9 | jokeContent = this.value
10 | )
11 | }
--------------------------------------------------------------------------------
/part6/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/mapper/DTOMapper.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain.mapper
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
5 |
6 | fun Joke.toDTO(): JokeDTO {
7 | return JokeDTO(
8 | jokeId = this.id.value,
9 | jokeContent = this.value
10 | )
11 | }
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/mapper/DTOMapper.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain.mapper
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
5 |
6 | fun Joke.toDTO(): JokeDTO {
7 | return JokeDTO(
8 | jokeId = this.id.value,
9 | jokeContent = this.value
10 | )
11 | }
--------------------------------------------------------------------------------
/ktor-2.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/mapper/DTOMapper.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain.mapper
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
5 |
6 | fun Joke.toDTO(): JokeDTO {
7 | return JokeDTO(
8 | jokeId = this.id.value,
9 | jokeContent = this.value
10 | )
11 | }
--------------------------------------------------------------------------------
/part4/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Sat May 06 16:17:57 CEST 2023
8 | liquibase.pwd=password
9 | liquibase.url=jdbc\:mysql\://your-url.com
10 | liquibase.user=user
11 | sdk.dir=/Users/mg/Library/Android/sdk
12 |
--------------------------------------------------------------------------------
/part5/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Sat May 06 16:19:35 CEST 2023
8 | liquibase.pwd=password
9 | liquibase.url=jdbc\:mysql\://your-url.com
10 | liquibase.user=user
11 | sdk.dir=/Users/mg/Library/Android/sdk
12 |
--------------------------------------------------------------------------------
/part6/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Sat May 06 16:22:20 CEST 2023
8 | liquibase.pwd=password
9 | liquibase.url=jdbc\:mysql\://your-url.com
10 | liquibase.user=user
11 | sdk.dir=/Users/mg/Library/Android/sdk
12 |
--------------------------------------------------------------------------------
/ktor-1.6.x/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Sat May 06 16:28:17 CEST 2023
8 | liquibase.pwd=password
9 | liquibase.url=jdbc\:mysql\://your-url.com
10 | liquibase.user=user
11 | sdk.dir=/Users/mg/Library/Android/sdk
12 |
--------------------------------------------------------------------------------
/ktor-2.x/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Sat May 06 16:28:17 CEST 2023
8 | liquibase.pwd=password
9 | liquibase.url=jdbc\:mysql\://your-url.com
10 | liquibase.user=user
11 | sdk.dir=/Users/mg/Library/Android/sdk
12 |
--------------------------------------------------------------------------------
/part1/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/part1/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
4 |
5 | class JokeRepositoryImpl : JokeRepository {
6 |
7 | override suspend fun getRandomJoke(): JokeDTO {
8 | // TODO
9 | return JokeDTO(
10 | jokeId = "joke-id",
11 | jokeContent = "joke-content"
12 | )
13 | }
14 | }
--------------------------------------------------------------------------------
/part2/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
4 |
5 | class JokeRepositoryImpl : JokeRepository {
6 |
7 | override suspend fun getRandomJoke(): JokeDTO {
8 | // TODO
9 | return JokeDTO(
10 | jokeId = "joke-id",
11 | jokeContent = "joke-content"
12 | )
13 | }
14 | }
--------------------------------------------------------------------------------
/part3/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/SchemaDefinition.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.JokeTable
4 | import org.jetbrains.exposed.sql.SchemaUtils
5 | import org.jetbrains.exposed.sql.transactions.transaction
6 |
7 | object SchemaDefinition {
8 |
9 | fun createSchema() {
10 | transaction {
11 | SchemaUtils.create(JokeTable)
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/part4/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/SchemaDefinition.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.JokeTable
4 | import org.jetbrains.exposed.sql.SchemaUtils
5 | import org.jetbrains.exposed.sql.transactions.transaction
6 |
7 | object SchemaDefinition {
8 |
9 | fun createSchema() {
10 | transaction {
11 | SchemaUtils.create(JokeTable)
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/part5/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/SchemaDefinition.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.JokeTable
4 | import org.jetbrains.exposed.sql.SchemaUtils
5 | import org.jetbrains.exposed.sql.transactions.transaction
6 |
7 | object SchemaDefinition {
8 |
9 | fun createSchema() {
10 | transaction {
11 | SchemaUtils.create(JokeTable)
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/part6/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/SchemaDefinition.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.JokeTable
4 | import org.jetbrains.exposed.sql.SchemaUtils
5 | import org.jetbrains.exposed.sql.transactions.transaction
6 |
7 | object SchemaDefinition {
8 |
9 | fun createSchema() {
10 | transaction {
11 | SchemaUtils.create(JokeTable)
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/ktor-1.6.x/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/SchemaDefinition.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.JokeTable
4 | import org.jetbrains.exposed.sql.SchemaUtils
5 | import org.jetbrains.exposed.sql.transactions.transaction
6 |
7 | object SchemaDefinition {
8 |
9 | fun createSchema() {
10 | transaction {
11 | SchemaUtils.create(JokeTable)
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/ktor-2.x/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/SchemaDefinition.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.JokeTable
4 | import org.jetbrains.exposed.sql.SchemaUtils
5 | import org.jetbrains.exposed.sql.transactions.transaction
6 |
7 | object SchemaDefinition {
8 |
9 | fun createSchema() {
10 | transaction {
11 | SchemaUtils.create(JokeTable)
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/part3/src/main/resources/application.conf:
--------------------------------------------------------------------------------
1 | ktor {
2 | deployment {
3 | port = 8080
4 | port = ${?PORT}
5 | }
6 | application {
7 | modules = [com.prof18.ktor.chucknorris.sample.ApplicationKt.module]
8 | }
9 |
10 | server {
11 | isProd = false
12 | }
13 |
14 | database {
15 | driverClass = "com.mysql.cj.jdbc.Driver"
16 | url = "jdbc:mysql://localhost:3308/chucknorris?useUnicode=true&characterEncoding=UTF-8"
17 | user = "root"
18 | password = "password"
19 | maxPoolSize = 3
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/part4/src/main/resources/application.conf:
--------------------------------------------------------------------------------
1 | ktor {
2 | deployment {
3 | port = 8080
4 | port = ${?PORT}
5 | }
6 | application {
7 | modules = [com.prof18.ktor.chucknorris.sample.ApplicationKt.module]
8 | }
9 |
10 | server {
11 | isProd = false
12 | }
13 |
14 | database {
15 | driverClass = "com.mysql.cj.jdbc.Driver"
16 | url = "jdbc:mysql://localhost:3308/chucknorris?useUnicode=true&characterEncoding=UTF-8"
17 | user = "root"
18 | password = "password"
19 | maxPoolSize = 3
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/part5/src/main/resources/application.conf:
--------------------------------------------------------------------------------
1 | ktor {
2 | deployment {
3 | port = 8080
4 | port = ${?PORT}
5 | }
6 | application {
7 | modules = [com.prof18.ktor.chucknorris.sample.ApplicationKt.module]
8 | }
9 |
10 | server {
11 | isProd = false
12 | }
13 |
14 | database {
15 | driverClass = "com.mysql.cj.jdbc.Driver"
16 | url = "jdbc:mysql://localhost:3308/chucknorris?useUnicode=true&characterEncoding=UTF-8"
17 | user = "root"
18 | password = "password"
19 | maxPoolSize = 3
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/part6/src/main/resources/application.conf:
--------------------------------------------------------------------------------
1 | ktor {
2 | deployment {
3 | port = 8080
4 | port = ${?PORT}
5 | }
6 | application {
7 | modules = [com.prof18.ktor.chucknorris.sample.ApplicationKt.module]
8 | }
9 |
10 | server {
11 | isProd = false
12 | }
13 |
14 | database {
15 | driverClass = "com.mysql.cj.jdbc.Driver"
16 | url = "jdbc:mysql://localhost:3308/chucknorris?useUnicode=true&characterEncoding=UTF-8"
17 | user = "root"
18 | password = "password"
19 | maxPoolSize = 3
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/resources/application.conf:
--------------------------------------------------------------------------------
1 | ktor {
2 | deployment {
3 | port = 8080
4 | port = ${?PORT}
5 | }
6 | application {
7 | modules = [com.prof18.ktor.chucknorris.sample.ApplicationKt.module]
8 | }
9 |
10 | server {
11 | isProd = false
12 | }
13 |
14 | database {
15 | driverClass = "com.mysql.cj.jdbc.Driver"
16 | url = "jdbc:mysql://localhost:3308/chucknorris?useUnicode=true&characterEncoding=UTF-8"
17 | user = "root"
18 | password = "password"
19 | maxPoolSize = 3
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ktor-2.x/src/main/resources/application.conf:
--------------------------------------------------------------------------------
1 | ktor {
2 | deployment {
3 | port = 8080
4 | port = ${?PORT}
5 | }
6 | application {
7 | modules = [com.prof18.ktor.chucknorris.sample.ApplicationKt.module]
8 | }
9 |
10 | server {
11 | isProd = false
12 | }
13 |
14 | database {
15 | driverClass = "com.mysql.cj.jdbc.Driver"
16 | url = "jdbc:mysql://localhost:3308/chucknorris?useUnicode=true&characterEncoding=UTF-8"
17 | user = "root"
18 | password = "password"
19 | maxPoolSize = 3
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/part2/README.md:
--------------------------------------------------------------------------------
1 | # Ktor Chuck Norris Sample
2 |
3 | A [Ktor](http://ktor.io) (version 1.6.x) sample project that returns Random Chuck Norris jokes.
4 |
5 | This branch contains all the code used in the [How to persist Ktor logs](https://www.marcogomiero.com/posts/2021/ktor-logging-on-disk/) article. For a summary of all the articles, go to the [ktor-1.6.x folder]
6 | (https://github.com/prof18/ktor-chuck-norris-sample/tree/main/ktor-1.6.x)
7 |
8 | The data used for the databases are from the [Chuck Norris IO](https://github.com/chucknorris-io/chuck-db) project.
9 |
--------------------------------------------------------------------------------
/part1/README.md:
--------------------------------------------------------------------------------
1 | # Ktor Chuck Norris Sample
2 |
3 | A [Ktor](http://ktor.io) (version 1.6.x) sample project that returns Random Chuck Norris jokes.
4 |
5 | This project contains all the code used in the [Structuring a Ktor project](https://www.marcogomiero.com/posts/2021/ktor-project-structure/) article. For a summary of all the articles, go to the [ktor-1.6.x folder]
6 | (https://github.com/prof18/ktor-chuck-norris-sample/tree/main/ktor-1.6.x)
7 |
8 | The data used for the databases are from the [Chuck Norris IO](https://github.com/chucknorris-io/chuck-db) project.
9 |
--------------------------------------------------------------------------------
/part1/src/main/kotlin/com/prof18/ktor/chucknorris/sample/di/AppModule.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.di
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepositoryImpl
6 | import org.koin.dsl.module
7 | import org.koin.dsl.single
8 |
9 | val appModule = module {
10 | // Backend Config
11 | single()
12 | single { JokeRepositoryImpl() }
13 | }
14 |
--------------------------------------------------------------------------------
/part2/src/main/kotlin/com/prof18/ktor/chucknorris/sample/di/AppModule.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.di
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepositoryImpl
6 | import org.koin.dsl.module
7 | import org.koin.dsl.single
8 |
9 | val appModule = module {
10 | // Backend Config
11 | single()
12 | single { JokeRepositoryImpl() }
13 | }
14 |
--------------------------------------------------------------------------------
/part6/README.md:
--------------------------------------------------------------------------------
1 | # Ktor Chuck Norris Sample
2 |
3 | A [Ktor](http://ktor.io) (version 1.6.x) sample project that returns Random Chuck Norris jokes.
4 |
5 | This branch contains all the code used in the [How to schedule jobs with Quartz on Ktor](https://www.marcogomiero.com/posts/2022/ktor-jobs-quartz/) article. For a summary of all the articles, go to the [ktor-1.6.x folder]
6 | (https://github.com/prof18/ktor-chuck-norris-sample/tree/main/ktor-1.6.x)
7 |
8 | The data used for the databases are from the [Chuck Norris IO](https://github.com/chucknorris-io/chuck-db) project.
9 |
--------------------------------------------------------------------------------
/part1/src/test/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/fake/JokeRepositoryFake.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.fake
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
5 |
6 | class JokeRepositoryFake: JokeRepository {
7 |
8 | override suspend fun getRandomJoke(): JokeDTO {
9 | return JokeDTO(
10 | jokeId = "fake-id",
11 | jokeContent = "fake-content"
12 | )
13 | }
14 | }
--------------------------------------------------------------------------------
/part2/src/test/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/fake/JokeRepositoryFake.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.fake
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
5 |
6 | class JokeRepositoryFake: JokeRepository {
7 |
8 | override suspend fun getRandomJoke(): JokeDTO {
9 | return JokeDTO(
10 | jokeId = "fake-id",
11 | jokeContent = "fake-content"
12 | )
13 | }
14 | }
--------------------------------------------------------------------------------
/part5/README.md:
--------------------------------------------------------------------------------
1 | # Ktor Chuck Norris Sample
2 |
3 | A [Ktor](http://ktor.io) (version 1.6.x) sample project that returns Random Chuck Norris jokes.
4 |
5 | This branch contains all the code used in the [Generate API documentation from Swagger on Ktor](https://www.marcogomiero.com/posts/2022/ktor-setup-documentation/) article. For a summary of all the articles, go to the [ktor-1.6.x folder]
6 | (https://github.com/prof18/ktor-chuck-norris-sample/tree/main/ktor-1.6.x)
7 |
8 | The data used for the databases are from the [Chuck Norris IO](https://github.com/chucknorris-io/chuck-db) project.
9 |
--------------------------------------------------------------------------------
/part3/README.md:
--------------------------------------------------------------------------------
1 | # Ktor Chuck Norris Sample
2 |
3 | A [Ktor](http://ktor.io) (version 1.6.x) sample project that returns Random Chuck Norris jokes.
4 |
5 | This branch contains all the code used in the [How to use an in-memory database for testing on Ktor](https://www.marcogomiero.com/posts/2021/ktor-in-memory-db-testing/) article. For a summary of all the articles, go to the [ktor-1.6.x folder]
6 | (https://github.com/prof18/ktor-chuck-norris-sample/tree/main/ktor-1.6.x)
7 |
8 | The data used for the databases are from the [Chuck Norris IO](https://github.com/chucknorris-io/chuck-db) project.
9 |
--------------------------------------------------------------------------------
/part3/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/JokeLocalDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.JokeTable
5 | import org.jetbrains.exposed.sql.selectAll
6 |
7 | class JokeLocalDataSourceImpl : JokeLocalDataSource {
8 |
9 | override fun getAllJokes(): List {
10 | val query = JokeTable.selectAll()
11 | return Joke.wrapRows(query).toList()
12 | }
13 | }
--------------------------------------------------------------------------------
/part4/README.md:
--------------------------------------------------------------------------------
1 | # Ktor Chuck Norris Sample
2 |
3 | A [Ktor](http://ktor.io) (version 1.6.x) sample project that returns Random Chuck Norris jokes.
4 |
5 | This branch contains all the code used in the [How to handle database migrations with Liquibase on Ktor](https://www.marcogomiero.com/posts/2022/ktor-migration-liquibase/) article. For a summary of all the articles, go to the [ktor-1.6.x folder]
6 | (https://github.com/prof18/ktor-chuck-norris-sample/tree/main/ktor-1.6.x)
7 |
8 | The data used for the databases are from the [Chuck Norris IO](https://github.com/chucknorris-io/chuck-db) project.
9 |
--------------------------------------------------------------------------------
/part4/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/JokeLocalDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.JokeTable
5 | import org.jetbrains.exposed.sql.selectAll
6 |
7 | class JokeLocalDataSourceImpl : JokeLocalDataSource {
8 |
9 | override fun getAllJokes(): List {
10 | val query = JokeTable.selectAll()
11 | return Joke.wrapRows(query).toList()
12 | }
13 | }
--------------------------------------------------------------------------------
/part5/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/JokeLocalDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.JokeTable
5 | import org.jetbrains.exposed.sql.selectAll
6 |
7 | class JokeLocalDataSourceImpl : JokeLocalDataSource {
8 |
9 | override fun getAllJokes(): List {
10 | val query = JokeTable.selectAll()
11 | return Joke.wrapRows(query).toList()
12 | }
13 | }
--------------------------------------------------------------------------------
/part6/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/JokeLocalDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.JokeTable
5 | import org.jetbrains.exposed.sql.selectAll
6 |
7 | class JokeLocalDataSourceImpl : JokeLocalDataSource {
8 |
9 | override fun getAllJokes(): List {
10 | val query = JokeTable.selectAll()
11 | return Joke.wrapRows(query).toList()
12 | }
13 | }
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/JokeLocalDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.JokeTable
5 | import org.jetbrains.exposed.sql.selectAll
6 |
7 | class JokeLocalDataSourceImpl : JokeLocalDataSource {
8 |
9 | override fun getAllJokes(): List {
10 | val query = JokeTable.selectAll()
11 | return Joke.wrapRows(query).toList()
12 | }
13 | }
--------------------------------------------------------------------------------
/ktor-2.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/JokeLocalDataSourceImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.JokeTable
5 | import org.jetbrains.exposed.sql.selectAll
6 |
7 | class JokeLocalDataSourceImpl : JokeLocalDataSource {
8 |
9 | override fun getAllJokes(): List {
10 | val query = JokeTable.selectAll()
11 | return Joke.wrapRows(query).toList()
12 | }
13 | }
--------------------------------------------------------------------------------
/part2/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/ktor-2.x/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/part3/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/part4/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/part5/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/part6/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/ktor-1.6.x/src/test/resources/logback-test.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/ktor-2.x/src/main/resources/doc/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Api Doc
6 |
7 |
8 |
9 |
10 |
11 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/part5/src/main/resources/doc/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Api Doc
6 |
7 |
8 |
9 |
10 |
11 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/part6/src/main/resources/doc/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Api Doc
6 |
7 |
8 |
9 |
10 |
11 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/resources/doc/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Api Doc
6 |
7 |
8 |
9 |
10 |
11 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/part1/src/main/kotlin/com/prof18/ktor/chucknorris/sample/config/AppConfig.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.config
2 |
3 | import io.ktor.application.*
4 | import org.koin.ktor.ext.inject
5 |
6 | class AppConfig {
7 | lateinit var serverConfig: ServerConfig
8 | // Place here other configurations
9 | }
10 |
11 | fun Application.setupConfig() {
12 | val appConfig by inject()
13 |
14 | // Server
15 | val serverObject = environment.config.config("ktor.server")
16 | val isProd = serverObject.property("isProd").getString().toBoolean()
17 | appConfig.serverConfig = ServerConfig(isProd)
18 |
19 | }
20 |
21 | data class ServerConfig(
22 | val isProd: Boolean
23 | )
24 |
--------------------------------------------------------------------------------
/part2/src/main/kotlin/com/prof18/ktor/chucknorris/sample/config/AppConfig.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.config
2 |
3 | import io.ktor.application.*
4 | import org.koin.ktor.ext.inject
5 |
6 | class AppConfig {
7 | lateinit var serverConfig: ServerConfig
8 | // Place here other configurations
9 | }
10 |
11 | fun Application.setupConfig() {
12 | val appConfig by inject()
13 |
14 | // Server
15 | val serverObject = environment.config.config("ktor.server")
16 | val isProd = serverObject.property("isProd").getString().toBoolean()
17 | appConfig.serverConfig = ServerConfig(isProd)
18 |
19 | }
20 |
21 | data class ServerConfig(
22 | val isProd: Boolean
23 | )
24 |
--------------------------------------------------------------------------------
/ktor-2.x/src/main/resources/swagger/swagger.yml:
--------------------------------------------------------------------------------
1 | swagger: "2.0"
2 | info:
3 | title: Ktor Chuck Norris Sample
4 | description: A ktor sample project that returns Random Chuck Norris jokes
5 | version: 0.0.1
6 | tags:
7 | - name: Jokes
8 | description: Jokes Apis
9 |
10 | paths:
11 | /joke/random:
12 | get:
13 | summary: Get a random Chuck Norris Joke
14 | responses:
15 | "200":
16 | description: "JokeDTO"
17 | schema:
18 | $ref: "#/definitions/JokeDTO"
19 |
20 | definitions:
21 | JokeDTO:
22 | type: object
23 | properties:
24 | jokeId:
25 | type: string
26 | jokeContent:
27 | type: string
28 | required:
29 | - jokeId
30 | - jokeContent
31 |
--------------------------------------------------------------------------------
/part5/src/main/resources/swagger/swagger.yml:
--------------------------------------------------------------------------------
1 | swagger: "2.0"
2 | info:
3 | title: Ktor Chuck Norris Sample
4 | description: A ktor sample project that returns Random Chuck Norris jokes
5 | version: 0.0.1
6 | tags:
7 | - name: Jokes
8 | description: Jokes Apis
9 |
10 | paths:
11 | /joke/random:
12 | get:
13 | summary: Get a random Chuck Norris Joke
14 | responses:
15 | "200":
16 | description: "JokeDTO"
17 | schema:
18 | $ref: "#/definitions/JokeDTO"
19 |
20 | definitions:
21 | JokeDTO:
22 | type: object
23 | properties:
24 | jokeId:
25 | type: string
26 | jokeContent:
27 | type: string
28 | required:
29 | - jokeId
30 | - jokeContent
31 |
--------------------------------------------------------------------------------
/part6/src/main/resources/swagger/swagger.yml:
--------------------------------------------------------------------------------
1 | swagger: "2.0"
2 | info:
3 | title: Ktor Chuck Norris Sample
4 | description: A ktor sample project that returns Random Chuck Norris jokes
5 | version: 0.0.1
6 | tags:
7 | - name: Jokes
8 | description: Jokes Apis
9 |
10 | paths:
11 | /joke/random:
12 | get:
13 | summary: Get a random Chuck Norris Joke
14 | responses:
15 | "200":
16 | description: "JokeDTO"
17 | schema:
18 | $ref: "#/definitions/JokeDTO"
19 |
20 | definitions:
21 | JokeDTO:
22 | type: object
23 | properties:
24 | jokeId:
25 | type: string
26 | jokeContent:
27 | type: string
28 | required:
29 | - jokeId
30 | - jokeContent
31 |
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/resources/swagger/swagger.yml:
--------------------------------------------------------------------------------
1 | swagger: "2.0"
2 | info:
3 | title: Ktor Chuck Norris Sample
4 | description: A ktor sample project that returns Random Chuck Norris jokes
5 | version: 0.0.1
6 | tags:
7 | - name: Jokes
8 | description: Jokes Apis
9 |
10 | paths:
11 | /joke/random:
12 | get:
13 | summary: Get a random Chuck Norris Joke
14 | responses:
15 | "200":
16 | description: "JokeDTO"
17 | schema:
18 | $ref: "#/definitions/JokeDTO"
19 |
20 | definitions:
21 | JokeDTO:
22 | type: object
23 | properties:
24 | jokeId:
25 | type: string
26 | jokeContent:
27 | type: string
28 | required:
29 | - jokeId
30 | - jokeContent
31 |
--------------------------------------------------------------------------------
/part5/src/main/resources/doc/swagger.yml:
--------------------------------------------------------------------------------
1 | swagger: "2.0"
2 | info:
3 | title: Ktor Chuck Norris Sample
4 | description: A ktor sample project that returns Random Chuck Norris jokes
5 | version: 0.0.1
6 | tags:
7 | - name: Jokes
8 | description: Jokes Apis
9 |
10 | paths:
11 | /joke/random:
12 | get:
13 | summary: Get a random Chuck Norris Joke
14 | description: Optional extended description in CommonMark or HTML.
15 | responses:
16 | "200":
17 | description: "JokeDTO"
18 | schema:
19 | $ref: "#/definitions/JokeDTO"
20 |
21 | definitions:
22 | JokeDTO:
23 | type: object
24 | properties:
25 | jokeId:
26 | type: string
27 | jokeContent:
28 | type: string
29 | required:
30 | - jokeId
31 | - jokeContent
32 |
--------------------------------------------------------------------------------
/part6/src/main/resources/doc/swagger.yml:
--------------------------------------------------------------------------------
1 | swagger: "2.0"
2 | info:
3 | title: Ktor Chuck Norris Sample
4 | description: A ktor sample project that returns Random Chuck Norris jokes
5 | version: 0.0.1
6 | tags:
7 | - name: Jokes
8 | description: Jokes Apis
9 |
10 | paths:
11 | /joke/random:
12 | get:
13 | summary: Get a random Chuck Norris Joke
14 | description: Optional extended description in CommonMark or HTML.
15 | responses:
16 | "200":
17 | description: "JokeDTO"
18 | schema:
19 | $ref: "#/definitions/JokeDTO"
20 |
21 | definitions:
22 | JokeDTO:
23 | type: object
24 | properties:
25 | jokeId:
26 | type: string
27 | jokeContent:
28 | type: string
29 | required:
30 | - jokeId
31 | - jokeContent
32 |
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/resources/doc/swagger.yml:
--------------------------------------------------------------------------------
1 | swagger: "2.0"
2 | info:
3 | title: Ktor Chuck Norris Sample
4 | description: A ktor sample project that returns Random Chuck Norris jokes
5 | version: 0.0.1
6 | tags:
7 | - name: Jokes
8 | description: Jokes Apis
9 |
10 | paths:
11 | /joke/random:
12 | get:
13 | summary: Get a random Chuck Norris Joke
14 | description: Optional extended description in CommonMark or HTML.
15 | responses:
16 | "200":
17 | description: "JokeDTO"
18 | schema:
19 | $ref: "#/definitions/JokeDTO"
20 |
21 | definitions:
22 | JokeDTO:
23 | type: object
24 | properties:
25 | jokeId:
26 | type: string
27 | jokeContent:
28 | type: string
29 | required:
30 | - jokeId
31 | - jokeContent
32 |
--------------------------------------------------------------------------------
/ktor-2.x/src/main/resources/doc/swagger.yml:
--------------------------------------------------------------------------------
1 | swagger: "2.0"
2 | info:
3 | title: Ktor Chuck Norris Sample
4 | description: A ktor sample project that returns Random Chuck Norris jokes
5 | version: 0.0.1
6 | tags:
7 | - name: Jokes
8 | description: Jokes Apis
9 |
10 | paths:
11 | /joke/random:
12 | get:
13 | summary: Get a random Chuck Norris Joke
14 | description: Optional extended description in CommonMark or HTML.
15 | responses:
16 | "200":
17 | description: "JokeDTO"
18 | schema:
19 | $ref: "#/definitions/JokeDTO"
20 |
21 | definitions:
22 | JokeDTO:
23 | type: object
24 | properties:
25 | jokeId:
26 | type: string
27 | jokeContent:
28 | type: string
29 | required:
30 | - jokeId
31 | - jokeContent
32 |
--------------------------------------------------------------------------------
/part1/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/resource/JokeResource.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.resource
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import io.ktor.application.*
5 | import io.ktor.locations.*
6 | import io.ktor.response.*
7 | import io.ktor.routing.*
8 | import org.koin.ktor.ext.inject
9 |
10 | @KtorExperimentalLocationsAPI
11 | @Location("joke")
12 | class JokeEndpoint {
13 |
14 | @Location("/random")
15 | class Random(val parent: JokeEndpoint)
16 | }
17 |
18 | @KtorExperimentalLocationsAPI
19 | fun Route.jokeEndpoint() {
20 |
21 | val jokeRepository by inject()
22 |
23 | get {
24 | call.respond(jokeRepository.getRandomJoke())
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/part2/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/resource/JokeResource.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.resource
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import io.ktor.application.*
5 | import io.ktor.locations.*
6 | import io.ktor.response.*
7 | import io.ktor.routing.*
8 | import org.koin.ktor.ext.inject
9 |
10 | @KtorExperimentalLocationsAPI
11 | @Location("joke")
12 | class JokeEndpoint {
13 |
14 | @Location("/random")
15 | class Random(val parent: JokeEndpoint)
16 | }
17 |
18 | @KtorExperimentalLocationsAPI
19 | fun Route.jokeEndpoint() {
20 |
21 | val jokeRepository by inject()
22 |
23 | get {
24 | call.respond(jokeRepository.getRandomJoke())
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/part3/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/resource/JokeResource.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.resource
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import io.ktor.application.*
5 | import io.ktor.locations.*
6 | import io.ktor.response.*
7 | import io.ktor.routing.*
8 | import org.koin.ktor.ext.inject
9 |
10 | @KtorExperimentalLocationsAPI
11 | @Location("joke")
12 | class JokeEndpoint {
13 |
14 | @Location("/random")
15 | class Random(val parent: JokeEndpoint)
16 | }
17 |
18 | @KtorExperimentalLocationsAPI
19 | fun Route.jokeEndpoint() {
20 |
21 | val jokeRepository by inject()
22 |
23 | get {
24 | call.respond(jokeRepository.getRandomJoke())
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/part4/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/resource/JokeResource.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.resource
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import io.ktor.application.*
5 | import io.ktor.locations.*
6 | import io.ktor.response.*
7 | import io.ktor.routing.*
8 | import org.koin.ktor.ext.inject
9 |
10 | @KtorExperimentalLocationsAPI
11 | @Location("joke")
12 | class JokeEndpoint {
13 |
14 | @Location("/random")
15 | class Random(val parent: JokeEndpoint)
16 | }
17 |
18 | @KtorExperimentalLocationsAPI
19 | fun Route.jokeEndpoint() {
20 |
21 | val jokeRepository by inject()
22 |
23 | get {
24 | call.respond(jokeRepository.getRandomJoke())
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/part5/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/resource/JokeResource.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.resource
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import io.ktor.application.*
5 | import io.ktor.locations.*
6 | import io.ktor.response.*
7 | import io.ktor.routing.*
8 | import org.koin.ktor.ext.inject
9 |
10 | @KtorExperimentalLocationsAPI
11 | @Location("joke")
12 | class JokeEndpoint {
13 |
14 | @Location("/random")
15 | class Random(val parent: JokeEndpoint)
16 | }
17 |
18 | @KtorExperimentalLocationsAPI
19 | fun Route.jokeEndpoint() {
20 |
21 | val jokeRepository by inject()
22 |
23 | get {
24 | call.respond(jokeRepository.getRandomJoke())
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/part3/src/main/resources/db/migration/migrations.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | Jokes Table
9 |
10 |
11 |
12 |
13 | Jokes Data
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/part4/src/main/resources/db/migration/migrations.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | Jokes Table
9 |
10 |
11 |
12 |
13 | Jokes Data
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/part5/src/main/resources/db/migration/migrations.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | Jokes Table
9 |
10 |
11 |
12 |
13 | Jokes Data
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/ktor-2.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/jobs/JobFactory.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.jobs
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import org.quartz.Job
5 | import org.quartz.Scheduler
6 | import org.quartz.spi.JobFactory
7 | import org.quartz.spi.TriggerFiredBundle
8 | import kotlin.reflect.jvm.jvmName
9 |
10 | class JobFactory(
11 | private val jokeRepository: JokeRepository
12 | ): JobFactory {
13 |
14 | override fun newJob(bundle: TriggerFiredBundle?, scheduler: Scheduler?): Job {
15 | if (bundle != null) {
16 | val jobClass = bundle.jobDetail.jobClass
17 | if (jobClass.name == RandomJokeJob::class.jvmName) {
18 | return RandomJokeJob(jokeRepository)
19 | }
20 | }
21 | throw NotImplementedError("Job Factory error")
22 | }
23 | }
--------------------------------------------------------------------------------
/part6/src/main/kotlin/com/prof18/ktor/chucknorris/sample/jobs/JobFactory.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.jobs
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import org.quartz.Job
5 | import org.quartz.Scheduler
6 | import org.quartz.spi.JobFactory
7 | import org.quartz.spi.TriggerFiredBundle
8 | import kotlin.reflect.jvm.jvmName
9 |
10 | class JobFactory(
11 | private val jokeRepository: JokeRepository
12 | ): JobFactory {
13 |
14 | override fun newJob(bundle: TriggerFiredBundle?, scheduler: Scheduler?): Job {
15 | if (bundle != null) {
16 | val jobClass = bundle.jobDetail.jobClass
17 | if (jobClass.name == RandomJokeJob::class.jvmName) {
18 | return RandomJokeJob(jokeRepository)
19 | }
20 | }
21 | throw NotImplementedError("Job Factory error")
22 | }
23 | }
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/jobs/JobFactory.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.jobs
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import org.quartz.Job
5 | import org.quartz.Scheduler
6 | import org.quartz.spi.JobFactory
7 | import org.quartz.spi.TriggerFiredBundle
8 | import kotlin.reflect.jvm.jvmName
9 |
10 | class JobFactory(
11 | private val jokeRepository: JokeRepository
12 | ): JobFactory {
13 |
14 | override fun newJob(bundle: TriggerFiredBundle?, scheduler: Scheduler?): Job {
15 | if (bundle != null) {
16 | val jobClass = bundle.jobDetail.jobClass
17 | if (jobClass.name == RandomJokeJob::class.jvmName) {
18 | return RandomJokeJob(jokeRepository)
19 | }
20 | }
21 | throw NotImplementedError("Job Factory error")
22 | }
23 | }
--------------------------------------------------------------------------------
/part3/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSource
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.mapper.toDTO
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
6 | import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
7 |
8 | class JokeRepositoryImpl(
9 | private val jokeLocalDataSource: JokeLocalDataSource
10 | ) : JokeRepository {
11 |
12 | override suspend fun getRandomJoke(): JokeDTO {
13 | val jokeDTO = newSuspendedTransaction {
14 | val allJokes = jokeLocalDataSource.getAllJokes()
15 | val randomJoke = allJokes.random()
16 | return@newSuspendedTransaction randomJoke.toDTO()
17 | }
18 | return jokeDTO
19 | }
20 | }
--------------------------------------------------------------------------------
/part4/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSource
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.mapper.toDTO
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
6 | import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
7 |
8 | class JokeRepositoryImpl(
9 | private val jokeLocalDataSource: JokeLocalDataSource
10 | ) : JokeRepository {
11 |
12 | override suspend fun getRandomJoke(): JokeDTO {
13 | val jokeDTO = newSuspendedTransaction {
14 | val allJokes = jokeLocalDataSource.getAllJokes()
15 | val randomJoke = allJokes.random()
16 | return@newSuspendedTransaction randomJoke.toDTO()
17 | }
18 | return jokeDTO
19 | }
20 | }
--------------------------------------------------------------------------------
/part5/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSource
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.mapper.toDTO
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
6 | import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
7 |
8 | class JokeRepositoryImpl(
9 | private val jokeLocalDataSource: JokeLocalDataSource
10 | ) : JokeRepository {
11 |
12 | override suspend fun getRandomJoke(): JokeDTO {
13 | val jokeDTO = newSuspendedTransaction {
14 | val allJokes = jokeLocalDataSource.getAllJokes()
15 | val randomJoke = allJokes.random()
16 | return@newSuspendedTransaction randomJoke.toDTO()
17 | }
18 | return jokeDTO
19 | }
20 | }
--------------------------------------------------------------------------------
/part5/src/main/kotlin/com/prof18/ktor/chucknorris/sample/di/AppModule.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.di
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
5 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactoryImpl
6 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSource
7 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSourceImpl
8 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
9 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepositoryImpl
10 | import org.koin.dsl.module
11 | import org.koin.dsl.single
12 |
13 | val appModule = module {
14 | // Backend Config
15 | single()
16 | single { DatabaseFactoryImpl(get()) }
17 | single { JokeLocalDataSourceImpl() }
18 | single { JokeRepositoryImpl(get()) }
19 | }
20 |
--------------------------------------------------------------------------------
/part3/src/main/kotlin/com/prof18/ktor/chucknorris/sample/di/AppModule.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.di
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
5 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactoryImpl
6 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSource
7 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSourceImpl
8 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
9 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepositoryImpl
10 | import org.koin.dsl.module
11 | import org.koin.dsl.single
12 |
13 | val appModule = module {
14 | // Backend Config
15 | single()
16 | single { DatabaseFactoryImpl(get()) }
17 | single { JokeLocalDataSourceImpl() }
18 | single { JokeRepositoryImpl(get()) }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/part4/src/main/kotlin/com/prof18/ktor/chucknorris/sample/di/AppModule.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.di
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
5 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactoryImpl
6 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSource
7 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSourceImpl
8 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
9 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepositoryImpl
10 | import org.koin.dsl.module
11 | import org.koin.dsl.single
12 |
13 | val appModule = module {
14 | // Backend Config
15 | single()
16 | single { DatabaseFactoryImpl(get()) }
17 | single { JokeLocalDataSourceImpl() }
18 | single { JokeRepositoryImpl(get()) }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/part3/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/dao/Joke.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data.dao
2 |
3 | import org.jetbrains.exposed.dao.Entity
4 | import org.jetbrains.exposed.dao.EntityClass
5 | import org.jetbrains.exposed.dao.id.EntityID
6 | import org.jetbrains.exposed.dao.id.IdTable
7 | import org.jetbrains.exposed.sql.Column
8 | import org.jetbrains.exposed.sql.javatime.datetime
9 |
10 | object JokeTable: IdTable(name = "joke") {
11 | val createdAt = datetime("created_at")
12 | val updatedAt = datetime("updated_at")
13 | val value = text("value")
14 |
15 | override val id: Column> = varchar("joke_id", 255).entityId()
16 | override val primaryKey: PrimaryKey = PrimaryKey(id)
17 |
18 | }
19 |
20 | class Joke(id: EntityID): Entity(id) {
21 | companion object: EntityClass(JokeTable)
22 |
23 | var createdAt by JokeTable.createdAt
24 | var updatedAt by JokeTable.updatedAt
25 | var value by JokeTable.value
26 | }
--------------------------------------------------------------------------------
/part4/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/dao/Joke.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data.dao
2 |
3 | import org.jetbrains.exposed.dao.Entity
4 | import org.jetbrains.exposed.dao.EntityClass
5 | import org.jetbrains.exposed.dao.id.EntityID
6 | import org.jetbrains.exposed.dao.id.IdTable
7 | import org.jetbrains.exposed.sql.Column
8 | import org.jetbrains.exposed.sql.javatime.datetime
9 |
10 | object JokeTable: IdTable(name = "joke") {
11 | val createdAt = datetime("created_at")
12 | val updatedAt = datetime("updated_at")
13 | val value = text("value")
14 |
15 | override val id: Column> = varchar("joke_id", 255).entityId()
16 | override val primaryKey: PrimaryKey = PrimaryKey(id)
17 |
18 | }
19 |
20 | class Joke(id: EntityID): Entity(id) {
21 | companion object: EntityClass(JokeTable)
22 |
23 | var createdAt by JokeTable.createdAt
24 | var updatedAt by JokeTable.updatedAt
25 | var value by JokeTable.value
26 | }
--------------------------------------------------------------------------------
/part5/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/dao/Joke.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data.dao
2 |
3 | import org.jetbrains.exposed.dao.Entity
4 | import org.jetbrains.exposed.dao.EntityClass
5 | import org.jetbrains.exposed.dao.id.EntityID
6 | import org.jetbrains.exposed.dao.id.IdTable
7 | import org.jetbrains.exposed.sql.Column
8 | import org.jetbrains.exposed.sql.javatime.datetime
9 |
10 | object JokeTable: IdTable(name = "joke") {
11 | val createdAt = datetime("created_at")
12 | val updatedAt = datetime("updated_at")
13 | val value = text("value")
14 |
15 | override val id: Column> = varchar("joke_id", 255).entityId()
16 | override val primaryKey: PrimaryKey = PrimaryKey(id)
17 |
18 | }
19 |
20 | class Joke(id: EntityID): Entity(id) {
21 | companion object: EntityClass(JokeTable)
22 |
23 | var createdAt by JokeTable.createdAt
24 | var updatedAt by JokeTable.updatedAt
25 | var value by JokeTable.value
26 | }
--------------------------------------------------------------------------------
/part6/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/dao/Joke.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data.dao
2 |
3 | import org.jetbrains.exposed.dao.Entity
4 | import org.jetbrains.exposed.dao.EntityClass
5 | import org.jetbrains.exposed.dao.id.EntityID
6 | import org.jetbrains.exposed.dao.id.IdTable
7 | import org.jetbrains.exposed.sql.Column
8 | import org.jetbrains.exposed.sql.javatime.datetime
9 |
10 | object JokeTable: IdTable(name = "joke") {
11 | val createdAt = datetime("created_at")
12 | val updatedAt = datetime("updated_at")
13 | val value = text("value")
14 |
15 | override val id: Column> = varchar("joke_id", 255).entityId()
16 | override val primaryKey: PrimaryKey = PrimaryKey(id)
17 |
18 | }
19 |
20 | class Joke(id: EntityID): Entity(id) {
21 | companion object: EntityClass(JokeTable)
22 |
23 | var createdAt by JokeTable.createdAt
24 | var updatedAt by JokeTable.updatedAt
25 | var value by JokeTable.value
26 | }
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/dao/Joke.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data.dao
2 |
3 | import org.jetbrains.exposed.dao.Entity
4 | import org.jetbrains.exposed.dao.EntityClass
5 | import org.jetbrains.exposed.dao.id.EntityID
6 | import org.jetbrains.exposed.dao.id.IdTable
7 | import org.jetbrains.exposed.sql.Column
8 | import org.jetbrains.exposed.sql.javatime.datetime
9 |
10 | object JokeTable: IdTable(name = "joke") {
11 | val createdAt = datetime("created_at")
12 | val updatedAt = datetime("updated_at")
13 | val value = text("value")
14 |
15 | override val id: Column> = varchar("joke_id", 255).entityId()
16 | override val primaryKey: PrimaryKey = PrimaryKey(id)
17 |
18 | }
19 |
20 | class Joke(id: EntityID): Entity(id) {
21 | companion object: EntityClass(JokeTable)
22 |
23 | var createdAt by JokeTable.createdAt
24 | var updatedAt by JokeTable.updatedAt
25 | var value by JokeTable.value
26 | }
--------------------------------------------------------------------------------
/ktor-2.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/data/dao/Joke.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.data.dao
2 |
3 | import org.jetbrains.exposed.dao.Entity
4 | import org.jetbrains.exposed.dao.EntityClass
5 | import org.jetbrains.exposed.dao.id.EntityID
6 | import org.jetbrains.exposed.dao.id.IdTable
7 | import org.jetbrains.exposed.sql.Column
8 | import org.jetbrains.exposed.sql.javatime.datetime
9 |
10 | object JokeTable: IdTable(name = "joke") {
11 | val createdAt = datetime("created_at")
12 | val updatedAt = datetime("updated_at")
13 | val value = text("value")
14 |
15 | override val id: Column> = varchar("joke_id", 255).entityId()
16 | override val primaryKey: PrimaryKey = PrimaryKey(id)
17 |
18 | }
19 |
20 | class Joke(id: EntityID): Entity(id) {
21 | companion object: EntityClass(JokeTable)
22 |
23 | var createdAt by JokeTable.createdAt
24 | var updatedAt by JokeTable.updatedAt
25 | var value by JokeTable.value
26 | }
--------------------------------------------------------------------------------
/part6/src/main/resources/db/migration/migrations.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | Jokes Table
9 |
10 |
11 |
12 |
13 | Jokes Data
14 |
15 |
16 |
17 |
18 | Tables for Quartz
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/resources/db/migration/migrations.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | Jokes Table
9 |
10 |
11 |
12 |
13 | Jokes Data
14 |
15 |
16 |
17 |
18 | Tables for Quartz
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/ktor-2.x/src/main/resources/db/migration/migrations.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 | Jokes Table
9 |
10 |
11 |
12 |
13 | Jokes Data
14 |
15 |
16 |
17 |
18 | Tables for Quartz
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/ktor-2.x/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/DatabaseFactoryForUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
4 | import com.zaxxer.hikari.HikariConfig
5 | import com.zaxxer.hikari.HikariDataSource
6 | import org.jetbrains.exposed.sql.Database
7 |
8 | class DatabaseFactoryForUnitTest: DatabaseFactory {
9 |
10 | lateinit var source: HikariDataSource
11 |
12 | override fun close() {
13 | source.close()
14 | }
15 |
16 | override fun connect() {
17 | Database.connect(hikari())
18 | SchemaDefinition.createSchema()
19 | }
20 |
21 | private fun hikari(): HikariDataSource {
22 | val config = HikariConfig()
23 | config.driverClassName = "org.h2.Driver"
24 | config.jdbcUrl = "jdbc:h2:mem:;DATABASE_TO_UPPER=false;MODE=MYSQL"
25 | config.maximumPoolSize = 2
26 | config.isAutoCommit = true
27 | config.validate()
28 | source = HikariDataSource(config)
29 | return source
30 | }
31 | }
--------------------------------------------------------------------------------
/part1/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/TestServer.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.module
5 | import io.ktor.config.*
6 | import io.ktor.locations.*
7 | import io.ktor.server.testing.*
8 | import org.koin.core.module.Module
9 | import org.koin.dsl.module
10 | import org.koin.dsl.single
11 |
12 | fun MapApplicationConfig.createConfigForTesting() {
13 | // Server config
14 | put("ktor.server.isProd", "false")
15 | }
16 |
17 |
18 | @KtorExperimentalLocationsAPI
19 | fun withTestServer(koinModules: List = listOf(appTestModule), block: TestApplicationEngine.() -> Unit) {
20 | withTestApplication(
21 | {
22 | (environment.config as MapApplicationConfig).apply {
23 | createConfigForTesting()
24 | }
25 | module(testing = true, koinModules = koinModules)
26 | }, block
27 | )
28 | }
29 |
30 | val appTestModule = module {
31 | single()
32 | }
33 |
34 |
35 |
--------------------------------------------------------------------------------
/part2/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/TestServer.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.module
5 | import io.ktor.config.*
6 | import io.ktor.locations.*
7 | import io.ktor.server.testing.*
8 | import org.koin.core.module.Module
9 | import org.koin.dsl.module
10 | import org.koin.dsl.single
11 |
12 | fun MapApplicationConfig.createConfigForTesting() {
13 | // Server config
14 | put("ktor.server.isProd", "false")
15 | }
16 |
17 |
18 | @KtorExperimentalLocationsAPI
19 | fun withTestServer(koinModules: List = listOf(appTestModule), block: TestApplicationEngine.() -> Unit) {
20 | withTestApplication(
21 | {
22 | (environment.config as MapApplicationConfig).apply {
23 | createConfigForTesting()
24 | }
25 | module(testing = true, koinModules = koinModules)
26 | }, block
27 | )
28 | }
29 |
30 | val appTestModule = module {
31 | single()
32 | }
33 |
34 |
35 |
--------------------------------------------------------------------------------
/part3/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/DatabaseFactoryForUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
4 | import com.zaxxer.hikari.HikariConfig
5 | import com.zaxxer.hikari.HikariDataSource
6 | import org.jetbrains.exposed.sql.Database
7 |
8 | class DatabaseFactoryForUnitTest: DatabaseFactory {
9 |
10 | lateinit var source: HikariDataSource
11 |
12 | override fun close() {
13 | source.close()
14 | }
15 |
16 | override fun connect() {
17 | Database.connect(hikari())
18 | SchemaDefinition.createSchema()
19 | }
20 |
21 | private fun hikari(): HikariDataSource {
22 | val config = HikariConfig()
23 | config.driverClassName = "org.h2.Driver"
24 | config.jdbcUrl = "jdbc:h2:mem:;DATABASE_TO_UPPER=false;MODE=MYSQL"
25 | config.maximumPoolSize = 2
26 | config.isAutoCommit = true
27 | config.validate()
28 | source = HikariDataSource(config)
29 | return source
30 | }
31 | }
--------------------------------------------------------------------------------
/part4/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/DatabaseFactoryForUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
4 | import com.zaxxer.hikari.HikariConfig
5 | import com.zaxxer.hikari.HikariDataSource
6 | import org.jetbrains.exposed.sql.Database
7 |
8 | class DatabaseFactoryForUnitTest: DatabaseFactory {
9 |
10 | lateinit var source: HikariDataSource
11 |
12 | override fun close() {
13 | source.close()
14 | }
15 |
16 | override fun connect() {
17 | Database.connect(hikari())
18 | SchemaDefinition.createSchema()
19 | }
20 |
21 | private fun hikari(): HikariDataSource {
22 | val config = HikariConfig()
23 | config.driverClassName = "org.h2.Driver"
24 | config.jdbcUrl = "jdbc:h2:mem:;DATABASE_TO_UPPER=false;MODE=MYSQL"
25 | config.maximumPoolSize = 2
26 | config.isAutoCommit = true
27 | config.validate()
28 | source = HikariDataSource(config)
29 | return source
30 | }
31 | }
--------------------------------------------------------------------------------
/part5/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/DatabaseFactoryForUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
4 | import com.zaxxer.hikari.HikariConfig
5 | import com.zaxxer.hikari.HikariDataSource
6 | import org.jetbrains.exposed.sql.Database
7 |
8 | class DatabaseFactoryForUnitTest: DatabaseFactory {
9 |
10 | lateinit var source: HikariDataSource
11 |
12 | override fun close() {
13 | source.close()
14 | }
15 |
16 | override fun connect() {
17 | Database.connect(hikari())
18 | SchemaDefinition.createSchema()
19 | }
20 |
21 | private fun hikari(): HikariDataSource {
22 | val config = HikariConfig()
23 | config.driverClassName = "org.h2.Driver"
24 | config.jdbcUrl = "jdbc:h2:mem:;DATABASE_TO_UPPER=false;MODE=MYSQL"
25 | config.maximumPoolSize = 2
26 | config.isAutoCommit = true
27 | config.validate()
28 | source = HikariDataSource(config)
29 | return source
30 | }
31 | }
--------------------------------------------------------------------------------
/part6/src/main/kotlin/com/prof18/ktor/chucknorris/sample/jobs/RandomJokeJob.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.jobs
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import org.quartz.Job
5 | import org.quartz.JobExecutionContext
6 |
7 | class RandomJokeJob(
8 | private val jokeRepository: JokeRepository
9 | ) : Job {
10 |
11 | override fun execute(context: JobExecutionContext?) {
12 | if (context == null) {
13 | return
14 | }
15 |
16 | val dataMap = context.jobDetail.jobDataMap
17 |
18 | val name: String? = try {
19 | dataMap.getString(JOB_MAP_NAME_ID_KEY)
20 | } catch (e: ClassCastException) {
21 | null
22 | }
23 |
24 | if (name != null) {
25 | val greetingMessage = jokeRepository.getChuckGreeting(name)
26 |
27 | println(greetingMessage)
28 | }
29 | }
30 |
31 | companion object {
32 | const val JOB_MAP_NAME_ID_KEY = "name"
33 | const val WATCH_JOB_GROUP = "WatchJob"
34 |
35 | }
36 | }
37 |
38 |
39 |
--------------------------------------------------------------------------------
/part6/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/DatabaseFactoryForUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
4 | import com.zaxxer.hikari.HikariConfig
5 | import com.zaxxer.hikari.HikariDataSource
6 | import org.jetbrains.exposed.sql.Database
7 |
8 | class DatabaseFactoryForUnitTest: DatabaseFactory {
9 |
10 | lateinit var source: HikariDataSource
11 |
12 | override fun close() {
13 | source.close()
14 | }
15 |
16 | override fun connect() {
17 | Database.connect(hikari())
18 | SchemaDefinition.createSchema()
19 | }
20 |
21 | private fun hikari(): HikariDataSource {
22 | val config = HikariConfig()
23 | config.driverClassName = "org.h2.Driver"
24 | config.jdbcUrl = "jdbc:h2:mem:;DATABASE_TO_UPPER=false;MODE=MYSQL"
25 | config.maximumPoolSize = 2
26 | config.isAutoCommit = true
27 | config.validate()
28 | source = HikariDataSource(config)
29 | return source
30 | }
31 | }
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/jobs/RandomJokeJob.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.jobs
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import org.quartz.Job
5 | import org.quartz.JobExecutionContext
6 |
7 | class RandomJokeJob(
8 | private val jokeRepository: JokeRepository
9 | ) : Job {
10 |
11 | override fun execute(context: JobExecutionContext?) {
12 | if (context == null) {
13 | return
14 | }
15 |
16 | val dataMap = context.jobDetail.jobDataMap
17 |
18 | val name: String? = try {
19 | dataMap.getString(JOB_MAP_NAME_ID_KEY)
20 | } catch (e: ClassCastException) {
21 | null
22 | }
23 |
24 | if (name != null) {
25 | val greetingMessage = jokeRepository.getChuckGreeting(name)
26 |
27 | println(greetingMessage)
28 | }
29 | }
30 |
31 | companion object {
32 | const val JOB_MAP_NAME_ID_KEY = "name"
33 | const val WATCH_JOB_GROUP = "WatchJob"
34 |
35 | }
36 | }
37 |
38 |
39 |
--------------------------------------------------------------------------------
/ktor-1.6.x/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/DatabaseFactoryForUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
4 | import com.zaxxer.hikari.HikariConfig
5 | import com.zaxxer.hikari.HikariDataSource
6 | import org.jetbrains.exposed.sql.Database
7 |
8 | class DatabaseFactoryForUnitTest: DatabaseFactory {
9 |
10 | lateinit var source: HikariDataSource
11 |
12 | override fun close() {
13 | source.close()
14 | }
15 |
16 | override fun connect() {
17 | Database.connect(hikari())
18 | SchemaDefinition.createSchema()
19 | }
20 |
21 | private fun hikari(): HikariDataSource {
22 | val config = HikariConfig()
23 | config.driverClassName = "org.h2.Driver"
24 | config.jdbcUrl = "jdbc:h2:mem:;DATABASE_TO_UPPER=false;MODE=MYSQL"
25 | config.maximumPoolSize = 2
26 | config.isAutoCommit = true
27 | config.validate()
28 | source = HikariDataSource(config)
29 | return source
30 | }
31 | }
--------------------------------------------------------------------------------
/ktor-2.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/jobs/RandomJokeJob.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.jobs
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import org.quartz.Job
5 | import org.quartz.JobExecutionContext
6 |
7 | class RandomJokeJob(
8 | private val jokeRepository: JokeRepository
9 | ) : Job {
10 |
11 | override fun execute(context: JobExecutionContext?) {
12 | if (context == null) {
13 | return
14 | }
15 |
16 | val dataMap = context.jobDetail.jobDataMap
17 |
18 | val name: String? = try {
19 | dataMap.getString(JOB_MAP_NAME_ID_KEY)
20 | } catch (e: ClassCastException) {
21 | null
22 | }
23 |
24 | if (name != null) {
25 | val greetingMessage = jokeRepository.getChuckGreeting(name)
26 |
27 | println(greetingMessage)
28 | }
29 | }
30 |
31 | companion object {
32 | const val JOB_MAP_NAME_ID_KEY = "name"
33 | const val WATCH_JOB_GROUP = "WatchJob"
34 |
35 | }
36 | }
37 |
38 |
39 |
--------------------------------------------------------------------------------
/part6/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/resource/JokeResource.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.resource
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import io.ktor.application.*
5 | import io.ktor.locations.*
6 | import io.ktor.locations.post
7 | import io.ktor.response.*
8 | import io.ktor.routing.*
9 | import org.koin.ktor.ext.inject
10 |
11 | @KtorExperimentalLocationsAPI
12 | @Location("joke")
13 | class JokeEndpoint {
14 |
15 | @Location("/random")
16 | class Random(val parent: JokeEndpoint)
17 |
18 | @Location("/watch/{name}")
19 | class Watch(val name: String, val parent: JokeEndpoint)
20 | }
21 |
22 | @KtorExperimentalLocationsAPI
23 | fun Route.jokeEndpoint() {
24 |
25 | val jokeRepository by inject()
26 |
27 | get {
28 | call.respond(jokeRepository.getRandomJoke())
29 | }
30 |
31 | post { apiCallParams ->
32 | val name = apiCallParams.name
33 | jokeRepository.watch(name)
34 | call.respond("Ok")
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/resource/JokeResource.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.resource
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import io.ktor.application.*
5 | import io.ktor.locations.*
6 | import io.ktor.locations.post
7 | import io.ktor.response.*
8 | import io.ktor.routing.*
9 | import org.koin.ktor.ext.inject
10 |
11 | @KtorExperimentalLocationsAPI
12 | @Location("joke")
13 | class JokeEndpoint {
14 |
15 | @Location("/random")
16 | class Random(val parent: JokeEndpoint)
17 |
18 | @Location("/watch/{name}")
19 | class Watch(val name: String, val parent: JokeEndpoint)
20 | }
21 |
22 | @KtorExperimentalLocationsAPI
23 | fun Route.jokeEndpoint() {
24 |
25 | val jokeRepository by inject()
26 |
27 | get {
28 | call.respond(jokeRepository.getRandomJoke())
29 | }
30 |
31 | post { apiCallParams ->
32 | val name = apiCallParams.name
33 | jokeRepository.watch(name)
34 | call.respond("Ok")
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/part3/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/DatabaseFactoryForServerTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
5 | import com.zaxxer.hikari.HikariConfig
6 | import com.zaxxer.hikari.HikariDataSource
7 | import org.jetbrains.exposed.sql.Database
8 |
9 | class DatabaseFactoryForServerTest(appConfig: AppConfig): DatabaseFactory {
10 |
11 | private val dbConfig = appConfig.databaseConfig
12 |
13 | override fun connect() {
14 | Database.connect(hikari())
15 | SchemaDefinition.createSchema()
16 | }
17 |
18 | override fun close() {
19 | // not needed
20 | }
21 |
22 | private fun hikari(): HikariDataSource {
23 | val config = HikariConfig()
24 | config.driverClassName = dbConfig.driverClass
25 | config.jdbcUrl = dbConfig.url
26 | config.maximumPoolSize = dbConfig.maxPoolSize
27 | config.isAutoCommit = true
28 | config.validate()
29 | return HikariDataSource(config)
30 | }
31 | }
--------------------------------------------------------------------------------
/part4/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/DatabaseFactoryForServerTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
5 | import com.zaxxer.hikari.HikariConfig
6 | import com.zaxxer.hikari.HikariDataSource
7 | import org.jetbrains.exposed.sql.Database
8 |
9 | class DatabaseFactoryForServerTest(appConfig: AppConfig): DatabaseFactory {
10 |
11 | private val dbConfig = appConfig.databaseConfig
12 |
13 | override fun connect() {
14 | Database.connect(hikari())
15 | SchemaDefinition.createSchema()
16 | }
17 |
18 | override fun close() {
19 | // not needed
20 | }
21 |
22 | private fun hikari(): HikariDataSource {
23 | val config = HikariConfig()
24 | config.driverClassName = dbConfig.driverClass
25 | config.jdbcUrl = dbConfig.url
26 | config.maximumPoolSize = dbConfig.maxPoolSize
27 | config.isAutoCommit = true
28 | config.validate()
29 | return HikariDataSource(config)
30 | }
31 | }
--------------------------------------------------------------------------------
/part5/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/DatabaseFactoryForServerTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
5 | import com.zaxxer.hikari.HikariConfig
6 | import com.zaxxer.hikari.HikariDataSource
7 | import org.jetbrains.exposed.sql.Database
8 |
9 | class DatabaseFactoryForServerTest(appConfig: AppConfig): DatabaseFactory {
10 |
11 | private val dbConfig = appConfig.databaseConfig
12 |
13 | override fun connect() {
14 | Database.connect(hikari())
15 | SchemaDefinition.createSchema()
16 | }
17 |
18 | override fun close() {
19 | // not needed
20 | }
21 |
22 | private fun hikari(): HikariDataSource {
23 | val config = HikariConfig()
24 | config.driverClassName = dbConfig.driverClass
25 | config.jdbcUrl = dbConfig.url
26 | config.maximumPoolSize = dbConfig.maxPoolSize
27 | config.isAutoCommit = true
28 | config.validate()
29 | return HikariDataSource(config)
30 | }
31 | }
--------------------------------------------------------------------------------
/part6/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/DatabaseFactoryForServerTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
5 | import com.zaxxer.hikari.HikariConfig
6 | import com.zaxxer.hikari.HikariDataSource
7 | import org.jetbrains.exposed.sql.Database
8 |
9 | class DatabaseFactoryForServerTest(appConfig: AppConfig): DatabaseFactory {
10 |
11 | private val dbConfig = appConfig.databaseConfig
12 |
13 | override fun connect() {
14 | Database.connect(hikari())
15 | SchemaDefinition.createSchema()
16 | }
17 |
18 | override fun close() {
19 | // not needed
20 | }
21 |
22 | private fun hikari(): HikariDataSource {
23 | val config = HikariConfig()
24 | config.driverClassName = dbConfig.driverClass
25 | config.jdbcUrl = dbConfig.url
26 | config.maximumPoolSize = dbConfig.maxPoolSize
27 | config.isAutoCommit = true
28 | config.validate()
29 | return HikariDataSource(config)
30 | }
31 | }
--------------------------------------------------------------------------------
/ktor-1.6.x/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/DatabaseFactoryForServerTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
5 | import com.zaxxer.hikari.HikariConfig
6 | import com.zaxxer.hikari.HikariDataSource
7 | import org.jetbrains.exposed.sql.Database
8 |
9 | class DatabaseFactoryForServerTest(appConfig: AppConfig): DatabaseFactory {
10 |
11 | private val dbConfig = appConfig.databaseConfig
12 |
13 | override fun connect() {
14 | Database.connect(hikari())
15 | SchemaDefinition.createSchema()
16 | }
17 |
18 | override fun close() {
19 | // not needed
20 | }
21 |
22 | private fun hikari(): HikariDataSource {
23 | val config = HikariConfig()
24 | config.driverClassName = dbConfig.driverClass
25 | config.jdbcUrl = dbConfig.url
26 | config.maximumPoolSize = dbConfig.maxPoolSize
27 | config.isAutoCommit = true
28 | config.validate()
29 | return HikariDataSource(config)
30 | }
31 | }
--------------------------------------------------------------------------------
/ktor-2.x/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/database/DatabaseFactoryForServerTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
5 | import com.zaxxer.hikari.HikariConfig
6 | import com.zaxxer.hikari.HikariDataSource
7 | import org.jetbrains.exposed.sql.Database
8 |
9 | class DatabaseFactoryForServerTest(appConfig: AppConfig): DatabaseFactory {
10 |
11 | private val dbConfig = appConfig.databaseConfig
12 |
13 | override fun connect() {
14 | Database.connect(hikari())
15 | SchemaDefinition.createSchema()
16 | }
17 |
18 | override fun close() {
19 | // not needed
20 | }
21 |
22 | private fun hikari(): HikariDataSource {
23 | val config = HikariConfig()
24 | config.driverClassName = dbConfig.driverClass
25 | config.jdbcUrl = dbConfig.url
26 | config.maximumPoolSize = dbConfig.maxPoolSize
27 | config.isAutoCommit = true
28 | config.validate()
29 | return HikariDataSource(config)
30 | }
31 | }
--------------------------------------------------------------------------------
/ktor-2.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/resource/JokeResource.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.resource
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import io.ktor.resources.Resource
5 | import io.ktor.server.application.call
6 | import io.ktor.server.resources.get
7 | import io.ktor.server.resources.post
8 | import io.ktor.server.response.respond
9 | import io.ktor.server.routing.Route
10 | import org.koin.ktor.ext.inject
11 |
12 | @Resource("joke")
13 | class JokeEndpoint {
14 |
15 | @Resource("/random")
16 | class Random(val parent: JokeEndpoint = JokeEndpoint())
17 |
18 | @Resource("/watch/{name}")
19 | class Watch(val name: String, val parent: JokeEndpoint = JokeEndpoint())
20 | }
21 |
22 | fun Route.jokeEndpoint() {
23 |
24 | val jokeRepository by inject()
25 |
26 | get {
27 | call.respond(jokeRepository.getRandomJoke())
28 | }
29 |
30 | post { apiCallParams ->
31 | val name = apiCallParams.name
32 | jokeRepository.watch(name)
33 | call.respond("Ok")
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/part6/src/main/kotlin/com/prof18/ktor/chucknorris/sample/di/AppModule.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.di
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
5 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactoryImpl
6 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSource
7 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSourceImpl
8 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
9 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepositoryImpl
10 | import com.prof18.ktor.chucknorris.sample.jobs.JobFactory
11 | import com.prof18.ktor.chucknorris.sample.jobs.JobSchedulerManager
12 | import org.koin.dsl.module
13 | import org.koin.dsl.single
14 |
15 | val appModule = module {
16 | // Backend Config
17 | single()
18 | single { DatabaseFactoryImpl(get()) }
19 | single { JokeLocalDataSourceImpl() }
20 | single { JokeRepositoryImpl(get(), get()) }
21 | single()
22 | single()
23 | }
24 |
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/di/AppModule.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.di
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
5 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactoryImpl
6 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSource
7 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSourceImpl
8 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
9 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepositoryImpl
10 | import com.prof18.ktor.chucknorris.sample.jobs.JobFactory
11 | import com.prof18.ktor.chucknorris.sample.jobs.JobSchedulerManager
12 | import org.koin.dsl.module
13 | import org.koin.dsl.single
14 |
15 | val appModule = module {
16 | // Backend Config
17 | single()
18 | single { DatabaseFactoryImpl(get()) }
19 | single { JokeLocalDataSourceImpl() }
20 | single { JokeRepositoryImpl(get(), get()) }
21 | single()
22 | single()
23 | }
24 |
--------------------------------------------------------------------------------
/ktor-2.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/di/AppModule.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.di
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
5 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactoryImpl
6 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSource
7 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSourceImpl
8 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
9 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepositoryImpl
10 | import com.prof18.ktor.chucknorris.sample.jobs.JobFactory
11 | import com.prof18.ktor.chucknorris.sample.jobs.JobSchedulerManager
12 | import org.koin.core.module.dsl.singleOf
13 | import org.koin.dsl.module
14 |
15 | val appModule = module {
16 | // Backend Config
17 | singleOf(::AppConfig)
18 | single { DatabaseFactoryImpl(get()) }
19 | single { JokeLocalDataSourceImpl() }
20 | single { JokeRepositoryImpl(get(), get()) }
21 | singleOf(::JobSchedulerManager)
22 | singleOf(::JobFactory)
23 | }
24 |
--------------------------------------------------------------------------------
/part2/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 | ${LOG_DEST}/ktor-chuck-norris-sample.log
10 |
11 |
12 | ${LOG_DEST}/ktor-chuck-norris-sample.%d{yyyy-MM-dd}.log
13 |
14 |
15 | ${LOG_MAX_HISTORY}
16 | 3GB
17 |
18 |
19 |
20 |
21 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/part3/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 | ${LOG_DEST}/ktor-chuck-norris-sample.log
10 |
11 |
12 | ${LOG_DEST}/ktor-chuck-norris-sample.%d{yyyy-MM-dd}.log
13 |
14 |
15 | ${LOG_MAX_HISTORY}
16 | 3GB
17 |
18 |
19 |
20 |
21 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/part4/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 | ${LOG_DEST}/ktor-chuck-norris-sample.log
10 |
11 |
12 | ${LOG_DEST}/ktor-chuck-norris-sample.%d{yyyy-MM-dd}.log
13 |
14 |
15 | ${LOG_MAX_HISTORY}
16 | 3GB
17 |
18 |
19 |
20 |
21 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/part5/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 | ${LOG_DEST}/ktor-chuck-norris-sample.log
10 |
11 |
12 | ${LOG_DEST}/ktor-chuck-norris-sample.%d{yyyy-MM-dd}.log
13 |
14 |
15 | ${LOG_MAX_HISTORY}
16 | 3GB
17 |
18 |
19 |
20 |
21 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/part6/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 | ${LOG_DEST}/ktor-chuck-norris-sample.log
10 |
11 |
12 | ${LOG_DEST}/ktor-chuck-norris-sample.%d{yyyy-MM-dd}.log
13 |
14 |
15 | ${LOG_MAX_HISTORY}
16 | 3GB
17 |
18 |
19 |
20 |
21 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 | ${LOG_DEST}/ktor-chuck-norris-sample.log
10 |
11 |
12 | ${LOG_DEST}/ktor-chuck-norris-sample.%d{yyyy-MM-dd}.log
13 |
14 |
15 | ${LOG_MAX_HISTORY}
16 | 3GB
17 |
18 |
19 |
20 |
21 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/ktor-2.x/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 | ${LOG_DEST}/ktor-chuck-norris-sample.log
10 |
11 |
12 | ${LOG_DEST}/ktor-chuck-norris-sample.%d{yyyy-MM-dd}.log
13 |
14 |
15 | ${LOG_MAX_HISTORY}
16 | 3GB
17 |
18 |
19 |
20 |
21 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/part3/src/main/kotlin/com/prof18/ktor/chucknorris/sample/config/AppConfig.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.config
2 |
3 | import io.ktor.application.*
4 | import org.koin.ktor.ext.inject
5 |
6 | class AppConfig {
7 | lateinit var databaseConfig: DatabaseConfig
8 | lateinit var serverConfig: ServerConfig
9 | // Place here other configurations
10 | }
11 |
12 | fun Application.setupConfig() {
13 | val appConfig by inject()
14 |
15 | // Server
16 | val serverObject = environment.config.config("ktor.server")
17 | val isProd = serverObject.property("isProd").getString().toBoolean()
18 | appConfig.serverConfig = ServerConfig(isProd)
19 |
20 | // Database
21 | val databaseObject = environment.config.config("ktor.database")
22 | val driverClass = databaseObject.property("driverClass").getString()
23 | val url = databaseObject.property("url").getString()
24 | val user = databaseObject.property("user").getString()
25 | val password = databaseObject.property("password").getString()
26 | val maxPoolSize = databaseObject.property("maxPoolSize").getString().toInt()
27 | appConfig.databaseConfig = DatabaseConfig(driverClass, url, user, password, maxPoolSize)
28 | }
29 |
30 | data class DatabaseConfig(
31 | val driverClass: String,
32 | val url: String,
33 | val user: String,
34 | val password: String,
35 | val maxPoolSize: Int
36 | )
37 |
38 | data class ServerConfig(
39 | val isProd: Boolean
40 | )
41 |
--------------------------------------------------------------------------------
/part4/src/main/kotlin/com/prof18/ktor/chucknorris/sample/config/AppConfig.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.config
2 |
3 | import io.ktor.application.*
4 | import org.koin.ktor.ext.inject
5 |
6 | class AppConfig {
7 | lateinit var databaseConfig: DatabaseConfig
8 | lateinit var serverConfig: ServerConfig
9 | // Place here other configurations
10 | }
11 |
12 | fun Application.setupConfig() {
13 | val appConfig by inject()
14 |
15 | // Server
16 | val serverObject = environment.config.config("ktor.server")
17 | val isProd = serverObject.property("isProd").getString().toBoolean()
18 | appConfig.serverConfig = ServerConfig(isProd)
19 |
20 | // Database
21 | val databaseObject = environment.config.config("ktor.database")
22 | val driverClass = databaseObject.property("driverClass").getString()
23 | val url = databaseObject.property("url").getString()
24 | val user = databaseObject.property("user").getString()
25 | val password = databaseObject.property("password").getString()
26 | val maxPoolSize = databaseObject.property("maxPoolSize").getString().toInt()
27 | appConfig.databaseConfig = DatabaseConfig(driverClass, url, user, password, maxPoolSize)
28 | }
29 |
30 | data class DatabaseConfig(
31 | val driverClass: String,
32 | val url: String,
33 | val user: String,
34 | val password: String,
35 | val maxPoolSize: Int
36 | )
37 |
38 | data class ServerConfig(
39 | val isProd: Boolean
40 | )
41 |
--------------------------------------------------------------------------------
/part5/src/main/kotlin/com/prof18/ktor/chucknorris/sample/config/AppConfig.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.config
2 |
3 | import io.ktor.application.*
4 | import org.koin.ktor.ext.inject
5 |
6 | class AppConfig {
7 | lateinit var databaseConfig: DatabaseConfig
8 | lateinit var serverConfig: ServerConfig
9 | // Place here other configurations
10 | }
11 |
12 | fun Application.setupConfig() {
13 | val appConfig by inject()
14 |
15 | // Server
16 | val serverObject = environment.config.config("ktor.server")
17 | val isProd = serverObject.property("isProd").getString().toBoolean()
18 | appConfig.serverConfig = ServerConfig(isProd)
19 |
20 | // Database
21 | val databaseObject = environment.config.config("ktor.database")
22 | val driverClass = databaseObject.property("driverClass").getString()
23 | val url = databaseObject.property("url").getString()
24 | val user = databaseObject.property("user").getString()
25 | val password = databaseObject.property("password").getString()
26 | val maxPoolSize = databaseObject.property("maxPoolSize").getString().toInt()
27 | appConfig.databaseConfig = DatabaseConfig(driverClass, url, user, password, maxPoolSize)
28 | }
29 |
30 | data class DatabaseConfig(
31 | val driverClass: String,
32 | val url: String,
33 | val user: String,
34 | val password: String,
35 | val maxPoolSize: Int
36 | )
37 |
38 | data class ServerConfig(
39 | val isProd: Boolean
40 | )
41 |
--------------------------------------------------------------------------------
/part6/src/main/kotlin/com/prof18/ktor/chucknorris/sample/config/AppConfig.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.config
2 |
3 | import io.ktor.application.*
4 | import org.koin.ktor.ext.inject
5 |
6 | class AppConfig {
7 | lateinit var databaseConfig: DatabaseConfig
8 | lateinit var serverConfig: ServerConfig
9 | // Place here other configurations
10 | }
11 |
12 | fun Application.setupConfig() {
13 | val appConfig by inject()
14 |
15 | // Server
16 | val serverObject = environment.config.config("ktor.server")
17 | val isProd = serverObject.property("isProd").getString().toBoolean()
18 | appConfig.serverConfig = ServerConfig(isProd)
19 |
20 | // Database
21 | val databaseObject = environment.config.config("ktor.database")
22 | val driverClass = databaseObject.property("driverClass").getString()
23 | val url = databaseObject.property("url").getString()
24 | val user = databaseObject.property("user").getString()
25 | val password = databaseObject.property("password").getString()
26 | val maxPoolSize = databaseObject.property("maxPoolSize").getString().toInt()
27 | appConfig.databaseConfig = DatabaseConfig(driverClass, url, user, password, maxPoolSize)
28 | }
29 |
30 | data class DatabaseConfig(
31 | val driverClass: String,
32 | val url: String,
33 | val user: String,
34 | val password: String,
35 | val maxPoolSize: Int
36 | )
37 |
38 | data class ServerConfig(
39 | val isProd: Boolean
40 | )
41 |
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/config/AppConfig.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.config
2 |
3 | import io.ktor.application.*
4 | import org.koin.ktor.ext.inject
5 |
6 | class AppConfig {
7 | lateinit var databaseConfig: DatabaseConfig
8 | lateinit var serverConfig: ServerConfig
9 | // Place here other configurations
10 | }
11 |
12 | fun Application.setupConfig() {
13 | val appConfig by inject()
14 |
15 | // Server
16 | val serverObject = environment.config.config("ktor.server")
17 | val isProd = serverObject.property("isProd").getString().toBoolean()
18 | appConfig.serverConfig = ServerConfig(isProd)
19 |
20 | // Database
21 | val databaseObject = environment.config.config("ktor.database")
22 | val driverClass = databaseObject.property("driverClass").getString()
23 | val url = databaseObject.property("url").getString()
24 | val user = databaseObject.property("user").getString()
25 | val password = databaseObject.property("password").getString()
26 | val maxPoolSize = databaseObject.property("maxPoolSize").getString().toInt()
27 | appConfig.databaseConfig = DatabaseConfig(driverClass, url, user, password, maxPoolSize)
28 | }
29 |
30 | data class DatabaseConfig(
31 | val driverClass: String,
32 | val url: String,
33 | val user: String,
34 | val password: String,
35 | val maxPoolSize: Int
36 | )
37 |
38 | data class ServerConfig(
39 | val isProd: Boolean
40 | )
41 |
--------------------------------------------------------------------------------
/ktor-2.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/config/AppConfig.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.config
2 |
3 | import io.ktor.server.application.Application
4 | import org.koin.ktor.ext.inject
5 |
6 | class AppConfig {
7 | lateinit var databaseConfig: DatabaseConfig
8 | lateinit var serverConfig: ServerConfig
9 | // Place here other configurations
10 | }
11 |
12 | fun Application.setupConfig() {
13 | val appConfig by inject()
14 |
15 | // Server
16 | val serverObject = environment.config.config("ktor.server")
17 | val isProd = serverObject.property("isProd").getString().toBoolean()
18 | appConfig.serverConfig = ServerConfig(isProd)
19 |
20 | // Database
21 | val databaseObject = environment.config.config("ktor.database")
22 | val driverClass = databaseObject.property("driverClass").getString()
23 | val url = databaseObject.property("url").getString()
24 | val user = databaseObject.property("user").getString()
25 | val password = databaseObject.property("password").getString()
26 | val maxPoolSize = databaseObject.property("maxPoolSize").getString().toInt()
27 | appConfig.databaseConfig = DatabaseConfig(driverClass, url, user, password, maxPoolSize)
28 | }
29 |
30 | data class DatabaseConfig(
31 | val driverClass: String,
32 | val url: String,
33 | val user: String,
34 | val password: String,
35 | val maxPoolSize: Int
36 | )
37 |
38 | data class ServerConfig(
39 | val isProd: Boolean
40 | )
41 |
--------------------------------------------------------------------------------
/part1/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2 |
3 | val ktor_version: String by project
4 | val kotlin_version: String by project
5 | val logback_version: String by project
6 | val koin_version: String by project
7 |
8 | plugins {
9 | application
10 | kotlin("jvm") version "1.5.30"
11 | id("org.jetbrains.kotlin.plugin.serialization") version "1.5.30"
12 | }
13 |
14 | group = "com.prof18.ktor.chucknorris.sample"
15 | version = "0.0.1"
16 | application {
17 | mainClass.set("io.ktor.server.netty.EngineMain")
18 | }
19 |
20 | repositories {
21 | mavenCentral()
22 | }
23 |
24 | tasks.withType().all {
25 | kotlinOptions {
26 | jvmTarget = "11"
27 | }
28 | }
29 |
30 | dependencies {
31 | implementation("io.ktor:ktor-server-core:$ktor_version")
32 | implementation("io.ktor:ktor-serialization:$ktor_version")
33 | implementation("io.ktor:ktor-server-host-common:$ktor_version")
34 | implementation("io.ktor:ktor-server-netty:$ktor_version")
35 | implementation("io.ktor:ktor-locations:$ktor_version")
36 | implementation("ch.qos.logback:logback-classic:$logback_version")
37 |
38 | // Koin
39 | implementation("io.insert-koin:koin-ktor:$koin_version")
40 | implementation("io.insert-koin:koin-logger-slf4j:$koin_version")
41 |
42 | // Testing
43 | testImplementation("io.ktor:ktor-server-tests:$ktor_version")
44 | testImplementation("io.insert-koin:koin-test:$koin_version")
45 | testImplementation("io.insert-koin:koin-test-junit4:$koin_version")
46 | testImplementation("junit:junit:4.12")
47 | }
--------------------------------------------------------------------------------
/part2/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2 |
3 | val ktor_version: String by project
4 | val kotlin_version: String by project
5 | val logback_version: String by project
6 | val koin_version: String by project
7 |
8 | plugins {
9 | application
10 | kotlin("jvm") version "1.5.30"
11 | id("org.jetbrains.kotlin.plugin.serialization") version "1.5.30"
12 | }
13 |
14 | group = "com.prof18.ktor.chucknorris.sample"
15 | version = "0.0.1"
16 | application {
17 | mainClass.set("io.ktor.server.netty.EngineMain")
18 | }
19 |
20 | repositories {
21 | mavenCentral()
22 | }
23 |
24 | tasks.withType().all {
25 | kotlinOptions {
26 | jvmTarget = "11"
27 | }
28 | }
29 |
30 | dependencies {
31 | implementation("io.ktor:ktor-server-core:$ktor_version")
32 | implementation("io.ktor:ktor-serialization:$ktor_version")
33 | implementation("io.ktor:ktor-server-host-common:$ktor_version")
34 | implementation("io.ktor:ktor-server-netty:$ktor_version")
35 | implementation("io.ktor:ktor-locations:$ktor_version")
36 | implementation("ch.qos.logback:logback-classic:$logback_version")
37 |
38 | // Koin
39 | implementation("io.insert-koin:koin-ktor:$koin_version")
40 | implementation("io.insert-koin:koin-logger-slf4j:$koin_version")
41 |
42 | // Testing
43 | testImplementation("io.ktor:ktor-server-tests:$ktor_version")
44 | testImplementation("io.insert-koin:koin-test:$koin_version")
45 | testImplementation("io.insert-koin:koin-test-junit4:$koin_version")
46 | testImplementation("junit:junit:4.12")
47 | }
--------------------------------------------------------------------------------
/ktor-1.6.x/README.md:
--------------------------------------------------------------------------------
1 | # Ktor Chuck Norris Sample
2 |
3 | A [Ktor](http://ktor.io) (version 1.6.x) sample project that returns Random Chuck Norris jokes.
4 |
5 | This project contains all the code used in some articles published on my website.
6 |
7 | ## 1. Structuring a Ktor project
8 |
9 | - Article: https://www.marcogomiero.com/posts/2021/ktor-project-structure/
10 | - Code: [part1 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part1)
11 |
12 | ## 2. How to persist Ktor logs
13 |
14 | - Article: https://www.marcogomiero.com/posts/2021/ktor-logging-on-disk/
15 | - Code: [part2 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part2)
16 |
17 | ## 3. How to use an in-memory database for testing on Ktor
18 |
19 | - Article: https://www.marcogomiero.com/posts/2021/ktor-in-memory-db-testing/
20 | - Code: [part3 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part3)
21 |
22 | ## 4. How to handle database migrations with Liquibase on Ktor
23 |
24 | - Article: https://www.marcogomiero.com/posts/2022/ktor-migration-liquibase/
25 | - Code: [part4 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part4)
26 |
27 | ## 5. Generate API documentation from Swagger on Ktor
28 |
29 | - Article: https://www.marcogomiero.com/posts/2022/ktor-setup-documentation/
30 | - Code: [part5 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part5)
31 |
32 | ## 6. How to schedule jobs with Quartz on Ktor
33 |
34 | - Article: https://www.marcogomiero.com/posts/2022/ktor-jobs-quartz/
35 | - Code: [part6 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part6)
36 |
37 | ---
38 |
39 | The data used for the databases are from the [Chuck Norris IO](https://github.com/chucknorris-io/chuck-db) project.
40 |
--------------------------------------------------------------------------------
/part3/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/TestServer.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSource
6 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSourceImpl
7 | import com.prof18.ktor.chucknorris.sample.module
8 | import com.prof18.ktor.chucknorris.sample.testutils.database.DatabaseFactoryForServerTest
9 | import io.ktor.config.*
10 | import io.ktor.locations.*
11 | import io.ktor.server.testing.*
12 | import org.koin.core.module.Module
13 | import org.koin.dsl.module
14 | import org.koin.dsl.single
15 |
16 | fun MapApplicationConfig.createConfigForTesting() {
17 | // Server config
18 | put("ktor.server.isProd", "false")
19 |
20 | // Database Config
21 | put("ktor.database.driverClass", "org.h2.Driver")
22 | put("ktor.database.url", "jdbc:h2:mem:;DATABASE_TO_UPPER=false;MODE=MYSQL")
23 | put("ktor.database.user", "root")
24 | put("ktor.database.password", "password")
25 | put("ktor.database.maxPoolSize", "1")
26 | }
27 |
28 |
29 | @KtorExperimentalLocationsAPI
30 | fun withTestServer(koinModules: List = listOf(appTestModule), block: TestApplicationEngine.() -> Unit) {
31 | withTestApplication(
32 | {
33 | (environment.config as MapApplicationConfig).apply {
34 | createConfigForTesting()
35 | }
36 | module(testing = true, koinModules = koinModules)
37 | }, block
38 | )
39 | }
40 |
41 | val appTestModule = module {
42 | single()
43 | single { DatabaseFactoryForServerTest(get()) }
44 | single { JokeLocalDataSourceImpl() }
45 | }
46 |
47 |
48 |
--------------------------------------------------------------------------------
/part4/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/TestServer.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSource
6 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSourceImpl
7 | import com.prof18.ktor.chucknorris.sample.module
8 | import com.prof18.ktor.chucknorris.sample.testutils.database.DatabaseFactoryForServerTest
9 | import io.ktor.config.*
10 | import io.ktor.locations.*
11 | import io.ktor.server.testing.*
12 | import org.koin.core.module.Module
13 | import org.koin.dsl.module
14 | import org.koin.dsl.single
15 |
16 | fun MapApplicationConfig.createConfigForTesting() {
17 | // Server config
18 | put("ktor.server.isProd", "false")
19 |
20 | // Database Config
21 | put("ktor.database.driverClass", "org.h2.Driver")
22 | put("ktor.database.url", "jdbc:h2:mem:;DATABASE_TO_UPPER=false;MODE=MYSQL")
23 | put("ktor.database.user", "root")
24 | put("ktor.database.password", "password")
25 | put("ktor.database.maxPoolSize", "1")
26 | }
27 |
28 |
29 | @KtorExperimentalLocationsAPI
30 | fun withTestServer(koinModules: List = listOf(appTestModule), block: TestApplicationEngine.() -> Unit) {
31 | withTestApplication(
32 | {
33 | (environment.config as MapApplicationConfig).apply {
34 | createConfigForTesting()
35 | }
36 | module(testing = true, koinModules = koinModules)
37 | }, block
38 | )
39 | }
40 |
41 | val appTestModule = module {
42 | single()
43 | single { DatabaseFactoryForServerTest(get()) }
44 | single { JokeLocalDataSourceImpl() }
45 | }
46 |
47 |
48 |
--------------------------------------------------------------------------------
/part5/src/test/kotlin/com/prof18/ktor/chucknorris/sample/testutils/TestServer.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.testutils
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSource
6 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSourceImpl
7 | import com.prof18.ktor.chucknorris.sample.module
8 | import com.prof18.ktor.chucknorris.sample.testutils.database.DatabaseFactoryForServerTest
9 | import io.ktor.config.*
10 | import io.ktor.locations.*
11 | import io.ktor.server.testing.*
12 | import org.koin.core.module.Module
13 | import org.koin.dsl.module
14 | import org.koin.dsl.single
15 |
16 | fun MapApplicationConfig.createConfigForTesting() {
17 | // Server config
18 | put("ktor.server.isProd", "false")
19 |
20 | // Database Config
21 | put("ktor.database.driverClass", "org.h2.Driver")
22 | put("ktor.database.url", "jdbc:h2:mem:;DATABASE_TO_UPPER=false;MODE=MYSQL")
23 | put("ktor.database.user", "root")
24 | put("ktor.database.password", "password")
25 | put("ktor.database.maxPoolSize", "1")
26 | }
27 |
28 |
29 | @KtorExperimentalLocationsAPI
30 | fun withTestServer(koinModules: List = listOf(appTestModule), block: TestApplicationEngine.() -> Unit) {
31 | withTestApplication(
32 | {
33 | (environment.config as MapApplicationConfig).apply {
34 | createConfigForTesting()
35 | }
36 | module(testing = true, koinModules = koinModules)
37 | }, block
38 | )
39 | }
40 |
41 | val appTestModule = module {
42 | single()
43 | single { DatabaseFactoryForServerTest(get()) }
44 | single { JokeLocalDataSourceImpl() }
45 | }
46 |
47 |
48 |
--------------------------------------------------------------------------------
/ktor-2.x/README.md:
--------------------------------------------------------------------------------
1 | # Ktor Chuck Norris Sample
2 |
3 | A [Ktor](http://ktor.io) (version 2.x) sample project that returns Random Chuck Norris jokes.
4 |
5 | This project contains all the code used in some articles published on my website.
6 |
7 | ## 1. Structuring a Ktor project
8 |
9 | - Article: https://www.marcogomiero.com/posts/2021/ktor-project-structure/
10 | - Code: [part1 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part1)
11 |
12 | ## 2. How to persist Ktor logs
13 |
14 | - Article: https://www.marcogomiero.com/posts/2021/ktor-logging-on-disk/
15 | - Code: [part2 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part2)
16 |
17 | ## 3. How to use an in-memory database for testing on Ktor
18 |
19 | - Article: https://www.marcogomiero.com/posts/2021/ktor-in-memory-db-testing/
20 | - Code: [part3 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part3)
21 |
22 | ## 4. How to handle database migrations with Liquibase on Ktor
23 |
24 | - Article: https://www.marcogomiero.com/posts/2022/ktor-migration-liquibase/
25 | - Code: [part4 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part4)
26 |
27 | ## 5. Generate API documentation from Swagger on Ktor
28 |
29 | - Article: https://www.marcogomiero.com/posts/2022/ktor-setup-documentation/
30 | - Code: [part5 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part5)
31 |
32 | ## 6. How to schedule jobs with Quartz on Ktor
33 |
34 | - Article: https://www.marcogomiero.com/posts/2022/ktor-jobs-quartz/
35 | - Code: [part6 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part6)
36 |
37 | ## Ktor 1.6.x
38 |
39 | In the [ktor-1.6.x folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/ktor-1.6.x), the entire project is implemented with Ktor 1.6.x.
40 |
41 | ---
42 |
43 | The data used for the databases are from the [Chuck Norris IO](https://github.com/chucknorris-io/chuck-db) project.
44 |
--------------------------------------------------------------------------------
/part1/src/test/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/resource/JokeResourceTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.resource
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.fake.JokeRepositoryFake
6 | import com.prof18.ktor.chucknorris.sample.testutils.appTestModule
7 | import com.prof18.ktor.chucknorris.sample.testutils.withTestServer
8 | import io.ktor.http.*
9 | import io.ktor.locations.*
10 | import io.ktor.server.testing.*
11 | import kotlinx.serialization.ExperimentalSerializationApi
12 | import kotlinx.serialization.decodeFromString
13 | import kotlinx.serialization.json.Json
14 | import org.junit.Assert.assertEquals
15 | import org.junit.Test
16 | import org.koin.dsl.module
17 | import org.koin.test.AutoCloseKoinTest
18 |
19 | @ExperimentalSerializationApi
20 | @KtorExperimentalLocationsAPI
21 | class JokeResourceTest : AutoCloseKoinTest() {
22 |
23 | @Test
24 | fun `random joke api works correctly`() = withTestServer(
25 | koinModules = appTestModule.plus(
26 | module {
27 | // Just to showcase the possibility, in this case this dependency can be put in the base test module
28 | single { JokeRepositoryFake() }
29 | }
30 | )
31 | ) {
32 |
33 | val href = application.locations.href(
34 | JokeEndpoint.Random(
35 | parent = JokeEndpoint()
36 | )
37 | )
38 |
39 | handleRequest(HttpMethod.Get, href).apply {
40 | assertEquals(HttpStatusCode.OK, response.status())
41 |
42 | val response = Json.decodeFromString(response.content!!)
43 |
44 | assertEquals("fake-id", response.jokeId)
45 | assertEquals("fake-content", response.jokeContent)
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/ktor-2.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/database/DatabaseFactoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.zaxxer.hikari.HikariConfig
5 | import com.zaxxer.hikari.HikariDataSource
6 | import org.jetbrains.exposed.sql.Database
7 |
8 | class DatabaseFactoryImpl(appConfig: AppConfig) : DatabaseFactory {
9 |
10 | private val dbConfig = appConfig.databaseConfig
11 |
12 | override fun close() {
13 | // not necessary
14 | }
15 |
16 | override fun connect() {
17 | Database.connect(hikari())
18 | }
19 |
20 | private fun hikari(): HikariDataSource {
21 | val config = HikariConfig()
22 | config.driverClassName = dbConfig.driverClass
23 | config.jdbcUrl = dbConfig.url
24 | config.username = dbConfig.user
25 | config.password = dbConfig.password
26 | config.maximumPoolSize = dbConfig.maxPoolSize
27 | config.isAutoCommit = false
28 | config.transactionIsolation = "TRANSACTION_REPEATABLE_READ"
29 |
30 | // Suggestions from https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration
31 | config.addDataSourceProperty("cachePrepStmts", "true");
32 | config.addDataSourceProperty("prepStmtCacheSize", "250");
33 | config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
34 | config.addDataSourceProperty("useServerPrepStmts", "true");
35 | config.addDataSourceProperty("useLocalSessionState", "true");
36 | config.addDataSourceProperty("rewriteBatchedStatements", "true");
37 | config.addDataSourceProperty("cacheResultSetMetadata", "true");
38 | config.addDataSourceProperty("cacheServerConfiguration", "true");
39 | config.addDataSourceProperty("elideSetAutoCommits", "true");
40 | config.addDataSourceProperty("maintainTimeStats", "false");
41 |
42 | config.validate()
43 | return HikariDataSource(config)
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/part2/src/test/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/resource/JokeResourceTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.resource
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.fake.JokeRepositoryFake
6 | import com.prof18.ktor.chucknorris.sample.testutils.appTestModule
7 | import com.prof18.ktor.chucknorris.sample.testutils.withTestServer
8 | import io.ktor.http.*
9 | import io.ktor.locations.*
10 | import io.ktor.server.testing.*
11 | import io.ktor.util.*
12 | import kotlinx.serialization.ExperimentalSerializationApi
13 | import kotlinx.serialization.decodeFromString
14 | import kotlinx.serialization.json.Json
15 | import org.junit.Assert.assertEquals
16 | import org.junit.Test
17 | import org.koin.dsl.module
18 | import org.koin.test.AutoCloseKoinTest
19 |
20 | @KtorExperimentalLocationsAPI
21 | class JokeResourceTest : AutoCloseKoinTest() {
22 |
23 | @ExperimentalSerializationApi
24 | @Test
25 | fun `random joke api works correctly`() = withTestServer(
26 | koinModules = appTestModule.plus(
27 | module {
28 | // Just to showcase the possibility, in this case this dependency can be put in the base test module
29 | single { JokeRepositoryFake() }
30 | }
31 | )
32 | ) {
33 |
34 | val href = application.locations.href(
35 | JokeEndpoint.Random(
36 | parent = JokeEndpoint()
37 | )
38 | )
39 |
40 | handleRequest(HttpMethod.Get, href).apply {
41 | assertEquals(HttpStatusCode.OK, response.status())
42 |
43 | val response = Json.decodeFromString(response.content!!)
44 |
45 | assertEquals("fake-id", response.jokeId)
46 | assertEquals("fake-content", response.jokeContent)
47 | }
48 | }
49 | }
--------------------------------------------------------------------------------
/part3/src/main/kotlin/com/prof18/ktor/chucknorris/sample/database/DatabaseFactoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.zaxxer.hikari.HikariConfig
5 | import com.zaxxer.hikari.HikariDataSource
6 | import io.ktor.config.*
7 | import org.jetbrains.exposed.sql.Database
8 |
9 | class DatabaseFactoryImpl(appConfig: AppConfig) : DatabaseFactory {
10 |
11 | private val dbConfig = appConfig.databaseConfig
12 |
13 | override fun close() {
14 | // not necessary
15 | }
16 |
17 | override fun connect() {
18 | Database.connect(hikari())
19 | }
20 |
21 | private fun hikari(): HikariDataSource {
22 | val config = HikariConfig()
23 | config.driverClassName = dbConfig.driverClass
24 | config.jdbcUrl = dbConfig.url
25 | config.username = dbConfig.user
26 | config.password = dbConfig.password
27 | config.maximumPoolSize = dbConfig.maxPoolSize
28 | config.isAutoCommit = false
29 | config.transactionIsolation = "TRANSACTION_REPEATABLE_READ"
30 |
31 | // Suggestions from https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration
32 | config.addDataSourceProperty("cachePrepStmts", "true");
33 | config.addDataSourceProperty("prepStmtCacheSize", "250");
34 | config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
35 | config.addDataSourceProperty("useServerPrepStmts", "true");
36 | config.addDataSourceProperty("useLocalSessionState", "true");
37 | config.addDataSourceProperty("rewriteBatchedStatements", "true");
38 | config.addDataSourceProperty("cacheResultSetMetadata", "true");
39 | config.addDataSourceProperty("cacheServerConfiguration", "true");
40 | config.addDataSourceProperty("elideSetAutoCommits", "true");
41 | config.addDataSourceProperty("maintainTimeStats", "false");
42 |
43 | config.validate()
44 | return HikariDataSource(config)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/part4/src/main/kotlin/com/prof18/ktor/chucknorris/sample/database/DatabaseFactoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.zaxxer.hikari.HikariConfig
5 | import com.zaxxer.hikari.HikariDataSource
6 | import io.ktor.config.*
7 | import org.jetbrains.exposed.sql.Database
8 |
9 | class DatabaseFactoryImpl(appConfig: AppConfig) : DatabaseFactory {
10 |
11 | private val dbConfig = appConfig.databaseConfig
12 |
13 | override fun close() {
14 | // not necessary
15 | }
16 |
17 | override fun connect() {
18 | Database.connect(hikari())
19 | }
20 |
21 | private fun hikari(): HikariDataSource {
22 | val config = HikariConfig()
23 | config.driverClassName = dbConfig.driverClass
24 | config.jdbcUrl = dbConfig.url
25 | config.username = dbConfig.user
26 | config.password = dbConfig.password
27 | config.maximumPoolSize = dbConfig.maxPoolSize
28 | config.isAutoCommit = false
29 | config.transactionIsolation = "TRANSACTION_REPEATABLE_READ"
30 |
31 | // Suggestions from https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration
32 | config.addDataSourceProperty("cachePrepStmts", "true");
33 | config.addDataSourceProperty("prepStmtCacheSize", "250");
34 | config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
35 | config.addDataSourceProperty("useServerPrepStmts", "true");
36 | config.addDataSourceProperty("useLocalSessionState", "true");
37 | config.addDataSourceProperty("rewriteBatchedStatements", "true");
38 | config.addDataSourceProperty("cacheResultSetMetadata", "true");
39 | config.addDataSourceProperty("cacheServerConfiguration", "true");
40 | config.addDataSourceProperty("elideSetAutoCommits", "true");
41 | config.addDataSourceProperty("maintainTimeStats", "false");
42 |
43 | config.validate()
44 | return HikariDataSource(config)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/part5/src/main/kotlin/com/prof18/ktor/chucknorris/sample/database/DatabaseFactoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.zaxxer.hikari.HikariConfig
5 | import com.zaxxer.hikari.HikariDataSource
6 | import io.ktor.config.*
7 | import org.jetbrains.exposed.sql.Database
8 |
9 | class DatabaseFactoryImpl(appConfig: AppConfig) : DatabaseFactory {
10 |
11 | private val dbConfig = appConfig.databaseConfig
12 |
13 | override fun close() {
14 | // not necessary
15 | }
16 |
17 | override fun connect() {
18 | Database.connect(hikari())
19 | }
20 |
21 | private fun hikari(): HikariDataSource {
22 | val config = HikariConfig()
23 | config.driverClassName = dbConfig.driverClass
24 | config.jdbcUrl = dbConfig.url
25 | config.username = dbConfig.user
26 | config.password = dbConfig.password
27 | config.maximumPoolSize = dbConfig.maxPoolSize
28 | config.isAutoCommit = false
29 | config.transactionIsolation = "TRANSACTION_REPEATABLE_READ"
30 |
31 | // Suggestions from https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration
32 | config.addDataSourceProperty("cachePrepStmts", "true");
33 | config.addDataSourceProperty("prepStmtCacheSize", "250");
34 | config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
35 | config.addDataSourceProperty("useServerPrepStmts", "true");
36 | config.addDataSourceProperty("useLocalSessionState", "true");
37 | config.addDataSourceProperty("rewriteBatchedStatements", "true");
38 | config.addDataSourceProperty("cacheResultSetMetadata", "true");
39 | config.addDataSourceProperty("cacheServerConfiguration", "true");
40 | config.addDataSourceProperty("elideSetAutoCommits", "true");
41 | config.addDataSourceProperty("maintainTimeStats", "false");
42 |
43 | config.validate()
44 | return HikariDataSource(config)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/part6/src/main/kotlin/com/prof18/ktor/chucknorris/sample/database/DatabaseFactoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.zaxxer.hikari.HikariConfig
5 | import com.zaxxer.hikari.HikariDataSource
6 | import io.ktor.config.*
7 | import org.jetbrains.exposed.sql.Database
8 |
9 | class DatabaseFactoryImpl(appConfig: AppConfig) : DatabaseFactory {
10 |
11 | private val dbConfig = appConfig.databaseConfig
12 |
13 | override fun close() {
14 | // not necessary
15 | }
16 |
17 | override fun connect() {
18 | Database.connect(hikari())
19 | }
20 |
21 | private fun hikari(): HikariDataSource {
22 | val config = HikariConfig()
23 | config.driverClassName = dbConfig.driverClass
24 | config.jdbcUrl = dbConfig.url
25 | config.username = dbConfig.user
26 | config.password = dbConfig.password
27 | config.maximumPoolSize = dbConfig.maxPoolSize
28 | config.isAutoCommit = false
29 | config.transactionIsolation = "TRANSACTION_REPEATABLE_READ"
30 |
31 | // Suggestions from https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration
32 | config.addDataSourceProperty("cachePrepStmts", "true");
33 | config.addDataSourceProperty("prepStmtCacheSize", "250");
34 | config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
35 | config.addDataSourceProperty("useServerPrepStmts", "true");
36 | config.addDataSourceProperty("useLocalSessionState", "true");
37 | config.addDataSourceProperty("rewriteBatchedStatements", "true");
38 | config.addDataSourceProperty("cacheResultSetMetadata", "true");
39 | config.addDataSourceProperty("cacheServerConfiguration", "true");
40 | config.addDataSourceProperty("elideSetAutoCommits", "true");
41 | config.addDataSourceProperty("maintainTimeStats", "false");
42 |
43 | config.validate()
44 | return HikariDataSource(config)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/database/DatabaseFactoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.database
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import com.zaxxer.hikari.HikariConfig
5 | import com.zaxxer.hikari.HikariDataSource
6 | import io.ktor.config.*
7 | import org.jetbrains.exposed.sql.Database
8 |
9 | class DatabaseFactoryImpl(appConfig: AppConfig) : DatabaseFactory {
10 |
11 | private val dbConfig = appConfig.databaseConfig
12 |
13 | override fun close() {
14 | // not necessary
15 | }
16 |
17 | override fun connect() {
18 | Database.connect(hikari())
19 | }
20 |
21 | private fun hikari(): HikariDataSource {
22 | val config = HikariConfig()
23 | config.driverClassName = dbConfig.driverClass
24 | config.jdbcUrl = dbConfig.url
25 | config.username = dbConfig.user
26 | config.password = dbConfig.password
27 | config.maximumPoolSize = dbConfig.maxPoolSize
28 | config.isAutoCommit = false
29 | config.transactionIsolation = "TRANSACTION_REPEATABLE_READ"
30 |
31 | // Suggestions from https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration
32 | config.addDataSourceProperty("cachePrepStmts", "true");
33 | config.addDataSourceProperty("prepStmtCacheSize", "250");
34 | config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
35 | config.addDataSourceProperty("useServerPrepStmts", "true");
36 | config.addDataSourceProperty("useLocalSessionState", "true");
37 | config.addDataSourceProperty("rewriteBatchedStatements", "true");
38 | config.addDataSourceProperty("cacheResultSetMetadata", "true");
39 | config.addDataSourceProperty("cacheServerConfiguration", "true");
40 | config.addDataSourceProperty("elideSetAutoCommits", "true");
41 | config.addDataSourceProperty("maintainTimeStats", "false");
42 |
43 | config.validate()
44 | return HikariDataSource(config)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ktor-2.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/jobs/JobSchedulerManager.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.jobs
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import org.quartz.Scheduler
5 | import org.quartz.SchedulerFactory
6 | import org.quartz.impl.StdSchedulerFactory
7 | import java.util.*
8 |
9 | class JobSchedulerManager(appConfig: AppConfig) {
10 |
11 | var scheduler: Scheduler
12 |
13 | init {
14 | val databaseConfig = appConfig.databaseConfig
15 |
16 | val props = Properties()
17 | props["org.quartz.scheduler.instanceName"] = "ChuckNorrisScheduler"
18 | props["org.quartz.threadPool.threadCount"] = "3"
19 |
20 | props["org.quartz.jobStore.dataSource"] = "mySql"
21 | props["org.quartz.dataSource.mySql.driver"] = databaseConfig.driverClass
22 | props["org.quartz.dataSource.mySql.URL"] = databaseConfig.url
23 | props["org.quartz.dataSource.mySql.user"] = databaseConfig.user
24 | props["org.quartz.dataSource.mySql.password"] = databaseConfig.password
25 | props["org.quartz.dataSource.mySql.maxConnections"] = "10"
26 |
27 | props["org.quartz.jobStore.class"] = "org.quartz.impl.jdbcjobstore.JobStoreTX"
28 | props["org.quartz.jobStore.driverDelegateClass"] = "org.quartz.impl.jdbcjobstore.StdJDBCDelegate"
29 | props["org.quartz.jobStore.tablePrefix"] = "QRTZ_"
30 |
31 |
32 | props["org.quartz.plugin.triggHistory.class"] = "org.quartz.plugins.history.LoggingTriggerHistoryPlugin"
33 | props["org.quartz.plugin.triggHistory.triggerFiredMessage"] = """Trigger {1}.{0} fired job {6}.{5} at: {4, date, HH:mm:ss MM/dd/yyyy}"""
34 | props["org.quartz.plugin.triggHistory.triggerCompleteMessage"] = """Trigger {1}.{0} completed firing job {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy}"""
35 |
36 | val schedulerFactory: SchedulerFactory = StdSchedulerFactory(props)
37 | scheduler = schedulerFactory.scheduler
38 | }
39 |
40 | fun startScheduler() {
41 | scheduler.start()
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/part6/src/main/kotlin/com/prof18/ktor/chucknorris/sample/jobs/JobSchedulerManager.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.jobs
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import org.quartz.Scheduler
5 | import org.quartz.SchedulerFactory
6 | import org.quartz.impl.StdSchedulerFactory
7 | import java.util.*
8 |
9 | class JobSchedulerManager(appConfig: AppConfig) {
10 |
11 | var scheduler: Scheduler
12 |
13 | init {
14 | val databaseConfig = appConfig.databaseConfig
15 |
16 | val props = Properties()
17 | props["org.quartz.scheduler.instanceName"] = "ChuckNorrisScheduler"
18 | props["org.quartz.threadPool.threadCount"] = "3"
19 |
20 | props["org.quartz.jobStore.dataSource"] = "mySql"
21 | props["org.quartz.dataSource.mySql.driver"] = databaseConfig.driverClass
22 | props["org.quartz.dataSource.mySql.URL"] = databaseConfig.url
23 | props["org.quartz.dataSource.mySql.user"] = databaseConfig.user
24 | props["org.quartz.dataSource.mySql.password"] = databaseConfig.password
25 | props["org.quartz.dataSource.mySql.maxConnections"] = "10"
26 |
27 | props["org.quartz.jobStore.class"] = "org.quartz.impl.jdbcjobstore.JobStoreTX"
28 | props["org.quartz.jobStore.driverDelegateClass"] = "org.quartz.impl.jdbcjobstore.StdJDBCDelegate"
29 | props["org.quartz.jobStore.tablePrefix"] = "QRTZ_"
30 |
31 |
32 | props["org.quartz.plugin.triggHistory.class"] = "org.quartz.plugins.history.LoggingTriggerHistoryPlugin"
33 | props["org.quartz.plugin.triggHistory.triggerFiredMessage"] = """Trigger {1}.{0} fired job {6}.{5} at: {4, date, HH:mm:ss MM/dd/yyyy}"""
34 | props["org.quartz.plugin.triggHistory.triggerCompleteMessage"] = """Trigger {1}.{0} completed firing job {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy}"""
35 |
36 | val schedulerFactory: SchedulerFactory = StdSchedulerFactory(props)
37 | scheduler = schedulerFactory.scheduler
38 | }
39 |
40 | fun startScheduler() {
41 | scheduler.start()
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/jobs/JobSchedulerManager.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.jobs
2 |
3 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
4 | import org.quartz.Scheduler
5 | import org.quartz.SchedulerFactory
6 | import org.quartz.impl.StdSchedulerFactory
7 | import java.util.*
8 |
9 | class JobSchedulerManager(appConfig: AppConfig) {
10 |
11 | var scheduler: Scheduler
12 |
13 | init {
14 | val databaseConfig = appConfig.databaseConfig
15 |
16 | val props = Properties()
17 | props["org.quartz.scheduler.instanceName"] = "ChuckNorrisScheduler"
18 | props["org.quartz.threadPool.threadCount"] = "3"
19 |
20 | props["org.quartz.jobStore.dataSource"] = "mySql"
21 | props["org.quartz.dataSource.mySql.driver"] = databaseConfig.driverClass
22 | props["org.quartz.dataSource.mySql.URL"] = databaseConfig.url
23 | props["org.quartz.dataSource.mySql.user"] = databaseConfig.user
24 | props["org.quartz.dataSource.mySql.password"] = databaseConfig.password
25 | props["org.quartz.dataSource.mySql.maxConnections"] = "10"
26 |
27 | props["org.quartz.jobStore.class"] = "org.quartz.impl.jdbcjobstore.JobStoreTX"
28 | props["org.quartz.jobStore.driverDelegateClass"] = "org.quartz.impl.jdbcjobstore.StdJDBCDelegate"
29 | props["org.quartz.jobStore.tablePrefix"] = "QRTZ_"
30 |
31 |
32 | props["org.quartz.plugin.triggHistory.class"] = "org.quartz.plugins.history.LoggingTriggerHistoryPlugin"
33 | props["org.quartz.plugin.triggHistory.triggerFiredMessage"] = """Trigger {1}.{0} fired job {6}.{5} at: {4, date, HH:mm:ss MM/dd/yyyy}"""
34 | props["org.quartz.plugin.triggHistory.triggerCompleteMessage"] = """Trigger {1}.{0} completed firing job {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy}"""
35 |
36 | val schedulerFactory: SchedulerFactory = StdSchedulerFactory(props)
37 | scheduler = schedulerFactory.scheduler
38 | }
39 |
40 | fun startScheduler() {
41 | scheduler.start()
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ktor Chuck Norris Sample
2 |
3 | A [Ktor](http://ktor.io) sample project that returns Random Chuck Norris jokes.
4 |
5 | This project contains all the code used in some articles published on my website.
6 |
7 | ## 1. Structuring a Ktor project
8 |
9 | - Article: https://www.marcogomiero.com/posts/2021/ktor-project-structure/
10 | - Code: [part1 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part1)
11 |
12 | ## 2. How to persist Ktor logs
13 |
14 | - Article: https://www.marcogomiero.com/posts/2021/ktor-logging-on-disk/
15 | - Code: [part2 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part2)
16 |
17 | ## 3. How to use an in-memory database for testing on Ktor
18 |
19 | - Article: https://www.marcogomiero.com/posts/2021/ktor-in-memory-db-testing/
20 | - Code: [part3 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part3)
21 |
22 | ## 4. How to handle database migrations with Liquibase on Ktor
23 |
24 | - Article: https://www.marcogomiero.com/posts/2022/ktor-migration-liquibase/
25 | - Code: [part4 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part4)
26 |
27 | ## 5. Generate API documentation from Swagger on Ktor
28 |
29 | - Article: https://www.marcogomiero.com/posts/2022/ktor-setup-documentation/
30 | - Code: [part5 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part5)
31 |
32 | ## 6. How to schedule jobs with Quartz on Ktor
33 |
34 | - Article: https://www.marcogomiero.com/posts/2022/ktor-jobs-quartz/
35 | - Code: [part6 folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/part6)
36 |
37 | ## Ktor 1.6.x
38 |
39 | In the [ktor-1.6.x folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/ktor-1.6.x), the entire project is implemented with Ktor 1.6.x.
40 |
41 | ## Ktor 2.x
42 |
43 | In the [ktor-2.x folder](https://github.com/prof18/ktor-chuck-norris-sample/tree/main/ktor-2.x), the entire project is implemented with Ktor 1.6.x.
44 |
45 | ---
46 |
47 | The data used for the databases are from the [Chuck Norris IO](https://github.com/chucknorris-io/chuck-db) project.
48 |
--------------------------------------------------------------------------------
/part1/src/main/kotlin/com/prof18/ktor/chucknorris/sample/Application.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample
2 |
3 | import ch.qos.logback.classic.Logger
4 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
5 | import com.prof18.ktor.chucknorris.sample.config.setupConfig
6 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
7 | import com.prof18.ktor.chucknorris.sample.di.appModule
8 | import com.prof18.ktor.chucknorris.sample.features.jokes.resource.jokeEndpoint
9 | import io.ktor.application.*
10 | import io.ktor.features.*
11 | import io.ktor.http.content.*
12 | import io.ktor.locations.*
13 | import io.ktor.response.*
14 | import io.ktor.routing.*
15 | import io.ktor.serialization.*
16 | import org.koin.core.module.Module
17 | import org.koin.ktor.ext.Koin
18 | import org.koin.ktor.ext.inject
19 | import org.koin.logger.slf4jLogger
20 | import org.slf4j.LoggerFactory
21 | import org.slf4j.event.Level
22 |
23 | fun main(args: Array): Unit =
24 | io.ktor.server.netty.EngineMain.main(args)
25 |
26 | /**
27 | * Please note that you can use any other name instead of *module*.
28 | * Also note that you can have more then one modules in your application.
29 | * */
30 | @KtorExperimentalLocationsAPI
31 | @Suppress("unused") // Referenced in application.conf
32 | @kotlin.jvm.JvmOverloads
33 | fun Application.module(testing: Boolean = false, koinModules: List = listOf(appModule)) {
34 |
35 | install(Koin) {
36 | slf4jLogger()
37 | modules(koinModules)
38 | }
39 |
40 | setupConfig()
41 |
42 | val appConfig by inject()
43 |
44 | if (!appConfig.serverConfig.isProd) {
45 | val root = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME) as Logger
46 | root.level = ch.qos.logback.classic.Level.TRACE
47 | }
48 |
49 | install(ContentNegotiation) {
50 | json()
51 | }
52 |
53 | install(CallLogging) {
54 | level = Level.INFO
55 | }
56 |
57 | install(Locations)
58 |
59 | routing {
60 | jokeEndpoint()
61 | get("/") {
62 | call.respondText("This is a sample Ktor backend to get Chuck Norris jokes")
63 | }
64 | }
65 | }
66 |
67 |
68 |
--------------------------------------------------------------------------------
/part2/src/main/kotlin/com/prof18/ktor/chucknorris/sample/Application.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample
2 |
3 | import ch.qos.logback.classic.Logger
4 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
5 | import com.prof18.ktor.chucknorris.sample.config.setupConfig
6 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
7 | import com.prof18.ktor.chucknorris.sample.di.appModule
8 | import com.prof18.ktor.chucknorris.sample.features.jokes.resource.jokeEndpoint
9 | import io.ktor.application.*
10 | import io.ktor.features.*
11 | import io.ktor.http.content.*
12 | import io.ktor.locations.*
13 | import io.ktor.response.*
14 | import io.ktor.routing.*
15 | import io.ktor.serialization.*
16 | import org.koin.core.module.Module
17 | import org.koin.ktor.ext.Koin
18 | import org.koin.ktor.ext.inject
19 | import org.koin.logger.slf4jLogger
20 | import org.slf4j.LoggerFactory
21 | import org.slf4j.event.Level
22 |
23 | fun main(args: Array): Unit =
24 | io.ktor.server.netty.EngineMain.main(args)
25 |
26 | /**
27 | * Please note that you can use any other name instead of *module*.
28 | * Also note that you can have more then one modules in your application.
29 | * */
30 | @KtorExperimentalLocationsAPI
31 | @Suppress("unused") // Referenced in application.conf
32 | @kotlin.jvm.JvmOverloads
33 | fun Application.module(testing: Boolean = false, koinModules: List = listOf(appModule)) {
34 |
35 | install(Koin) {
36 | slf4jLogger()
37 | modules(koinModules)
38 | }
39 |
40 | setupConfig()
41 |
42 | val appConfig by inject()
43 |
44 | if (!appConfig.serverConfig.isProd) {
45 | val root = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME) as Logger
46 | root.level = ch.qos.logback.classic.Level.TRACE
47 | }
48 |
49 | install(ContentNegotiation) {
50 | json()
51 | }
52 |
53 | install(CallLogging) {
54 | level = Level.INFO
55 | }
56 |
57 | install(Locations)
58 |
59 | routing {
60 | jokeEndpoint()
61 | get("/") {
62 | call.respondText("This is a sample Ktor backend to get Chuck Norris jokes")
63 | }
64 | }
65 | }
66 |
67 |
68 |
--------------------------------------------------------------------------------
/ktor-2.x/src/test/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/resource/JokeResourceTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.resource
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepositoryImpl
6 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
7 | import com.prof18.ktor.chucknorris.sample.testutils.appTestModule
8 | import com.prof18.ktor.chucknorris.sample.testutils.withTestServer
9 | import io.ktor.client.call.body
10 | import io.ktor.client.request.get
11 | import io.ktor.http.HttpStatusCode
12 | import kotlinx.serialization.ExperimentalSerializationApi
13 | import kotlinx.serialization.decodeFromString
14 | import kotlinx.serialization.json.Json
15 | import org.jetbrains.exposed.sql.transactions.transaction
16 | import org.junit.Assert.assertEquals
17 | import org.junit.Test
18 | import org.koin.dsl.module
19 | import org.koin.test.AutoCloseKoinTest
20 | import java.time.LocalDateTime
21 |
22 | @ExperimentalSerializationApi
23 | class JokeResourceTest : AutoCloseKoinTest() {
24 |
25 | @Test
26 | fun `random joke api works correctly`() = withTestServer(
27 | koinModules = appTestModule.plus(
28 | module {
29 | // Just to showcase the possibility, in this case this dependency can be put in the base test module
30 | single { JokeRepositoryImpl(get(), get()) }
31 | }
32 | )
33 | ) { client ->
34 | // Setup
35 | val joke = transaction {
36 | Joke.new("joke_1") {
37 | this.value = "Chuck Norris tests are always green"
38 | this.createdAt = LocalDateTime.now()
39 | this.updatedAt = LocalDateTime.now()
40 | }
41 | }
42 |
43 | val response = client.get("/joke/random")
44 | assertEquals(HttpStatusCode.OK, response.status)
45 |
46 | val jokeDto = Json.decodeFromString(response.body())
47 |
48 | assertEquals(transaction { joke.id.value }, jokeDto.jokeId)
49 | assertEquals(transaction { joke.value }, jokeDto.jokeContent)
50 | }
51 | }
--------------------------------------------------------------------------------
/part3/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
2 |
3 | val ktor_version: String by project
4 | val kotlin_version: String by project
5 | val logback_version: String by project
6 | val exposed_version: String by project
7 | val mysql_connector_version: String by project
8 | val hikaricp_version: String by project
9 | val h2_version: String by project
10 | val koin_version: String by project
11 |
12 | plugins {
13 | application
14 | kotlin("jvm") version "1.5.30"
15 | id("org.jetbrains.kotlin.plugin.serialization") version "1.5.30"
16 | }
17 |
18 | group = "com.prof18.ktor.chucknorris.sample"
19 | version = "0.0.1"
20 | application {
21 | mainClass.set("io.ktor.server.netty.EngineMain")
22 | }
23 |
24 | repositories {
25 | mavenCentral()
26 | }
27 |
28 | tasks.withType().all {
29 | kotlinOptions {
30 | jvmTarget = "11"
31 | }
32 | }
33 |
34 | dependencies {
35 | implementation("io.ktor:ktor-server-core:$ktor_version")
36 | implementation("io.ktor:ktor-serialization:$ktor_version")
37 | implementation("io.ktor:ktor-server-host-common:$ktor_version")
38 | implementation("io.ktor:ktor-server-netty:$ktor_version")
39 | implementation("io.ktor:ktor-locations:$ktor_version")
40 | implementation("ch.qos.logback:logback-classic:$logback_version")
41 |
42 | // Database
43 | implementation("org.jetbrains.exposed:exposed-core:$exposed_version")
44 | implementation("org.jetbrains.exposed:exposed-dao:$exposed_version")
45 | implementation("org.jetbrains.exposed:exposed-jdbc:$exposed_version")
46 | implementation("org.jetbrains.exposed:exposed-java-time:$exposed_version")
47 | implementation("mysql:mysql-connector-java:$mysql_connector_version")
48 | implementation("com.zaxxer:HikariCP:$hikaricp_version")
49 |
50 | // Koin
51 | implementation("io.insert-koin:koin-ktor:$koin_version")
52 | implementation("io.insert-koin:koin-logger-slf4j:$koin_version")
53 |
54 | // Testing
55 | testImplementation("io.ktor:ktor-server-tests:$ktor_version")
56 | testImplementation("com.h2database:h2:$h2_version")
57 | testImplementation("io.insert-koin:koin-test:$koin_version")
58 | testImplementation("io.insert-koin:koin-test-junit4:$koin_version")
59 | testImplementation("junit:junit:4.12")
60 |
61 | }
--------------------------------------------------------------------------------
/part3/src/test/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepositoryImplTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSource
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSourceImpl
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
6 | import com.prof18.ktor.chucknorris.sample.testutils.database.DatabaseFactoryForUnitTest
7 | import kotlinx.coroutines.runBlocking
8 | import org.jetbrains.exposed.sql.transactions.transaction
9 | import org.junit.After
10 | import org.junit.Assert.assertEquals
11 | import org.junit.Before
12 | import org.junit.Rule
13 | import org.junit.Test
14 | import org.koin.dsl.module
15 | import org.koin.test.KoinTest
16 | import org.koin.test.KoinTestRule
17 | import org.koin.test.inject
18 | import java.time.LocalDateTime
19 |
20 | class JokeRepositoryImplTest : KoinTest {
21 |
22 | private lateinit var databaseFactory: DatabaseFactoryForUnitTest
23 |
24 | @get:Rule
25 | val koinTestRule = KoinTestRule.create {
26 | // Your KoinApplication instance here
27 | modules(module {
28 | single { JokeLocalDataSourceImpl() }
29 | single { JokeRepositoryImpl(get()) }
30 | })
31 | }
32 |
33 | private val jokeRepository: JokeRepository by inject()
34 |
35 | @Before
36 | fun setup() {
37 | databaseFactory = DatabaseFactoryForUnitTest()
38 | databaseFactory.connect()
39 | }
40 |
41 | @After
42 | fun tearDown() {
43 | databaseFactory.close()
44 | }
45 |
46 | @Test
47 | fun `getRandomJoke returns data correctly`() = runBlocking {
48 | // Setup
49 | val joke = transaction {
50 | Joke.new("joke_1") {
51 | this.value = "Chuck Norris tests are always green"
52 | this.createdAt = LocalDateTime.now()
53 | this.updatedAt = LocalDateTime.now()
54 | }
55 | }
56 |
57 | // Act
58 | val randomJoke = jokeRepository.getRandomJoke()
59 |
60 | // Assert
61 | assertEquals(transaction { joke.id.value }, randomJoke.jokeId)
62 | assertEquals(transaction { joke.value }, randomJoke.jokeContent)
63 | }
64 | }
--------------------------------------------------------------------------------
/part4/src/test/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepositoryImplTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSource
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSourceImpl
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
6 | import com.prof18.ktor.chucknorris.sample.testutils.database.DatabaseFactoryForUnitTest
7 | import kotlinx.coroutines.runBlocking
8 | import org.jetbrains.exposed.sql.transactions.transaction
9 | import org.junit.After
10 | import org.junit.Assert.assertEquals
11 | import org.junit.Before
12 | import org.junit.Rule
13 | import org.junit.Test
14 | import org.koin.dsl.module
15 | import org.koin.test.KoinTest
16 | import org.koin.test.KoinTestRule
17 | import org.koin.test.inject
18 | import java.time.LocalDateTime
19 |
20 | class JokeRepositoryImplTest : KoinTest {
21 |
22 | private lateinit var databaseFactory: DatabaseFactoryForUnitTest
23 |
24 | @get:Rule
25 | val koinTestRule = KoinTestRule.create {
26 | // Your KoinApplication instance here
27 | modules(module {
28 | single { JokeLocalDataSourceImpl() }
29 | single { JokeRepositoryImpl(get()) }
30 | })
31 | }
32 |
33 | private val jokeRepository: JokeRepository by inject()
34 |
35 | @Before
36 | fun setup() {
37 | databaseFactory = DatabaseFactoryForUnitTest()
38 | databaseFactory.connect()
39 | }
40 |
41 | @After
42 | fun tearDown() {
43 | databaseFactory.close()
44 | }
45 |
46 | @Test
47 | fun `getRandomJoke returns data correctly`() = runBlocking {
48 | // Setup
49 | val joke = transaction {
50 | Joke.new("joke_1") {
51 | this.value = "Chuck Norris tests are always green"
52 | this.createdAt = LocalDateTime.now()
53 | this.updatedAt = LocalDateTime.now()
54 | }
55 | }
56 |
57 | // Act
58 | val randomJoke = jokeRepository.getRandomJoke()
59 |
60 | // Assert
61 | assertEquals(transaction { joke.id.value }, randomJoke.jokeId)
62 | assertEquals(transaction { joke.value }, randomJoke.jokeContent)
63 | }
64 | }
--------------------------------------------------------------------------------
/part5/src/test/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepositoryImplTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSource
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSourceImpl
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
6 | import com.prof18.ktor.chucknorris.sample.testutils.database.DatabaseFactoryForUnitTest
7 | import kotlinx.coroutines.runBlocking
8 | import org.jetbrains.exposed.sql.transactions.transaction
9 | import org.junit.After
10 | import org.junit.Assert.assertEquals
11 | import org.junit.Before
12 | import org.junit.Rule
13 | import org.junit.Test
14 | import org.koin.dsl.module
15 | import org.koin.test.KoinTest
16 | import org.koin.test.KoinTestRule
17 | import org.koin.test.inject
18 | import java.time.LocalDateTime
19 |
20 | class JokeRepositoryImplTest : KoinTest {
21 |
22 | private lateinit var databaseFactory: DatabaseFactoryForUnitTest
23 |
24 | @get:Rule
25 | val koinTestRule = KoinTestRule.create {
26 | // Your KoinApplication instance here
27 | modules(module {
28 | single { JokeLocalDataSourceImpl() }
29 | single { JokeRepositoryImpl(get()) }
30 | })
31 | }
32 |
33 | private val jokeRepository: JokeRepository by inject()
34 |
35 | @Before
36 | fun setup() {
37 | databaseFactory = DatabaseFactoryForUnitTest()
38 | databaseFactory.connect()
39 | }
40 |
41 | @After
42 | fun tearDown() {
43 | databaseFactory.close()
44 | }
45 |
46 | @Test
47 | fun `getRandomJoke returns data correctly`() = runBlocking {
48 | // Setup
49 | val joke = transaction {
50 | Joke.new("joke_1") {
51 | this.value = "Chuck Norris tests are always green"
52 | this.createdAt = LocalDateTime.now()
53 | this.updatedAt = LocalDateTime.now()
54 | }
55 | }
56 |
57 | // Act
58 | val randomJoke = jokeRepository.getRandomJoke()
59 |
60 | // Assert
61 | assertEquals(transaction { joke.id.value }, randomJoke.jokeId)
62 | assertEquals(transaction { joke.value }, randomJoke.jokeContent)
63 | }
64 | }
--------------------------------------------------------------------------------
/part3/src/main/kotlin/com/prof18/ktor/chucknorris/sample/Application.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample
2 |
3 | import ch.qos.logback.classic.Logger
4 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
5 | import com.prof18.ktor.chucknorris.sample.config.setupConfig
6 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
7 | import com.prof18.ktor.chucknorris.sample.di.appModule
8 | import com.prof18.ktor.chucknorris.sample.features.jokes.resource.jokeEndpoint
9 | import io.ktor.application.*
10 | import io.ktor.features.*
11 | import io.ktor.http.content.*
12 | import io.ktor.locations.*
13 | import io.ktor.response.*
14 | import io.ktor.routing.*
15 | import io.ktor.serialization.*
16 | import org.koin.core.module.Module
17 | import org.koin.ktor.ext.Koin
18 | import org.koin.ktor.ext.inject
19 | import org.koin.logger.slf4jLogger
20 | import org.slf4j.LoggerFactory
21 | import org.slf4j.event.Level
22 | // /Users/marco/Workspace/Examples/ktor-chuck-norris-sample
23 | // VM Options -DLOG_DEST=/Users/marco/Workspace/Examples/ktor-chuck-norris-sample/logs -DLOG_MAX_HISTORY=2
24 | fun main(args: Array): Unit =
25 | io.ktor.server.netty.EngineMain.main(args)
26 |
27 | /**
28 | * Please note that you can use any other name instead of *module*.
29 | * Also note that you can have more then one modules in your application.
30 | * */
31 | @KtorExperimentalLocationsAPI
32 | @Suppress("unused") // Referenced in application.conf
33 | @kotlin.jvm.JvmOverloads
34 | fun Application.module(testing: Boolean = false, koinModules: List = listOf(appModule)) {
35 |
36 | install(Koin) {
37 | slf4jLogger()
38 | modules(koinModules)
39 | }
40 |
41 | setupConfig()
42 |
43 | val appConfig by inject()
44 |
45 | if (!appConfig.serverConfig.isProd) {
46 | val root = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME) as Logger
47 | root.level = ch.qos.logback.classic.Level.TRACE
48 | }
49 |
50 | val databaseFactory by inject()
51 | databaseFactory.connect()
52 |
53 | install(ContentNegotiation) {
54 | json()
55 | }
56 |
57 | install(CallLogging) {
58 | level = Level.INFO
59 | }
60 |
61 | install(Locations)
62 |
63 | routing {
64 | jokeEndpoint()
65 | get("/") {
66 | call.respondText("This is a sample Ktor backend to get Chuck Norris jokes")
67 | }
68 | }
69 | }
70 |
71 |
72 |
--------------------------------------------------------------------------------
/part4/src/main/kotlin/com/prof18/ktor/chucknorris/sample/Application.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample
2 |
3 | import ch.qos.logback.classic.Logger
4 | import com.prof18.ktor.chucknorris.sample.config.AppConfig
5 | import com.prof18.ktor.chucknorris.sample.config.setupConfig
6 | import com.prof18.ktor.chucknorris.sample.database.DatabaseFactory
7 | import com.prof18.ktor.chucknorris.sample.di.appModule
8 | import com.prof18.ktor.chucknorris.sample.features.jokes.resource.jokeEndpoint
9 | import io.ktor.application.*
10 | import io.ktor.features.*
11 | import io.ktor.http.content.*
12 | import io.ktor.locations.*
13 | import io.ktor.response.*
14 | import io.ktor.routing.*
15 | import io.ktor.serialization.*
16 | import org.koin.core.module.Module
17 | import org.koin.ktor.ext.Koin
18 | import org.koin.ktor.ext.inject
19 | import org.koin.logger.slf4jLogger
20 | import org.slf4j.LoggerFactory
21 | import org.slf4j.event.Level
22 | // /Users/marco/Workspace/Examples/ktor-chuck-norris-sample
23 | // VM Options -DLOG_DEST=/Users/marco/Workspace/Examples/ktor-chuck-norris-sample/logs -DLOG_MAX_HISTORY=2
24 | fun main(args: Array): Unit =
25 | io.ktor.server.netty.EngineMain.main(args)
26 |
27 | /**
28 | * Please note that you can use any other name instead of *module*.
29 | * Also note that you can have more then one modules in your application.
30 | * */
31 | @KtorExperimentalLocationsAPI
32 | @Suppress("unused") // Referenced in application.conf
33 | @kotlin.jvm.JvmOverloads
34 | fun Application.module(testing: Boolean = false, koinModules: List = listOf(appModule)) {
35 |
36 | install(Koin) {
37 | slf4jLogger()
38 | modules(koinModules)
39 | }
40 |
41 | setupConfig()
42 |
43 | val appConfig by inject()
44 |
45 | if (!appConfig.serverConfig.isProd) {
46 | val root = LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME) as Logger
47 | root.level = ch.qos.logback.classic.Level.TRACE
48 | }
49 |
50 | val databaseFactory by inject()
51 | databaseFactory.connect()
52 |
53 | install(ContentNegotiation) {
54 | json()
55 | }
56 |
57 | install(CallLogging) {
58 | level = Level.INFO
59 | }
60 |
61 | install(Locations)
62 |
63 | routing {
64 | jokeEndpoint()
65 | get("/") {
66 | call.respondText("This is a sample Ktor backend to get Chuck Norris jokes")
67 | }
68 | }
69 | }
70 |
71 |
72 |
--------------------------------------------------------------------------------
/part3/src/test/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/resource/JokeResourceTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.resource
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepositoryImpl
6 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
7 | import com.prof18.ktor.chucknorris.sample.testutils.appTestModule
8 | import com.prof18.ktor.chucknorris.sample.testutils.withTestServer
9 | import io.ktor.http.*
10 | import io.ktor.locations.*
11 | import io.ktor.server.testing.*
12 | import kotlinx.serialization.ExperimentalSerializationApi
13 | import kotlinx.serialization.decodeFromString
14 | import kotlinx.serialization.json.Json
15 | import org.jetbrains.exposed.sql.transactions.transaction
16 | import org.junit.Assert.assertEquals
17 | import org.junit.Test
18 | import org.koin.dsl.module
19 | import org.koin.test.AutoCloseKoinTest
20 | import java.time.LocalDateTime
21 |
22 | @KtorExperimentalLocationsAPI
23 | @ExperimentalSerializationApi
24 | class JokeResourceTest : AutoCloseKoinTest() {
25 |
26 | @Test
27 | fun `random joke api works correctly`() = withTestServer(
28 | koinModules = appTestModule.plus(
29 | module {
30 | // Just to showcase the possibility, in this case this dependency can be put in the base test module
31 | single { JokeRepositoryImpl(get()) }
32 | }
33 | )
34 | ) {
35 |
36 | // Setup
37 | val joke = transaction {
38 | Joke.new("joke_1") {
39 | this.value = "Chuck Norris tests are always green"
40 | this.createdAt = LocalDateTime.now()
41 | this.updatedAt = LocalDateTime.now()
42 | }
43 | }
44 |
45 | val href = application.locations.href(
46 | JokeEndpoint.Random(
47 | parent = JokeEndpoint()
48 | )
49 | )
50 |
51 | handleRequest(HttpMethod.Get, href).apply {
52 | assertEquals(HttpStatusCode.OK, response.status())
53 |
54 | val response = Json.decodeFromString(response.content!!)
55 |
56 | assertEquals(transaction { joke.id.value }, response.jokeId)
57 | assertEquals(transaction { joke.value }, response.jokeContent)
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/part4/src/test/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/resource/JokeResourceTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.resource
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepositoryImpl
6 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
7 | import com.prof18.ktor.chucknorris.sample.testutils.appTestModule
8 | import com.prof18.ktor.chucknorris.sample.testutils.withTestServer
9 | import io.ktor.http.*
10 | import io.ktor.locations.*
11 | import io.ktor.server.testing.*
12 | import kotlinx.serialization.ExperimentalSerializationApi
13 | import kotlinx.serialization.decodeFromString
14 | import kotlinx.serialization.json.Json
15 | import org.jetbrains.exposed.sql.transactions.transaction
16 | import org.junit.Assert.assertEquals
17 | import org.junit.Test
18 | import org.koin.dsl.module
19 | import org.koin.test.AutoCloseKoinTest
20 | import java.time.LocalDateTime
21 |
22 | @KtorExperimentalLocationsAPI
23 | @ExperimentalSerializationApi
24 | class JokeResourceTest : AutoCloseKoinTest() {
25 |
26 | @Test
27 | fun `random joke api works correctly`() = withTestServer(
28 | koinModules = appTestModule.plus(
29 | module {
30 | // Just to showcase the possibility, in this case this dependency can be put in the base test module
31 | single { JokeRepositoryImpl(get()) }
32 | }
33 | )
34 | ) {
35 |
36 | // Setup
37 | val joke = transaction {
38 | Joke.new("joke_1") {
39 | this.value = "Chuck Norris tests are always green"
40 | this.createdAt = LocalDateTime.now()
41 | this.updatedAt = LocalDateTime.now()
42 | }
43 | }
44 |
45 | val href = application.locations.href(
46 | JokeEndpoint.Random(
47 | parent = JokeEndpoint()
48 | )
49 | )
50 |
51 | handleRequest(HttpMethod.Get, href).apply {
52 | assertEquals(HttpStatusCode.OK, response.status())
53 |
54 | val response = Json.decodeFromString(response.content!!)
55 |
56 | assertEquals(transaction { joke.id.value }, response.jokeId)
57 | assertEquals(transaction { joke.value }, response.jokeContent)
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/part5/src/test/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/resource/JokeResourceTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.resource
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.dao.Joke
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepository
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.JokeRepositoryImpl
6 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
7 | import com.prof18.ktor.chucknorris.sample.testutils.appTestModule
8 | import com.prof18.ktor.chucknorris.sample.testutils.withTestServer
9 | import io.ktor.http.*
10 | import io.ktor.locations.*
11 | import io.ktor.server.testing.*
12 | import kotlinx.serialization.ExperimentalSerializationApi
13 | import kotlinx.serialization.decodeFromString
14 | import kotlinx.serialization.json.Json
15 | import org.jetbrains.exposed.sql.transactions.transaction
16 | import org.junit.Assert.assertEquals
17 | import org.junit.Test
18 | import org.koin.dsl.module
19 | import org.koin.test.AutoCloseKoinTest
20 | import java.time.LocalDateTime
21 |
22 | @ExperimentalSerializationApi
23 | @KtorExperimentalLocationsAPI
24 | class JokeResourceTest : AutoCloseKoinTest() {
25 |
26 | @Test
27 | fun `random joke api works correctly`() = withTestServer(
28 | koinModules = appTestModule.plus(
29 | module {
30 | // Just to showcase the possibility, in this case this dependency can be put in the base test module
31 | single { JokeRepositoryImpl(get()) }
32 | }
33 | )
34 | ) {
35 |
36 | // Setup
37 | val joke = transaction {
38 | Joke.new("joke_1") {
39 | this.value = "Chuck Norris tests are always green"
40 | this.createdAt = LocalDateTime.now()
41 | this.updatedAt = LocalDateTime.now()
42 | }
43 | }
44 |
45 | val href = application.locations.href(
46 | JokeEndpoint.Random(
47 | parent = JokeEndpoint()
48 | )
49 | )
50 |
51 | handleRequest(HttpMethod.Get, href).apply {
52 | assertEquals(HttpStatusCode.OK, response.status())
53 |
54 | val response = Json.decodeFromString(response.content!!)
55 |
56 | assertEquals(transaction { joke.id.value }, response.jokeId)
57 | assertEquals(transaction { joke.value }, response.jokeContent)
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/part6/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSource
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.mapper.toDTO
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
6 | import com.prof18.ktor.chucknorris.sample.jobs.JobSchedulerManager
7 | import com.prof18.ktor.chucknorris.sample.jobs.RandomJokeJob
8 | import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
9 | import org.quartz.*
10 |
11 | class JokeRepositoryImpl(
12 | private val jokeLocalDataSource: JokeLocalDataSource,
13 | private val jobSchedulerManager: JobSchedulerManager
14 | ) : JokeRepository {
15 |
16 | override suspend fun getRandomJoke(): JokeDTO {
17 | val jokeDTO = newSuspendedTransaction {
18 | val allJokes = jokeLocalDataSource.getAllJokes()
19 | val randomJoke = allJokes.random()
20 | return@newSuspendedTransaction randomJoke.toDTO()
21 | }
22 | return jokeDTO
23 | }
24 |
25 | override suspend fun watch(name: String) {
26 | val jobId = "chuck-watch-job-for-name-$name"
27 | val triggerId = "chuck-watch-trigger-for-name-$name"
28 |
29 | // If a job exists, delete it!
30 | val jobScheduler = jobSchedulerManager.scheduler
31 | val jobKey = JobKey.jobKey(jobId, RandomJokeJob.WATCH_JOB_GROUP)
32 | jobScheduler.deleteJob(jobKey)
33 |
34 | val job: JobDetail = JobBuilder.newJob(RandomJokeJob::class.java)
35 | .withIdentity(jobId, RandomJokeJob.WATCH_JOB_GROUP)
36 | .usingJobData(RandomJokeJob.JOB_MAP_NAME_ID_KEY, name)
37 | .build()
38 |
39 | val trigger: Trigger = TriggerBuilder.newTrigger()
40 | .withIdentity(triggerId, RandomJokeJob.WATCH_JOB_GROUP)
41 | .withSchedule(
42 | SimpleScheduleBuilder.simpleSchedule()
43 | // every minute
44 | .withIntervalInMinutes(1)
45 | .repeatForever()
46 | )
47 | .build()
48 |
49 | // Tell quartz to schedule the job using our trigger
50 | jobSchedulerManager.scheduler.scheduleJob(job, trigger)
51 | }
52 |
53 | override fun getChuckGreeting(name: String): String {
54 | return "Hi $name, remember that Chuck Norris is watching you 👀"
55 | }
56 | }
--------------------------------------------------------------------------------
/ktor-1.6.x/src/main/kotlin/com/prof18/ktor/chucknorris/sample/features/jokes/domain/JokeRepositoryImpl.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.ktor.chucknorris.sample.features.jokes.domain
2 |
3 | import com.prof18.ktor.chucknorris.sample.features.jokes.data.JokeLocalDataSource
4 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.mapper.toDTO
5 | import com.prof18.ktor.chucknorris.sample.features.jokes.domain.model.JokeDTO
6 | import com.prof18.ktor.chucknorris.sample.jobs.JobSchedulerManager
7 | import com.prof18.ktor.chucknorris.sample.jobs.RandomJokeJob
8 | import org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
9 | import org.quartz.*
10 |
11 | class JokeRepositoryImpl(
12 | private val jokeLocalDataSource: JokeLocalDataSource,
13 | private val jobSchedulerManager: JobSchedulerManager
14 | ) : JokeRepository {
15 |
16 | override suspend fun getRandomJoke(): JokeDTO {
17 | val jokeDTO = newSuspendedTransaction {
18 | val allJokes = jokeLocalDataSource.getAllJokes()
19 | val randomJoke = allJokes.random()
20 | return@newSuspendedTransaction randomJoke.toDTO()
21 | }
22 | return jokeDTO
23 | }
24 |
25 | override suspend fun watch(name: String) {
26 | val jobId = "chuck-watch-job-for-name-$name"
27 | val triggerId = "chuck-watch-trigger-for-name-$name"
28 |
29 | // If a job exists, delete it!
30 | val jobScheduler = jobSchedulerManager.scheduler
31 | val jobKey = JobKey.jobKey(jobId, RandomJokeJob.WATCH_JOB_GROUP)
32 | jobScheduler.deleteJob(jobKey)
33 |
34 | val job: JobDetail = JobBuilder.newJob(RandomJokeJob::class.java)
35 | .withIdentity(jobId, RandomJokeJob.WATCH_JOB_GROUP)
36 | .usingJobData(RandomJokeJob.JOB_MAP_NAME_ID_KEY, name)
37 | .build()
38 |
39 | val trigger: Trigger = TriggerBuilder.newTrigger()
40 | .withIdentity(triggerId, RandomJokeJob.WATCH_JOB_GROUP)
41 | .withSchedule(
42 | SimpleScheduleBuilder.simpleSchedule()
43 | // every minute
44 | .withIntervalInMinutes(1)
45 | .repeatForever()
46 | )
47 | .build()
48 |
49 | // Tell quartz to schedule the job using our trigger
50 | jobSchedulerManager.scheduler.scheduleJob(job, trigger)
51 | }
52 |
53 | override fun getChuckGreeting(name: String): String {
54 | return "Hi $name, remember that Chuck Norris is watching you 👀"
55 | }
56 | }
--------------------------------------------------------------------------------