Skip to content

Commit

Permalink
Add more Swagger docs. Inject version into JAR.
Browse files Browse the repository at this point in the history
  • Loading branch information
cstroe committed Dec 22, 2018
1 parent f85e52a commit 2e4d20a
Show file tree
Hide file tree
Showing 12 changed files with 86 additions and 71 deletions.
12 changes: 2 additions & 10 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,6 @@ compileTestKotlin.kotlinOptions {
val bootJar: BootJar by tasks
bootJar.archiveName = "app.jar"

// Customize JAR manifest to surface project version in app
tasks.jar {
manifest {
attributes(
"Implementation-Title" to "Checklister",
"Implementation-Version" to version
)
}
}

sourceSets {
create("integrationTest") {
compileClasspath += sourceSets.main.get().output
Expand Down Expand Up @@ -137,4 +127,6 @@ dependencies {

// integrationTestCompile("org.seleniumhq.selenium:selenium-java:3.13.0")
// integrationTestCompile("org.seleniumhq.selenium:selenium-remote-driver:3.13.0")

implementation(project("modules:buildconfig"))
}
11 changes: 11 additions & 0 deletions modules/buildconfig/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// this is in a sub-project because the buildconfig plugin doesn't work well
// with the kotlin plugin
plugins {
// https://github.com/mfuerstenau/gradle-buildconfig-plugin
id("de.fuerstenau.buildconfig") version "1.1.8"
}


buildConfig {
packageName = "cloud.cosmin.checklister"
}
3 changes: 2 additions & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
rootProject.name = "checklister"
rootProject.name = "checklister"
include("modules:buildconfig")
30 changes: 16 additions & 14 deletions src/main/kotlin/cloud/cosmin/checklister/config/SwaggerConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cloud.cosmin.checklister.config

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import springfox.documentation.builders.ApiInfoBuilder
import springfox.documentation.builders.RequestHandlerSelectors.basePackage
import springfox.documentation.service.ApiInfo
import springfox.documentation.service.Contact
Expand All @@ -14,22 +15,23 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2
class SwaggerConfig {
@Bean
fun checklisterApi(): Docket {
val appName = this.javaClass.`package`.implementationTitle
val version = this.javaClass.`package`.implementationVersion
val apiInfo = ApiInfo(
"Checklister API",
"A RESTful API for managing lists.",
version,
"",
Contact("GitHub", "https://github.com/cosmincloud/checklister", null),
"Apache License 2.0",
"https://www.apache.org/licenses/LICENSE-2.0",
listOf())

return Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo)
.apiInfo(apiInfo())
.select()
.apis(basePackage("cloud.cosmin.checklister.rest"))
.apis(basePackage("cloud.cosmin.checklister.rest"))
.build()
}

fun apiInfo(): ApiInfo {
val appName = this.javaClass.`package`.implementationTitle
val version = this.javaClass.`package`.implementationVersion
return ApiInfoBuilder()
.title("Checklister API")
.description("A RESTful API for lists.")
.contact(Contact("GitHub", "https://github.com/cosmincloud/checklister", null))
.version(version)
.license("Apache License Version 2.0")
.licenseUrl("https://www.apache.org/licenses/LICENSE-2.0")
.build()
}
}
6 changes: 2 additions & 4 deletions src/main/kotlin/cloud/cosmin/checklister/dao/ListEntity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ package cloud.cosmin.checklister.dao

import org.hibernate.annotations.Fetch
import org.hibernate.annotations.FetchMode

import java.util.Objects
import java.util.UUID
import java.util.*
import javax.persistence.*

@Entity
Expand All @@ -14,7 +12,7 @@ class ListEntity {
var id: UUID? = null

@Column(nullable = false)
var title: String? = null
var title: String = ""

@OneToMany(mappedBy = "list")
@Fetch(FetchMode.JOIN)
Expand Down
3 changes: 1 addition & 2 deletions src/main/kotlin/cloud/cosmin/checklister/dto/Dtos.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ data class ListGetDto(
)

data class ListPostDto(
@JsonProperty var uuid: UUID?,
@JsonProperty var title: String?
@JsonProperty var title: String
)

data class ListWithItemsDto(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@ package cloud.cosmin.checklister.rest
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import springfox.documentation.annotations.ApiIgnore
import cloud.cosmin.checklister.BuildConfig

@RestController
@ApiIgnore
class IndexController {
@RequestMapping(path = arrayOf("/"), produces = arrayOf("text/html"))
fun index(): String {
val name = BuildConfig.NAME
val version = BuildConfig.VERSION
return """
<html><body>
<h1>Checklister</h1>
<h1>${name}</h1>
<h2>${version}</h2>
<p>
<a href="swagger-ui.html">Swagger UI</a>
<a href="swagger-ui.html">API</a>
</p>
</body></html>
""".trimIndent()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import cloud.cosmin.checklister.dto.ItemGetDto
import cloud.cosmin.checklister.dto.ItemPostDto
import cloud.cosmin.checklister.repo.ItemRepo
import cloud.cosmin.checklister.service.ConverterService
import io.swagger.annotations.Api
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.*
import java.util.*

@Controller
@Api(description = "Operations on list items", tags = arrayOf("item"))
class ItemController
@Autowired
constructor(
Expand Down
55 changes: 24 additions & 31 deletions src/main/kotlin/cloud/cosmin/checklister/rest/ListController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,44 @@ package cloud.cosmin.checklister.rest

import cloud.cosmin.checklister.dao.ItemEntity
import cloud.cosmin.checklister.dao.ListEntity
import cloud.cosmin.checklister.dto.ItemGetDto
import cloud.cosmin.checklister.dto.ItemPostDto
import cloud.cosmin.checklister.dto.ListGetDto
import cloud.cosmin.checklister.dto.ListPostDto
import cloud.cosmin.checklister.dto.ListWithItemsDto
import cloud.cosmin.checklister.dto.*
import cloud.cosmin.checklister.repo.ItemRepo
import cloud.cosmin.checklister.repo.ListRepo
import cloud.cosmin.checklister.service.ConverterService
import cloud.cosmin.checklister.service.UuidService
import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController

import org.springframework.web.bind.annotation.*
import java.net.URI
import java.util.ArrayList
import java.util.Optional
import java.util.UUID
import java.util.*

@RestController
@Api(description = "Operations on lists", tags = arrayOf("list"))
class ListController @Autowired
constructor(
private val listRepo: ListRepo,
private val itemRepo: ItemRepo,
private val converterService: ConverterService
private val converterService: ConverterService,
private val uuidService: UuidService
) {

val allLists: ResponseEntity<List<ListGetDto>>
@GetMapping("/api/v1/list")
get() {
val lists = ArrayList<ListGetDto>()
for (list in listRepo.findAll()) {
val dto = converterService.listDto(list)
lists.add(dto)
}
return ResponseEntity.ok(lists)
@GetMapping("/api/v1/list")
@ApiOperation("Retrieve all lists")
fun allLists(): ResponseEntity<List<ListGetDto>> {
val lists = ArrayList<ListGetDto>()
for (list in listRepo.findAll()) {
val dto = converterService.listDto(list)
lists.add(dto)
}
return ResponseEntity.ok(lists)
}

@PostMapping(value = arrayOf("/api/v1/list"), consumes = arrayOf("application/json"))
@ApiOperation("Create a new list")
fun createList(@RequestBody listDto: ListPostDto): ResponseEntity<ListGetDto> {
val newList = ListEntity()
if (listDto.uuid != null) {
newList.id = listDto.uuid
} else {
newList.id = UUID.randomUUID()
}
newList.id = uuidService.get()
newList.title = listDto.title
val saved = listRepo.save(newList)
val dto = converterService.listDto(saved)
Expand All @@ -60,6 +49,7 @@ constructor(
}

@GetMapping("/api/v1/list/{listId}")
@ApiOperation("Retrieve a single list")
fun getList(@PathVariable listId: UUID?): ResponseEntity<ListGetDto> {
if (listId == null) {
return ResponseEntity.badRequest().build()
Expand Down Expand Up @@ -95,6 +85,7 @@ constructor(
}

@GetMapping("/api/v1/list/{listId}/item")
@ApiOperation("Retrieve all items in a list")
fun getListWithItems(@PathVariable listId: UUID): ResponseEntity<ListWithItemsDto> {
val optionalList = listRepo.findById(listId)
if (!optionalList.isPresent) {
Expand All @@ -116,6 +107,7 @@ constructor(
}

@PostMapping("/api/v1/list/{listId}/item")
@ApiOperation("Add an item to the list")
fun createListItem(@PathVariable listId: UUID?,
@RequestBody itemDto: ItemPostDto): ResponseEntity<ItemGetDto> {
if (listId == null) {
Expand Down Expand Up @@ -145,6 +137,7 @@ constructor(

// TODO: Add endpoint for direct item access (/api/v1/item/{itemId}) ?
@GetMapping("/api/v1/list/{listId}/item/{itemId}")
@ApiOperation("Retrieve a single item from a list")
fun getListItem(@PathVariable listId: UUID?,
@PathVariable itemId: UUID?): ResponseEntity<ItemGetDto> {
if (listId == null || itemId == null) {
Expand Down
11 changes: 11 additions & 0 deletions src/main/kotlin/cloud/cosmin/checklister/service/UuidService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package cloud.cosmin.checklister.service

import org.springframework.stereotype.Service
import java.util.*

@Service
class UuidService {
fun get(): UUID {
return UUID.randomUUID()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,11 @@ internal class ListPostDtoTest {
@Test @DisplayName("should be de-serialized by ObjectMapper")
fun canBeSerialized() {
val objectMapper = ObjectMapper().registerModule(KotlinModule())
val randomUUID = UUID.randomUUID()
val dto = objectMapper.readValue<ListPostDto>("""
{
"uuid": "${randomUUID}",
"title": "mytitle"
}
""".trimIndent(), ListPostDto::class.java)
assertEquals("mytitle", dto.title)
assertEquals(randomUUID, dto.uuid)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import cloud.cosmin.checklister.dto.ListPostDto
import cloud.cosmin.checklister.repo.ItemRepo
import cloud.cosmin.checklister.repo.ListRepo
import cloud.cosmin.checklister.service.ConverterService
import cloud.cosmin.checklister.service.UuidService
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
Expand All @@ -22,29 +23,33 @@ class ListControllerTest {
private val itemRepo: ItemRepo? = null
@Mock
private val converterService: ConverterService? = null
@Mock
private val uuidService: UuidService? = null
@InjectMocks
private val controller: ListController? = null

private val uuid: UUID = UUID.randomUUID()

@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
Mockito.`when`(uuidService!!.get()).thenReturn(uuid)
}

@Test
@Throws(Exception::class)
fun testCreate() {
val randomUUID = UUID.randomUUID()
val savedEntity = ListEntity()
savedEntity.id = randomUUID
savedEntity.id = uuid
savedEntity.title = "title"
Mockito.`when`(listRepo!!.save<ListEntity>(ArgumentMatchers.any())).thenReturn(savedEntity)

val listPostDto = ListPostDto(randomUUID, "title")
val listPostDto = ListPostDto("title")
val response = controller!!.createList(listPostDto)
assertEquals(HttpStatus.CREATED, response.statusCode)

val entity = ListEntity()
entity.id = randomUUID
entity.id = uuid
entity.title = "title"
verify(listRepo).save(entity)
}
Expand Down

0 comments on commit 2e4d20a

Please sign in to comment.