Skip to content

Knowit-Objectnet/oko-backend

Repository files navigation

Prosjekt Ombruk Backend


Table of Contents

Intro

This is the backend of the reuse station project, belonging to Renovasjon og Gjenvinningsetaten (REG) in Oslo kommune.

Built with

It's entirely written in Kotlin with Exposed as its ORM and Ktor as its web framework. The code is mostly written in a functional style with the help of Arrow library.

Although Kotlin is Java-friendly, it's highly recommended reading up on Kotlin's documentation at kotlinlang.org

Most of the developers that contributed to the project used Intellij IDEA. We would recommend it as it has excellent Kotlin tooling. The next section has a list of some libraries you may need to look at for documentation. Note: the 4 first listed are the ones you will see most around the code base.

Libraries:

Getting started

Prerequisites

To compile and run this project, you would need a Java Development Kit. We have been using JDK 8. As mentioned earlier, we highly recommend using Intellij IDEA as most of the plugins and libraries needed will be prompted and installed. If you want to run without it, you will need to install Gradle.

Download project

This section will guide you to clone this repository. To follow this part of the guide, we expect you to have Git installed. Type the following lines in the Terminal (for unix users), or Command Prompt (for windows users):

cd /to-your-desired-directory
git clone https://kode.knowit.no/scm/oko/backend.git
cd backend

You are now inside the project folder. Type ls in the terminal, or dir in Command Prompt to see the root folder structure.

Running locally

To run this project locally you would need to install Docker. This is for running a database locally. After installing Docker, type in the commands bellow in a terminal to start a PostgreSQL-database:

docker run -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=admin -e POSTGRES_DB=db -p 5432:5432 postgres:13.2

Some explenation of the arguments in this initialization line: POSTGRES_USER: Username to connect to database. POSTGRES_PASSWORD: Password to connect to database. POSTGRES_DB: Name of database. -p 5432:5432: Port to connect to server. postgres:13.3: PostgreSQL version.

You can install dependencies and run the application with:

gradle run

If you received some errors, you may need to set some of the Environment Variables that are noted in the next section.

Environment variables

You may need to set two environment variables in order for the application to function as intended:

OKO_KEYCLOAK_CLIENT_SECRET

OKO_DEBUG

To authorize users we use an open source solution, Keycloak. The keycloak client secret can be found in both Keycloak and AWS, and is usually fetched from AWS when running there.

OKO_DEBUG allows for bypassing Keycloak entirely. Under normal operations, the application makes requests to keycloak when creating partners and stations, as well as for authenticating/authorizing.

By setting OKO_DEBUG to true, the application stops making calls to Keycloak, and starts allowing pre-created access tokens. These will be listed when running the application, and are also available in src/shared/api/JwtMockConfig.kt.

Usage

To communicate with the API we recommend you use some kind of API Client. E.g. Postman or Insomnia. It is important to remember that you need a bearer token to communicate with the server with or without Keycloak.

Table of endpoints

Entry when local: localhost:#PORTNUMBER# or 0.0.0.0:#PORTNUMBER# where #PORTNUMBER# is set to 8080 by default in application.conf.

Most but not all the endpoints have a get, post, patch and delete method. Look up the corresponding HTTP Controller file for more details of the nested endpoints and authentication.

Endpoint Description More details at
/aarsak Reason for cancellation src/aarsak/application/api/AarsakHttpController.kt
/aktor A general endpoint for looking up different participants src/aktor/application/api/AktorHttpController.kt
/kontakter Contact persons src/aktor/application/api/KontaktHttpController.kt
/partnere Partners that pick up from stations src/aktor/application/api/PartnerHttpController.kt
/stasjoner Stations src/aktor/application/api/StasjonHttpController.kt
/avtaler Agreements src/aktor/application/api/AvtaleHttpController.kt
/hentinger Pickup wrapper. A general way to get a planlagt henting or ekstrahenting src/henting/application/api/HentingHttpController.kt
/ekstra-hentinger Extra pickup src/henting/application/api/EkstraHentingHttpController.kt
/planlagte-hentinger Planned pickup src/henting/application/api/PlanlagtHentingHttpController.kt
/henteplaner Pickup plans src/henting/application/api/HenteplanHttpController.kt
/kategorier Categories src/kategori/application/api/KategoriHttpController.kt
/statistikk Weight statistics src/statistikk/application/api/StatistikkHttpController.kt
/utlysninger Announcements/Events src/utlysning/application/api/UtlysningHttpController.kt
/vektregistrering Weight registrations src/vektregistrering/application/api/VektregistreringHttpController.kt

How to code

The reason to program in a functional style is first and foremost to have better control on the flow of exceptions. We use object called Either from the Arrow-library. They are relatively easy object, but can be confusing at the beginning. Either objects return one of two states, a Right or a Left. Right is usually a success, and the return value, while Left is usually an exception.

The documentation for the Arrow-library is not particularly easy to understand, but you should still take a look at the methods used in the code. The same methods are most of the time used.

File Structure

Resources

The resource folder contains files that are needed one place or another in the application. The file, messages_en.properties, is used for creating custom messages for the validation library the application uses, Valiktor.

Application.conf

The application.conf file can be considered the entry point of the application, and contains important application values. The .conf file usually defines each variable twice, where the first occurrence is a default value and the second being one that can override the origin value by being passed in through environment variables.

Table of variables in application.conf

Block Name Description
deployment port The port to deploy the application to
deployment watch Currently not working. Used for hot reloading
application modules Entrypoint for application
db jdbcUrl The URL that jdbc should connect to
db password Password for the database
db user Username for the database
db migrationsLocation Location of db migration
keycloak clientSecret Used for sending requests to keycloak
keycloak keycloakUrl The URL of the keycloak instance to connect to
keycloak keycloakRealm The keycloak realm that should be used
oko debug Whether the application should run in debug mode or not. Should be false when deploying

OpenAPI

NOTE: This is outdated.
The OpenAPI folder describes the available API calls within the application. Each path has its own folder. These folders contain descriptions of the different endpoints belonging to a path. The schema folder contains component schemas that "belongs" to that path.

Furthermore, the openapi folder contains the two files api.yaml and openapi_yaml. api.yaml specifies the different paths and components in the different sub-modules. One can then use Swagger-cli or something akin to it to merge all the yaml files into one big file, openapi.yaml. This file is then usually uploaded to our SwaggerHub.

Migrations

Migrations are done through the use of Flyway. The different database migrations are located in the db.migrations folder. If the postgres database requires fields to be updated, a new migration has to be created in order to alter the running db instance. Each new migration must follow this naming schema: V[1-9]+__*.sql

Src

Each endpoint has been placed in its own folder within src, with some exception as can be seen in the table of endpoints.

Each folder has the following structure:

Name Description
dto Serializable data classes that are created for a specific REST operation on a specific endpoint. Contains validation logic.
services Business logic that does not belong in api. Communicates with the repository.
entity An object that represent an entity of the endpoint. Serializable data class.
model Representations of objects "belonging" to a specific endpoint.
infrastructure Data access layer. Contains ORM logic and code representations of database tables.

Most of the HTTP-requests follow this routine:

  1. HTTPController: Authenticate and correct HTTP-method
  2. Services: Access the correct repository and method to retrieve all the data that is requested.
  3. Repository: Prepares query for the PostgreSQL-database and creates an entity.

The exception to this rule are the packages not listed in table of endpoints. These packages, e.g. the shared and core folders, which contains common logic used in the other folders. notification is used to communicate with AWS Lambda.

Docker

We have used two different ways of running Docker throughout the project duration; Running locally has been done through the use of Docker-compose and Dockerfile.dev, whilst the deployed application simply uses Dockerfile. The deployment Dockerfile is not magic.

Two things to look out for is to ensure that access rights are set correctly and that db migrations are placed where they're expected. All files should work as-is.

Testing

Unit tests

We are doing unit tests with JUnit5, Ktors test server, and MockK. All the tests can be found in the test directory. All services have their own corresponding package. When writing new test you should try to make a as comprehensible as possible. We have tried to follow AAA(Assemble, Act, Analyze), which means that the test should have three distinct parts. One for setup, one for executing the feature you are testing, and one for checking that the results are what you expected. The variables name expected and actual are use throughout our tests to make understanding other tests easier.

Integration tests

For our integration tests we use ktor test framework. We lose a bit of in-depth http testing by doing it this way. The ease of use makes up for this as tests are much faster to write. Doing more in-depth integration testing is something which needs a closer look in the future. It is important to set the environment variable OKO_DEBUG to true before running integration tests. We are not testing against a real Keycloak instance. Debug mode makes sure this is the case.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages