├── .gitignore ├── META-INF └── MANIFEST.MF ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src ├── main ├── kotlin │ └── be │ │ └── kotlin │ │ └── myrestapi │ │ └── kotlinmyrestapi │ │ ├── KotlinmyrestapiApplication.kt │ │ ├── controller │ │ ├── BeerController.kt │ │ ├── BeerTypeController.kt │ │ ├── BreweryController.kt │ │ └── CountryController.kt │ │ ├── data │ │ ├── dto.kt │ │ └── resources.kt │ │ ├── repository │ │ ├── BeerRepository.kt │ │ ├── BeerTypeRepository.kt │ │ ├── BreweryRepository.kt │ │ └── CountryRepository.kt │ │ └── web │ │ └── SwaggerConfiguration.kt └── resources │ └── application.properties └── test ├── kotlin └── be │ └── kotlin │ └── myrestapi │ └── kotlinmyrestapi │ └── KotlinmyrestapiApplicationTests.kt └── resources └── application.properties /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | nbproject/private/ 21 | build/ 22 | nbbuild/ 23 | dist/ 24 | nbdist/ 25 | .nb-gradle/ -------------------------------------------------------------------------------- /META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: be.kotlin.myrestapi.kotlinmyrestapi.KotlinmyrestapiApplicationKt 3 | 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # kotlinmyrestapi 2 | Source code for a Kotlin-based Spring backend, used in the 'Kotlin Deep Dive' talk at Devoxx 2017 (https://cfp.devoxx.be/2017/talk/MCN-7281/Kotlin_Deep_Dive) 3 | 4 | ## Run 5 | Build and run: 6 | 7 | ``` 8 | ./gradlew build && java -jar build/libs/kotlinmyrestapi-clone-0.0.1-SNAPSHOT.jar 9 | ``` 10 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | kotlinVersion = '1.1.60' 4 | springBootVersion = '2.0.0.M5' 5 | } 6 | repositories { 7 | mavenCentral() 8 | maven { url "https://repo.spring.io/snapshot" } 9 | maven { url "https://repo.spring.io/milestone" } 10 | } 11 | dependencies { 12 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 13 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}") 14 | classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}") 15 | } 16 | } 17 | 18 | apply plugin: 'kotlin' 19 | apply plugin: 'kotlin-spring' 20 | apply plugin: 'eclipse' 21 | apply plugin: 'org.springframework.boot' 22 | apply plugin: 'io.spring.dependency-management' 23 | 24 | group = 'be.kotlin.myrestapi' 25 | version = '0.0.1-SNAPSHOT' 26 | sourceCompatibility = 1.8 27 | compileKotlin { 28 | kotlinOptions.jvmTarget = "1.8" 29 | } 30 | compileTestKotlin { 31 | kotlinOptions.jvmTarget = "1.8" 32 | } 33 | 34 | repositories { 35 | mavenCentral() 36 | maven { url "https://repo.spring.io/snapshot" } 37 | maven { url "https://repo.spring.io/milestone" } 38 | } 39 | 40 | bootJar { 41 | launchScript () 42 | } 43 | 44 | 45 | dependencies { 46 | compile('org.springframework.boot:spring-boot-starter-data-jpa') 47 | compile('org.springframework.boot:spring-boot-starter-web') 48 | compile("org.jetbrains.kotlin:kotlin-stdlib-jre8:${kotlinVersion}") 49 | compile("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}") 50 | compile("com.h2database:h2:1.4.196") 51 | compile("io.springfox:springfox-swagger2:2.7.0") 52 | compile("io.springfox:springfox-swagger-ui:2.7.0") 53 | testCompile('org.springframework.boot:spring-boot-starter-test') 54 | 55 | } 56 | 57 | 58 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GuyHeylens/kotlinmyrestapi/abd39b6391dabe862c172a7e867467c0709aba2b/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Oct 30 22:05:29 CET 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.2-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /src/main/kotlin/be/kotlin/myrestapi/kotlinmyrestapi/KotlinmyrestapiApplication.kt: -------------------------------------------------------------------------------- 1 | package be.kotlin.myrestapi.kotlinmyrestapi 2 | 3 | import be.kotlin.myrestapi.kotlinmyrestapi.data.BeerDto 4 | import be.kotlin.myrestapi.kotlinmyrestapi.data.BeerTypeDto 5 | import be.kotlin.myrestapi.kotlinmyrestapi.data.BreweryDto 6 | import be.kotlin.myrestapi.kotlinmyrestapi.data.CountryDto 7 | import be.kotlin.myrestapi.kotlinmyrestapi.repository.BeerRepository 8 | import be.kotlin.myrestapi.kotlinmyrestapi.repository.BeerTypeRepository 9 | import be.kotlin.myrestapi.kotlinmyrestapi.repository.BreweryRepository 10 | import be.kotlin.myrestapi.kotlinmyrestapi.repository.CountryRepository 11 | import org.slf4j.LoggerFactory 12 | import org.springframework.boot.CommandLineRunner 13 | import org.springframework.boot.SpringApplication 14 | import org.springframework.boot.autoconfigure.SpringBootApplication 15 | import org.springframework.context.annotation.Bean 16 | 17 | 18 | @SpringBootApplication 19 | class KotlinmyrestapiApplication{ 20 | 21 | private val log = LoggerFactory.getLogger(KotlinmyrestapiApplication::class.java) 22 | 23 | 24 | // @Bean 25 | // fun h2servletRegistration(): ServletRegistrationBean { 26 | // val registration = ServletRegistrationBean(WebServlet()) 27 | // registration.addUrlMappings("/console/*") 28 | // return registration 29 | // } 30 | 31 | 32 | @Bean 33 | fun init(repoBeer: BeerRepository, repoBeerType: BeerTypeRepository, repoCountry: CountryRepository, repoBrewery: BreweryRepository) = CommandLineRunner{ 34 | 35 | //save Country 36 | 37 | val c =repoCountry.save(CountryDto(1, "Belgium")) 38 | 39 | //save BeerTypes 40 | val typeBlond = repoBeerType.save(BeerTypeDto(1, "Blonde Ale", "Blonde Ale" )) 41 | 42 | repoBeerType.save(BeerTypeDto(2, "Flanders Red Ale", "Flanders Red Ale" )) 43 | repoBeerType.save(BeerTypeDto(3, "Geuze", "Geuze" )) 44 | repoBeerType.save(BeerTypeDto(4, "Lambic", "Lambic" )) 45 | val typeBrown = repoBeerType.save(BeerTypeDto(5, "Oud Bruin", "Oud Bruin" )) 46 | 47 | 48 | //save Brewery 49 | val brewery = repoBrewery.save(BreweryDto(1, "Abdij Westvleteren", "Donkerstraat", "12", "8640", "Vleteren", country = c)) 50 | 51 | //save some beers 52 | repoBeer.save(BeerDto(1,"Westvleteren Blond", 5.8, "Blond", typeBlond, brewery)) 53 | repoBeer.save(BeerDto(2,"Westvleteren Acht", 8.0, "Brown", typeBrown, brewery)) 54 | repoBeer.save(BeerDto(3,"Westvleteren Twaalf", 10.8, "Brown", typeBrown, brewery)) 55 | 56 | } 57 | } 58 | 59 | 60 | fun main(args: Array) { 61 | SpringApplication.run(KotlinmyrestapiApplication::class.java, *args) 62 | } 63 | -------------------------------------------------------------------------------- /src/main/kotlin/be/kotlin/myrestapi/kotlinmyrestapi/controller/BeerController.kt: -------------------------------------------------------------------------------- 1 | package be.kotlin.myrestapi.kotlinmyrestapi.controller 2 | 3 | import be.kotlin.myrestapi.kotlinmyrestapi.data.* 4 | import be.kotlin.myrestapi.kotlinmyrestapi.repository.BeerRepository 5 | import be.kotlin.myrestapi.kotlinmyrestapi.repository.BeerTypeRepository 6 | import be.kotlin.myrestapi.kotlinmyrestapi.repository.BreweryRepository 7 | import org.springframework.http.ResponseEntity 8 | import org.springframework.web.bind.annotation.* 9 | import javax.validation.Valid 10 | 11 | @RestController 12 | @RequestMapping("/api") 13 | class BeerController(private val beerRepo: BeerRepository, 14 | private val breweryRepository: BreweryRepository, 15 | private val beerTypeRepository: BeerTypeRepository) { 16 | 17 | 18 | //region Create 19 | @PostMapping("/beers") 20 | fun createNewBeer(@Valid @RequestBody beerResource: BeerResource) { 21 | val beerTypeResult : BeerTypeDto = beerTypeRepository.getOne(beerResource.beerTypeId) 22 | val breweryResult = breweryRepository.getOne(beerResource.breweryId) 23 | val beer = BeerDto(beerResource.id, beerResource.beerName, beerResource.alcoholPercentage, beerResource.beerColour, 24 | beerType = beerTypeResult, brewery = breweryResult ) 25 | beerRepo.save(beer) 26 | } 27 | //endregion 28 | 29 | //region Read 30 | @GetMapping("/beers") 31 | fun getBeers(): List { 32 | return beerRepo.findAll().map { 33 | beerDto -> BeerResource(beerDto.id, beerDto.beerName, beerDto.alcoholPercentage, beerDto.beerColour, 34 | beerDto.beerType.id, beerDto.beerType.beerType, 35 | beerDto.beerType.beerJudgeCertification , beerDto.brewery.id, beerDto.brewery.breweryName) 36 | } 37 | } 38 | 39 | 40 | @GetMapping("/beer/{id}") 41 | fun getBeerById(@PathVariable id: Long): ResponseEntity { 42 | return beerRepo.findById(id).map { 43 | ResponseEntity.ok(it) 44 | }.orElseGet({ResponseEntity.notFound().build()}) 45 | } 46 | 47 | 48 | 49 | 50 | 51 | 52 | //endregion 53 | 54 | 55 | //region Update 56 | @PutMapping("/beer/{id}") 57 | fun updateBeer(@PathVariable id:Long, @Valid @RequestBody newBeerDto: BeerDto): ResponseEntity{ 58 | 59 | var existing = beerRepo.getOne(id) 60 | 61 | val updatedBeer = existing.copy(beerName = newBeerDto.beerName, beerColour = newBeerDto.beerColour, alcoholPercentage = newBeerDto.alcoholPercentage) 62 | 63 | val result = beerRepo.save(updatedBeer) 64 | 65 | return if(result != null ){ 66 | ResponseEntity.ok(result) 67 | } else { 68 | ResponseEntity.notFound().build() 69 | } 70 | 71 | } 72 | //endregion 73 | 74 | 75 | 76 | 77 | 78 | 79 | } -------------------------------------------------------------------------------- /src/main/kotlin/be/kotlin/myrestapi/kotlinmyrestapi/controller/BeerTypeController.kt: -------------------------------------------------------------------------------- 1 | package be.kotlin.myrestapi.kotlinmyrestapi.controller 2 | 3 | import be.kotlin.myrestapi.kotlinmyrestapi.data.BeerTypeDto 4 | import be.kotlin.myrestapi.kotlinmyrestapi.data.BeerTypeResource 5 | import be.kotlin.myrestapi.kotlinmyrestapi.repository.BeerRepository 6 | import be.kotlin.myrestapi.kotlinmyrestapi.repository.BeerTypeRepository 7 | import org.springframework.http.ResponseEntity 8 | import org.springframework.web.bind.annotation.* 9 | 10 | @RestController 11 | @RequestMapping("/api") 12 | class BeerTypeController(private val beerTypeRepository: BeerTypeRepository, private val beerRepo: BeerRepository) { 13 | 14 | @GetMapping("/beertypes") 15 | fun getBeerTypes(): List{ 16 | return beerTypeRepository.findAll().map { beerTypeDto -> BeerTypeResource(beerTypeDto.id, beerTypeDto.beerType, beerTypeDto.beerJudgeCertification) } 17 | } 18 | 19 | @GetMapping("/beertypes/{beertypename}") 20 | fun getBeerTypeByName(@PathVariable(value = "beertypename") beerTypeName: String): ResponseEntity>{ 21 | 22 | val result = beerTypeRepository.findByBeerType(beerTypeName).map { 23 | beerTypeDto -> BeerTypeResource(beerTypeDto.id, beerTypeDto.beerType, beerTypeDto.beerJudgeCertification) 24 | } 25 | 26 | return if(result.isNotEmpty()){ 27 | ResponseEntity.ok(result) 28 | } else { 29 | ResponseEntity.notFound().build() 30 | } 31 | 32 | } 33 | 34 | @GetMapping("/type/{id}/beers") 35 | fun getBeersByTypeId(@PathVariable id: Long)= beerRepo.findByBeerTypeId(id).let{ 36 | ResponseEntity.ok(it) 37 | }?: ResponseEntity.notFound().build() 38 | } -------------------------------------------------------------------------------- /src/main/kotlin/be/kotlin/myrestapi/kotlinmyrestapi/controller/BreweryController.kt: -------------------------------------------------------------------------------- 1 | package be.kotlin.myrestapi.kotlinmyrestapi.controller 2 | 3 | import be.kotlin.myrestapi.kotlinmyrestapi.data.BeerResource 4 | import be.kotlin.myrestapi.kotlinmyrestapi.data.BreweryBeerResource 5 | import be.kotlin.myrestapi.kotlinmyrestapi.data.BreweryDto 6 | import be.kotlin.myrestapi.kotlinmyrestapi.data.BreweryResource 7 | import be.kotlin.myrestapi.kotlinmyrestapi.repository.BeerRepository 8 | import be.kotlin.myrestapi.kotlinmyrestapi.repository.BreweryRepository 9 | import org.springframework.http.ResponseEntity 10 | import org.springframework.web.bind.annotation.* 11 | 12 | @RestController 13 | @RequestMapping("/api") 14 | class BreweryController(private val breweryRepository: BreweryRepository, private val beerRepository: BeerRepository) { 15 | 16 | @GetMapping("/breweries") 17 | fun getBreweries(): List { 18 | return breweryRepository.findAll().map { breweryDto -> BreweryResource(breweryDto.id, breweryDto.breweryName, 19 | breweryDto.streetName, breweryDto.houseNumber, breweryDto.postalCode, breweryDto.town, 20 | breweryDto.country.id, breweryDto.country.countryName) } 21 | } 22 | 23 | @GetMapping("brewery/{id}") 24 | fun getBreweryById(@PathVariable(value = "id") Id: Long): ResponseEntity { 25 | val result = breweryRepository.getOne(Id) 26 | return if(result != null) { 27 | ResponseEntity.ok(BreweryResource(result.id, result.breweryName, result.streetName, result.houseNumber, 28 | result.postalCode, result.town, result.country.id, result.country.countryName)) 29 | } else { 30 | ResponseEntity.notFound().build() 31 | } 32 | } 33 | 34 | @GetMapping("breweries/name/{name}") 35 | fun getBreweryByName(@PathVariable(value = "name") breweryName: String): ResponseEntity>? { 36 | val b = breweryRepository.findByBreweryName(breweryName).map { breweryDto -> BreweryResource(breweryDto.id, breweryDto.breweryName, breweryDto.streetName, 37 | breweryDto.houseNumber, breweryDto.postalCode, breweryDto.town, 38 | breweryDto.country.id, breweryDto.country.countryName) } 39 | 40 | return if(b.isNotEmpty()){ 41 | ResponseEntity.ok(b) 42 | } else { 43 | ResponseEntity.notFound().build() 44 | } 45 | } 46 | 47 | @GetMapping("brewery/{id}/beers") 48 | fun getBeersByBreweryId(@PathVariable id: Long): ResponseEntity? { 49 | 50 | val result = breweryRepository.getOne(id) 51 | return if(result != null) { 52 | 53 | val breweryResource = BreweryResource(result.id, result.breweryName, result.streetName, result.houseNumber, result.postalCode, result.town, result.country.id , result.country.countryName) 54 | 55 | val beers = beerRepository.findByBreweryId(id)?.map { beerDto -> BeerResource(beerDto.id, beerDto.beerName, beerDto.alcoholPercentage, beerDto.beerColour, beerDto.beerType.id, beerDto.beerType.beerType, beerDto.beerType.beerJudgeCertification, beerDto.brewery.id, beerDto.brewery.breweryName) } 56 | 57 | ResponseEntity.ok(BreweryBeerResource(breweryResource, beers)) 58 | } else { 59 | ResponseEntity.notFound().build() 60 | } 61 | } 62 | 63 | 64 | } -------------------------------------------------------------------------------- /src/main/kotlin/be/kotlin/myrestapi/kotlinmyrestapi/controller/CountryController.kt: -------------------------------------------------------------------------------- 1 | package be.kotlin.myrestapi.kotlinmyrestapi.controller 2 | 3 | import be.kotlin.myrestapi.kotlinmyrestapi.data.CountryDto 4 | import be.kotlin.myrestapi.kotlinmyrestapi.data.CountryResource 5 | import be.kotlin.myrestapi.kotlinmyrestapi.repository.CountryRepository 6 | import org.springframework.http.HttpStatus 7 | import org.springframework.http.ResponseEntity 8 | import org.springframework.web.bind.annotation.* 9 | import sun.reflect.generics.tree.ReturnType 10 | import sun.security.provider.certpath.OCSPResponse 11 | 12 | @RestController 13 | @RequestMapping("/api") 14 | class CountryController(private val countryRepository: CountryRepository) { 15 | 16 | @GetMapping("/countries") 17 | fun getCountries():List = 18 | countryRepository.findAll().map { countryDto -> CountryResource(countryDto.id, countryDto.countryName) } 19 | 20 | 21 | 22 | 23 | @GetMapping("/country/{countryName}") 24 | fun getCountryByName(@PathVariable(value = "countryName") countryName: String): ResponseEntity? 25 | { 26 | var c = countryRepository.findByCountryName(countryName) 27 | 28 | return if (c != null) { 29 | ResponseEntity.ok(CountryResource(c.id, c.countryName)) 30 | } else { 31 | ResponseEntity.notFound().build() 32 | } 33 | } 34 | 35 | 36 | 37 | 38 | } -------------------------------------------------------------------------------- /src/main/kotlin/be/kotlin/myrestapi/kotlinmyrestapi/data/dto.kt: -------------------------------------------------------------------------------- 1 | package be.kotlin.myrestapi.kotlinmyrestapi.data 2 | 3 | import java.util.* 4 | import javax.persistence.* 5 | 6 | 7 | //Database Table representation classes. 8 | 9 | @Entity 10 | data class BeerDto( 11 | @Id 12 | @GeneratedValue(strategy = GenerationType.AUTO) 13 | val id: Long = -1, 14 | val beerName: String = "", 15 | val alcoholPercentage: Double = 0.0, 16 | val beerColour: String = "", 17 | @OneToOne 18 | val beerType: BeerTypeDto = BeerTypeDto(), 19 | @ManyToOne 20 | @JoinColumn(name="breweryId") 21 | val brewery: BreweryDto = BreweryDto()) 22 | 23 | @Entity 24 | data class BeerTypeDto( 25 | @Id 26 | @GeneratedValue(strategy=GenerationType.AUTO) 27 | val id: Long = 0, 28 | val beerType: String = "", 29 | val beerJudgeCertification: String = "") 30 | 31 | @Entity 32 | data class BreweryDto( 33 | @Id @GeneratedValue(strategy=GenerationType.AUTO) 34 | val id: Long = 0, 35 | val breweryName: String = "", 36 | val streetName: String = "", 37 | val houseNumber: String = "", 38 | val postalCode: String = "", 39 | val town: String = "", 40 | @OneToOne 41 | val country: CountryDto = CountryDto(), 42 | @OneToMany 43 | val beers: List = emptyList()) 44 | 45 | @Entity 46 | data class CountryDto( 47 | @Id 48 | @GeneratedValue(strategy=GenerationType.AUTO) 49 | val id: Long = 0, 50 | val countryName: String = "") -------------------------------------------------------------------------------- /src/main/kotlin/be/kotlin/myrestapi/kotlinmyrestapi/data/resources.kt: -------------------------------------------------------------------------------- 1 | package be.kotlin.myrestapi.kotlinmyrestapi.data 2 | 3 | 4 | //Resource representation classes 5 | //Exposed to the outside 6 | 7 | data class BeerResource(val id: Long, val beerName: String, val alcoholPercentage: Double, val beerColour: String, 8 | val beerTypeId: Long, val beerType: String, val beerJudge :String, val breweryId: Long, 9 | val breweryName: String) 10 | 11 | data class BeerTypeResource(val id: Long, val beerTypeName: String, val beerJudgeCertification: String) 12 | 13 | data class BreweryResource(val id: Long, val breweryName:String, val streetName: String, val houseNr: String, 14 | val postalCode: String, val town: String, val countryId :Long, val countryName: String) 15 | 16 | data class BreweryBeerResource(val brewery: BreweryResource, val beers: List?) 17 | 18 | data class CountryResource(val id: Long, val countryName: String) -------------------------------------------------------------------------------- /src/main/kotlin/be/kotlin/myrestapi/kotlinmyrestapi/repository/BeerRepository.kt: -------------------------------------------------------------------------------- 1 | package be.kotlin.myrestapi.kotlinmyrestapi.repository 2 | 3 | import be.kotlin.myrestapi.kotlinmyrestapi.data.BeerDto 4 | import be.kotlin.myrestapi.kotlinmyrestapi.data.BreweryDto 5 | import org.springframework.data.jpa.repository.JpaRepository 6 | 7 | interface BeerRepository : JpaRepository{ 8 | 9 | fun findByBeerName(beerName: String):Iterable 10 | 11 | fun findByAlcoholPercentage(percentage: Double):Iterable 12 | 13 | fun findByBeerTypeId(beerTypeId: Long): Iterable? 14 | 15 | fun findByBreweryId(breweryId: Long): Iterable? 16 | 17 | } -------------------------------------------------------------------------------- /src/main/kotlin/be/kotlin/myrestapi/kotlinmyrestapi/repository/BeerTypeRepository.kt: -------------------------------------------------------------------------------- 1 | package be.kotlin.myrestapi.kotlinmyrestapi.repository 2 | 3 | import be.kotlin.myrestapi.kotlinmyrestapi.data.BeerTypeDto 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | 6 | interface BeerTypeRepository : JpaRepository{ 7 | fun findByBeerType(beerTypeName: String): Iterable 8 | 9 | fun findByBeerJudgeCertification(beerTypeJudgeCertification: String): Iterable 10 | } -------------------------------------------------------------------------------- /src/main/kotlin/be/kotlin/myrestapi/kotlinmyrestapi/repository/BreweryRepository.kt: -------------------------------------------------------------------------------- 1 | package be.kotlin.myrestapi.kotlinmyrestapi.repository 2 | 3 | import be.kotlin.myrestapi.kotlinmyrestapi.data.BreweryDto 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | 6 | interface BreweryRepository : JpaRepository{ 7 | fun findByBreweryName(breweryName: String): Iterable 8 | } -------------------------------------------------------------------------------- /src/main/kotlin/be/kotlin/myrestapi/kotlinmyrestapi/repository/CountryRepository.kt: -------------------------------------------------------------------------------- 1 | package be.kotlin.myrestapi.kotlinmyrestapi.repository 2 | 3 | import be.kotlin.myrestapi.kotlinmyrestapi.data.CountryDto 4 | import org.springframework.data.jpa.repository.JpaRepository 5 | 6 | interface CountryRepository : JpaRepository{ 7 | 8 | fun findByCountryName(countryName: String): CountryDto? 9 | } -------------------------------------------------------------------------------- /src/main/kotlin/be/kotlin/myrestapi/kotlinmyrestapi/web/SwaggerConfiguration.kt: -------------------------------------------------------------------------------- 1 | package be.kotlin.myrestapi.kotlinmyrestapi.web 2 | 3 | import org.springframework.context.annotation.Bean 4 | import org.springframework.context.annotation.Configuration 5 | import springfox.documentation.swagger2.annotations.EnableSwagger2 6 | import springfox.documentation.builders.PathSelectors 7 | import springfox.documentation.builders.RequestHandlerSelectors 8 | import springfox.documentation.spi.DocumentationType 9 | import springfox.documentation.spring.web.plugins.Docket 10 | 11 | 12 | @Configuration 13 | @EnableSwagger2 14 | class SwaggerConfiguration { 15 | 16 | @Bean 17 | open fun api(): Docket = Docket(DocumentationType.SWAGGER_2) 18 | .select() 19 | .apis(RequestHandlerSelectors.any()) 20 | .paths(PathSelectors.any()) 21 | .build() 22 | } 23 | 24 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.url=jdbc:h2:mem:AZ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE 2 | spring.datasource.driverClassName=org.h2.Driver 3 | spring.datasource.username=sa 4 | spring.datasource.password= 5 | spring.jpa.database-platform=org.hibernate.dialect.H2Dialect 6 | -------------------------------------------------------------------------------- /src/test/kotlin/be/kotlin/myrestapi/kotlinmyrestapi/KotlinmyrestapiApplicationTests.kt: -------------------------------------------------------------------------------- 1 | package be.kotlin.myrestapi.kotlinmyrestapi 2 | 3 | import org.junit.Test 4 | import org.junit.runner.RunWith 5 | import org.springframework.boot.test.context.SpringBootTest 6 | import org.springframework.test.context.junit4.SpringRunner 7 | 8 | @RunWith(SpringRunner::class) 9 | @SpringBootTest 10 | class KotlinmyrestapiApplicationTests { 11 | 12 | @Test 13 | fun contextLoads() { 14 | return Unit 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.driver-class-name=org.h2.Driver 2 | spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_ON_EXIT=FALSE 3 | spring.datasource.username=sa 4 | spring.datasource.password=sa --------------------------------------------------------------------------------