Skip to content

vakenbolt/kotlin-docker-microservices-example

Repository files navigation

kotlin-docker-microservices-example

NBA Finals logo

A Vertx microservice that provides the winning team statistics for the NBA Finals(1980-2018). The data set for this example is found here. Swagger docs forthcoming.

Note: The dataset mentioned above has a couple of spelling errors that are corrected in the imported version for this project.

Table of Contents
  • Docker 18.0+
  • Gradle 5.0+
  • Java 1.8+
  1. Export an environment variable called API_CONFIG that points to the location of the server configuration JSON file.
$ export API_CONFIG=<%PATH%>/kotlin-docker-microservices-example/configs/api_server.config.json
  1. Optionally, if you would like the route path (/) of the server to return a 200 status code.
export ROOT_PATH_AVAILABLE=TRUE

This is particularly useful if the server will run in container environments where the root path is used for health checks (e.g. Kubernetes on Google Cloud)

  1. Start by building the API server and all associated modules.
$ ./gradlew clean build shadowJar
  1. Build a Docker image for the successfully built API server.
$ docker build -t nba_finals_web_api:0.9 web-api/
  1. Start the integration testing environment via docker-compose
$ docker-compose -f docker-compose-integration.yml up
  1. Run the integration tests.
$ ./gradlew test -Dtest.profile=integration

To shutdown an environment running via docker-compose:

$ docker-compose down -v --remove-orphans
  1. Tear down the integration docker-compose down environment if it is running and bring up the development environment.
$ docker-compose up

The hmac-sha-keygen module is available to create keys that are compatible with the encryption settings on the API server. The key used by the API server for encrypting JWT tokens is called jwtKey in the API server configuration file.

To generate a new key:

$ java -jar hmac-sha-keygen/build/libs/hmac-sha-keygen-0.9-SNAPSHOT-all.jar

dQWulnW5AUcrcr288/fzkl4a+Cwb59rWyIA1YRr587CcsbUdrT/iyA3rQGgJNhQLleIDJn5ipzv9z3ASKud70g

Sign up as a new user to get an authentication token.

$ curl -i http://localhost:8080/signUp -d '{"username":"ChicagoBulls", "password":"Testing123!"}'

HTTP/1.1 201 Created
content-length: 159

{"bearer":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIzIiwiZXhwIjoxNTU1MDEwMDc1fQ.m4RBIjn7qYJOr57XAdyDl_BTLOEFFmFCqCQIaKJBR6HzDDawzIDtGcGDab9z_ERSXEBsNvHKHKv2WmwxtyXTmw"}

To authenticate.

curl -i http://localhost:8080/authenticate -d '{"username":"ChicagoBulls", "password":"Testing123!"}'

HTTP/1.1 201 Created
content-length: 159

{"bearer":"eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIzIiwiZXhwIjoxNTU1MDExNDQ1fQ.WiqtD_0EHXD42J4weKgMKNM5FgfNQmZ_M7-kgJdlSJnQiFc7GLJm5mCxBCswMwPPE2eq2gBADv33WTQQ7wlL1w"}

To get all of the games for a given year.

curl -i http://localhost:8080/games/2018 -H 'Authorization: Bearer <%auth_token%>'

To get all of the games won for a given year.

curl -i http://localhost:8080/games/2010/wins -H 'Authorization: Bearer <%auth_token%>'

To get all of the games lost for a given year.

curl -i http://localhost:8080/games/2001/losses -H 'Authorization: Bearer <%auth_token%>'

To get all of the home games for a given year.

curl -i http://localhost:8080/games/1992/home -H 'Authorization: Bearer <%auth_token%>'

To get all of the away games for a given year.

curl -i http://localhost:8080/games/1987/away -H 'Authorization: Bearer <%auth_token%>'

To get all of the years that data is available.

curl -i http://localhost:8080/getYears -H 'Authorization: Bearer <%auth_token%>'

To get all of the teams in the data set.

curl -i http://localhost:8080/getTeams -H 'Authorization: Bearer <%auth_token%>'

To get all of the games by team.

curl -i http://localhost:8080/getGamesByTeam -d '{"team":"Bulls"}' -H 'Authorization: Bearer <%auth_token%>'

To get all of the games by team for a given year.

curl -i http://localhost:8080/getGamesByTeamAndYear -d '{"team":"Lakers","year":1980}' -H 'Authorization: Bearer <%auth_token%>'

To perform a health check.

curl -i http://localhost:8080/healthCheck

HTTP/1.1 200 OK
content-length: 0

MySQL: The docker-compose file instructs MySQL to auto-generate the root password and not expose it. A non-root user called nba_finals_db is created instead. MySQL is configured via startup SQL scripts located in configs/docker-entrypoint-initdb.d. The nba_finals_db user is not used to connect to the database from the API Server. This is accomplished with the nba_finals_service user which is created in the 3_create_mysql_users_and_roles.sql script.

Important Note: The nba_finals_service user has very limited permissions. It is only allowed to SELECT on all tables in the champions database except for the user table on which it can perform an INSERT.

JWT: Tokens are signed with HS512 and used for authentication and accessing secure endpoints. Once a token is granted, it is white-listed in Redis. The life-cycle of the Redis key is equal to the expiration time associated with the token. This ensures that an expired token is automatically removed from the white-list. Only tokens granted by the API server will be honored for authentication and verification.

The code revolves around the concept of Endpoint Handlers and Resolvers. An endpoint handler is responsible for extracting and validating all of the information that a resolver would need to execute the request. For example, AuthenticationEndpoint parses the request and calls an AuthenticationResolver to execute (or resolve) the request. Dependency injection is used to connect endpoint handlers to resolvers. Endpoints implement the Endpoint interface and are provided using Guice's Multibinder. All resolver functions return a ResolverResponse<T> which contains the response payload and status code.

Every Endpoint has a Responder injected as a dependency used to handle API responses. The Responder takes care of routing paths and invoking the resolver function. The Responder will catch and handle any exceptions that occur within the resolver function.

Localized error messages are provided via the localized_exception_messages resource bundle located in the resources folder in web-api. Localized messages are available via the ApiException which is provided by the ApiExceptionFactory class.

Note: Localization is currently not supported for JSR-303 annotations. These will be provided later via configurations available in the Hibernate Validation Library.

Dependency injection is provided via the Google Guice library. There is only one (and only one) injector used to provide an instance. This injector kicks off the whole dependency graph and makes the application available for use. The injector is found in the main function in NBAFinalsApiServer.kt. Guice Modules are also added in the main function. Below is a list of the Guice modules used in the API server.

Module Description
ApplicationLifeCycleModule Provides a mechanism to start the server and adds shutdown hooks.
CryptoModule Adds support for password hashing through SCrypt
DaoModule Provides JDBI data access objects.
EndpointsModule Provides all of the Endpoint Handlers.
HikariModule Provides HikarCP database connection pool.
HttpServerModule Provides Vertx HTTP Server.
JacksonModule Provides Jackson for ObjectMapper for serializing/de-serializing JSON objects.
JdbiModule Provides JDBI with SqlObject and Kotlin native support.
JwtModule Provides the JwtAuthentication class used to handle JWT authentication.
LocalizationModule Provides localization support
RedisModule Provides Redis connectivity via the Jedis library
ServerConfigModule Provides the ServerConfig class.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published