1- # Kotlin-Ktor and postgres backend
2-
3- ## Introduction
4-
5- Here lays a demonstration of my growing interest in Kotlin language and Ktor server framework. It's an example with
6- complex Graph algorithms.
1+ # Kotlin Ktor and postgres backend
2+ Here lays a Kotlin web project with Ktor framework, Postgres database, and JWT Authentication.
3+
4+ The project comprises following ingredients:
5+ - [ Ktor] ( https://ktor.io/ ) server includes [ JSON serializers] ( https://ktor.io/docs/serialization.html ) , [ Authentication] ( https://ktor.io/docs/authentication.html ) , and [ Testing] ( https://ktor.io/docs/testing.html )
6+ - [ Netty] ( https://netty.io/ ) web server
7+ - [ Postgres] ( https://www.postgresql.org/ ) as database
8+ - [ Exposed] ( https://github.com/JetBrains/Exposed ) as ORM
9+ - [ Hikari Connection Pool] ( https://github.com/brettwooldridge/HikariCP )
10+ - [ Logback] ( https://logback.qos.ch/ ) for logging purposes
11+ - [ JBCrypt] ( https://www.mindrot.org/projects/jBCrypt/ ) for hashing passwords(No salting yet)
12+
13+ There is a simple implementation of Graph search and traverse with DFS algorithm but if you aim for a solid solution
14+ better go for [ GUAVA Graph] ( https://github.com/google/guava/wiki/GraphsExplained ) from Google.
15+
16+ Project is agnostic about database, you can dynamically change Postgres to any other databases that Exposed JDBC
17+ supports by changing a couple of variables:
18+ - the database driver version in ` gradle.properties `
19+ - the database driver dependency in ` build.gradle.kts `
20+ - the ** WEB_DB_URL** variable in ` .env ` file
721
822## Flow
23+ 1 . deploy the docker compose with ` docker compose up -d ` command
24+ 2 . sign up to the system ` /signup ` with a username and password(not hardened enough)
25+ 3 . log in to with username and password to get access token ` /login `
26+ 4 . send post request with payload and token to ` /hirearchy ` to create the hierarchy of the organization
27+ 5 . send get request with token to ` /hierarchy/{name}/supervisors ` to fetch the supervisors of the current user
928
10- To start the application you need to:
11-
12- 1 . deploy the docker compose
13- 2 . sign up to the system ` /signup `
14- 3 . log in to get access token ` /login `
15- 4 . send post request with token to ` /hirearchy ` to create the hierarchy of the organization
16- 5 . send post request with token to ` /hierarchy/{name}/supervisors ` to get the supervisors of the user
29+ ## How to use
1730
18- ## Starting the application
31+ > You need ** root access ** for docker
1932
20- Go to the root directory of the project and deploy the application with following command:
33+ Go to the root directory of the project where ` docker-compose.yml ` is and change the environment variables in
34+ ` .env-example ` with yours and rename the file to ` mv .env-example .env ` then deploy the application with following command:
2135
2236``` bash
2337docker-compose up
2438```
2539
26- for shutting down the deployment:
40+ for shutting down the deployment run following command where the ` docker-compose.yml ` file resides :
2741
2842``` bash
2943docker-compose down -v
3044```
3145
32- You might need root user access as well
33-
3446### What it does?
3547
36- We have REST API to post the JSON below. This JSON represents an Person -> Person relationship that looks like this:
48+ We have REST API to post the JSON below. This JSON represents a Person -> Person relationship that looks like this:
3749
38- ``` json
39- {
50+ ``` json
51+ {
4052 "Pete" : " Nick" ,
4153 "Barbara" : " Nick" ,
4254 "Nick" : " Sophie" ,
4355 "Sophie" : " Jonas"
4456}
45- ```
57+ ```
4658
4759In this case, Nick is a supervisor of Pete and Barbara, Sophie supervises Nick. The supervisor list is
4860not always in order.
4961
50- ``` bash
51- curl --request POST -sLv \
52- --url ' http://localhost:3000/hierarchy' \
53- --header " Content-Type: application/json" \
54- --header " Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJodHRwOi8vMC4wLjAuMDo4MDgwL2hpZXJhcmNoeSIsImlzcyI6Imh0dHA6Ly8wLjAuMC4wOjgwODAvIiwiZXhwIjoxNjUwNDkwNzUwLCJ1c2VybmFtZSI6ImphbmUifQ.Xfn4JEOHo-Px7vy0TVyo3malCFlj3eFvzAJejqlefPM" \
55- --data ' {"Nick":"Barbara","Barbara":"Nick","Elias":"Levi"}'
56- ```
62+ ``` bash
63+ curl --request POST -sLv \
64+ --url ' http://localhost:3000/hierarchy' \
65+ --header " Content-Type: application/json" \
66+ --header " Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJodHRwOi8vMC4wLjAuMDo4MDgwL2hpZXJhcmNoeSIsImlzcyI6Imh0dHA6Ly8wLjAuMC4wOjgwODAvIiwiZXhwIjoxNjUwNDkwNzUwLCJ1c2VybmFtZSI6ImphbmUifQ.Xfn4JEOHo-Px7vy0TVyo3malCFlj3eFvzAJejqlefPM" \
67+ --data ' {"Nick":"Barbara","Barbara":"Nick","Elias":"Levi"}'
68+
69+ ```
5770
5871The response to querying the endpoint where the root is at the top of the JSON nested dictionary. For instance, previous
5972input would result in:
6073
6174``` bash
62- curl --request GET -sLv \
63- --url ' http://localhost:3000/hierarchy' \
64- --header " Content-Type: application/json" \
65- --header " Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJodHRwOi8vMC4wLjAuMDo4MDgwL2hpZXJhcmNoeSIsImlzcyI6Imh0dHA6Ly8wLjAuMC4wOjgwODAvIiwiZXhwIjoxNjUwNDkwNzUwLCJ1c2VybmFtZSI6ImphbmUifQ.Xfn4JEOHo-Px7vy0TVyo3malCFlj3eFvzAJejqlefPM"
66- ```
75+ curl --request GET -sLv \
76+ --url ' http://localhost:3000/hierarchy' \
77+ --header " Content-Type: application/json" \
78+ --header " Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJodHRwOi8vMC4wLjAuMDo4MDgwL2hpZXJhcmNoeSIsImlzcyI6Imh0dHA6Ly8wLjAuMC4wOjgwODAvIiwiZXhwIjoxNjUwNDkwNzUwLCJ1c2VybmFtZSI6ImphbmUifQ.Xfn4JEOHo-Px7vy0TVyo3malCFlj3eFvzAJejqlefPM"
79+ ```
6780
6881the response will be:
6982
70- ``` json
71- {
83+ ``` json
84+ {
7285 "Jonas" : {
7386 "Sophie" : {
7487 "Nick" : {
@@ -78,28 +91,28 @@ the response will be:
7891 }
7992 }
8093}
81- ```
94+ ```
8295
8396Query for a specific Person it's the hierarchy:
8497
85- ``` bash
86- curl --request GET -sLv \
87- --url ' http://localhost:3000/hierarchy/Nick/supervisors' \
88- --header " Content-Type: application/json" \
89- --header " Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJodHRwOi8vMC4wLjAuMDo4MDgwL2hpZXJhcmNoeSIsImlzcyI6Imh0dHA6Ly8wLjAuMC4wOjgwODAvIiwiZXhwIjoxNjUwNDkwNzUwLCJ1c2VybmFtZSI6ImphbmUifQ.Xfn4JEOHo-Px7vy0TVyo3malCFlj3eFvzAJejqlefPM"
90- ```
98+ ``` bash
99+ curl --request GET -sLv \
100+ --url ' http://localhost:3000/hierarchy/Nick/supervisors' \
101+ --header " Content-Type: application/json" \
102+ --header " Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJodHRwOi8vMC4wLjAuMDo4MDgwL2hpZXJhcmNoeSIsImlzcyI6Imh0dHA6Ly8wLjAuMC4wOjgwODAvIiwiZXhwIjoxNjUwNDkwNzUwLCJ1c2VybmFtZSI6ImphbmUifQ.Xfn4JEOHo-Px7vy0TVyo3malCFlj3eFvzAJejqlefPM"
103+ ```
91104
92105the response of the query will be:
93106
94- ``` json
95- {
107+ ``` json
108+ {
96109 "Nick" : {
97110 "Sophie" : {
98111 "Jonas" : {}
99112 }
100113 }
101114}
102- ```
115+ ```
103116
104117Sophie is the supervisor of the Nick and Jonas is supervisor of the supervisor of the Nick
105118
@@ -108,34 +121,41 @@ Sophie is the supervisor of the Nick and Jonas is supervisor of the supervisor o
108121Sign up to the system
109122
110123``` bash
111- curl --request POST -sL \
112- --url ' http://localhost:3000/signup' \
113- --header " Content-Type: application/json" \
114- --data ' {"username":"jane","password":"doe"}'
124+ curl --request POST -sL \
125+ --url ' http://localhost:3000/signup' \
126+ --header " Content-Type: application/json" \
127+ --data ' {"username":"jane","password":"doe"}'
115128 ```
116129
117130login to the system
118131
119132``` bash
120- curl --request POST -sL \
121- --url ' http://localhost:3000/login' \
122- --header " Content-Type: application/json" \
123- --data ' {"username":"jane","password":"doe"}'
124- ```
133+ curl --request POST -sL \
134+ --url ' http://localhost:3000/login' \
135+ --header " Content-Type: application/json" \
136+ --data ' {"username":"jane","password":"doe"}'
137+ ```
125138
126139The response will be the access token
127140
128141``` json
129- {
142+ {
130143 "token" : " eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJodHRwOi8vMC4wLjAuMDo4MDgwL2hpZXJhcmNoeSIsImlzcyI6Imh0dHA6Ly8wLjAuMC4wOjgwODAvIiwiZXhwIjoxNjUwMTU3NjIxLCJ1c2VybmFtZSI6ImpvaG4ifQ.LSJUte7oy9Kv7qkozI3APBzPxHVZ56GID-n0lRIKvdY"
131144}
132145```
133146
134- Also, you can use following [ Postman JSON collection file] ( /postman_collection.json ) and test the application from
135- Postman
147+ ## How to test locally
148+ For testing the project locally you can run docker compose with ` docker-compose-test.yml ` file. It will run the tests
149+ against a test database.
150+ ``` bash
151+ docker-compose --file docker-compose-test.yml up
152+ ```
153+ After finishing the tests you can clean test data nd shut the containers down with following command:
136154
137- To deploy the test environment and test the application:
155+ ``` bash
156+ docker-compose --file docker-compose-test.yml down -v
157+ ```
138158
139- ``` bash
140- docker-compose --file docker-compose-test.yml up
141- ```
159+ ## Continues Integration
160+ For continues integration, the CI workflow prepares the database, run the gradle build with tests, and generates report
161+ to Codacy about the quality of code.
0 commit comments