Skip to content

Commit 47998b4

Browse files
authored
KTLN-880 - API versioning with Kotlin And Spring Boot (#1083)
* KTLN-880 - API versioning with Kotlin And Spring Boot * Updated test names * Review comment addressed
1 parent 1cc17cc commit 47998b4

9 files changed

+242
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.baeldung.crud.versioning.controller
2+
3+
import org.springframework.web.bind.annotation.GetMapping
4+
import org.springframework.web.bind.annotation.RestController
5+
6+
@RestController
7+
class ContentNegotiationGreetingController {
8+
9+
@GetMapping("/greeting", produces = ["application/vnd.api.v1+json"])
10+
fun greetingV1(): Map<String, String> {
11+
return mapOf("message" to "Hello, welcome to the API v1!")
12+
}
13+
14+
@GetMapping("/greeting", produces = ["application/vnd.api.v2+json"])
15+
fun greetingV2(): Map<String, String> {
16+
val messageMap = HashMap<String, String>()
17+
messageMap["message"] = "Hello, welcome to the API v2!"
18+
messageMap["additionalInfo"] = "This is additional information for API v2"
19+
return messageMap
20+
}
21+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.baeldung.crud.versioning.controller
2+
3+
import org.springframework.web.bind.annotation.GetMapping
4+
import org.springframework.web.bind.annotation.RestController
5+
6+
@RestController
7+
class GreetingController {
8+
9+
@GetMapping("/greeting")
10+
fun greeting(): String {
11+
return "Hello, welcome to the API!"
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.baeldung.crud.versioning.controller
2+
3+
import org.springframework.web.bind.annotation.GetMapping
4+
import org.springframework.web.bind.annotation.RestController
5+
6+
@RestController
7+
class HeaderBasedGreetingController {
8+
9+
@GetMapping("/greeting", headers = ["X-API-Version=1"])
10+
fun greetingV1(): String {
11+
return "Hello, welcome to the API v1!"
12+
}
13+
14+
@GetMapping("/greeting", headers = ["X-API-Version=2"])
15+
fun greetingV2(): String {
16+
return "Hello, welcome to the API v2!"
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.baeldung.crud.versioning.controller
2+
3+
import org.springframework.web.bind.annotation.GetMapping
4+
import org.springframework.web.bind.annotation.RestController
5+
6+
@RestController
7+
class PathBasedGreetingController {
8+
9+
@GetMapping("/v1/greeting")
10+
fun greetingV1(): String {
11+
return "Hello, welcome to the API v1!"
12+
}
13+
14+
@GetMapping("/v2/greeting")
15+
fun greetingV2(): String {
16+
return "Hello, welcome to the API v2!"
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.baeldung.crud.versioning.controller
2+
3+
import org.springframework.web.bind.annotation.GetMapping
4+
import org.springframework.web.bind.annotation.RestController
5+
6+
@RestController
7+
class QueryBasedGreetingController {
8+
9+
@GetMapping("/greeting", params = ["version=1"])
10+
fun greetingV1(): String {
11+
return "Hello, welcome to the API v1!"
12+
}
13+
14+
@GetMapping("/greeting", params = ["version=2"])
15+
fun greetingV2(): String {
16+
return "Hello, welcome to the API v2!"
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.baeldung.versioning.controller
2+
3+
import org.assertj.core.api.Assertions.assertThat
4+
import org.junit.jupiter.api.Test
5+
import org.springframework.beans.factory.annotation.Autowired
6+
import org.springframework.boot.test.context.SpringBootTest
7+
import org.springframework.boot.test.web.client.TestRestTemplate
8+
import org.springframework.boot.test.web.server.LocalServerPort
9+
import org.springframework.core.ParameterizedTypeReference
10+
import org.springframework.http.HttpEntity
11+
import org.springframework.http.HttpHeaders
12+
import org.springframework.http.HttpMethod
13+
import org.springframework.http.HttpStatus
14+
15+
@SpringBootTest(classes = [com.baeldung.crud.SpringBootCrudApplication::class], webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
16+
class ContentNegotiationGreetingControllerIntegrationTest {
17+
18+
@Autowired
19+
lateinit var testRestTemplate: TestRestTemplate
20+
21+
@LocalServerPort
22+
var port: Int = 0
23+
24+
@Test
25+
fun `given version 1 in Accept header when greeting then return v1 message`() {
26+
val headers = HttpHeaders()
27+
headers.set("Accept", "application/vnd.api.v1+json")
28+
val entity = HttpEntity<String>(headers)
29+
val response = testRestTemplate.exchange("http://localhost:$port/greeting",
30+
HttpMethod.GET, entity, object : ParameterizedTypeReference<Map<String, String>>() {})
31+
assertThat(response.statusCode).isEqualTo(HttpStatus.OK)
32+
assertThat(response.body).containsEntry("message", "Hello, welcome to the API v1!")
33+
}
34+
35+
@Test
36+
fun `given version 2 in Accept header when greeting then return v2 message`() {
37+
val headers = HttpHeaders()
38+
headers.set("Accept", "application/vnd.api.v2+json")
39+
val entity = HttpEntity<String>(headers)
40+
val response = testRestTemplate.exchange("http://localhost:$port/greeting",
41+
HttpMethod.GET, entity, object : ParameterizedTypeReference<Map<String, String>>() {})
42+
assertThat(response.statusCode).isEqualTo(HttpStatus.OK)
43+
assertThat(response.body).containsEntry("message", "Hello, welcome to the API v2!")
44+
assertThat(response.body).containsEntry("additionalInfo", "This is additional information for API v2")
45+
}
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.baeldung.versioning.controller
2+
3+
import org.assertj.core.api.Assertions.assertThat
4+
import org.junit.jupiter.api.Test
5+
import org.springframework.beans.factory.annotation.Autowired
6+
import org.springframework.boot.test.context.SpringBootTest
7+
import org.springframework.boot.test.web.client.TestRestTemplate
8+
import org.springframework.boot.test.web.server.LocalServerPort
9+
import org.springframework.http.HttpEntity
10+
import org.springframework.http.HttpHeaders
11+
import org.springframework.http.HttpMethod
12+
import org.springframework.http.HttpStatus
13+
14+
@SpringBootTest(classes = [com.baeldung.crud.SpringBootCrudApplication::class], webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
15+
class HeaderBasedGreetingControllerIntegrationTest {
16+
17+
@Autowired
18+
lateinit var testRestTemplate: TestRestTemplate
19+
20+
@LocalServerPort
21+
var port: Int = 0
22+
23+
@Test
24+
fun `given version 1 in header when greeting then return v1 message`() {
25+
val headers = HttpHeaders()
26+
headers.set("X-API-Version", "1")
27+
val entity = HttpEntity<String>(headers)
28+
val response = testRestTemplate.exchange("http://localhost:$port/greeting", HttpMethod.GET, entity, String::class.java)
29+
assertThat(response.statusCode).isEqualTo(HttpStatus.OK)
30+
assertThat(response.body).isEqualTo("Hello, welcome to the API v1!")
31+
}
32+
33+
@Test
34+
fun `given version 2 in header when greeting then return v2 message`() {
35+
val headers = HttpHeaders()
36+
headers.set("X-API-Version", "2")
37+
val entity = HttpEntity<String>(headers)
38+
val response = testRestTemplate.exchange("http://localhost:$port/greeting", HttpMethod.GET, entity, String::class.java)
39+
assertThat(response.statusCode).isEqualTo(HttpStatus.OK)
40+
assertThat(response.body).isEqualTo("Hello, welcome to the API v2!")
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.baeldung.versioning.controller
2+
3+
import org.assertj.core.api.Assertions.assertThat
4+
import org.junit.jupiter.api.Test
5+
import org.springframework.beans.factory.annotation.Autowired
6+
import org.springframework.boot.test.context.SpringBootTest
7+
import org.springframework.boot.test.web.client.TestRestTemplate
8+
import org.springframework.boot.test.web.server.LocalServerPort
9+
import org.springframework.http.HttpStatus
10+
11+
@SpringBootTest(classes = [com.baeldung.crud.SpringBootCrudApplication::class], webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
12+
class PathBasedGreetingControllerIntegrationTest {
13+
14+
@Autowired
15+
lateinit var testRestTemplate: TestRestTemplate
16+
17+
@LocalServerPort
18+
var port: Int = 0
19+
20+
@Test
21+
fun `given version 1 in path when greeting then return v1 message`() {
22+
val response = testRestTemplate.getForEntity("http://localhost:$port/v1/greeting", String::class.java)
23+
assertThat(response.statusCode).isEqualTo(HttpStatus.OK)
24+
assertThat(response.body).isEqualTo("Hello, welcome to the API v1!")
25+
}
26+
27+
@Test
28+
fun `given version 2 in path when greeting then return v2 message`() {
29+
val response = testRestTemplate.getForEntity("http://localhost:$port/v2/greeting", String::class.java)
30+
assertThat(response.statusCode).isEqualTo(HttpStatus.OK)
31+
assertThat(response.body).isEqualTo("Hello, welcome to the API v2!")
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.baeldung.versioning.controller
2+
3+
import org.assertj.core.api.Assertions.assertThat
4+
import org.junit.jupiter.api.Test
5+
import org.springframework.beans.factory.annotation.Autowired
6+
import org.springframework.boot.test.context.SpringBootTest
7+
import org.springframework.boot.test.web.client.TestRestTemplate
8+
import org.springframework.boot.test.web.server.LocalServerPort
9+
import org.springframework.http.HttpStatus
10+
11+
@SpringBootTest(classes = [com.baeldung.crud.SpringBootCrudApplication::class], webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
12+
class QueryBasedGreetingControllerIntegrationTest {
13+
14+
@Autowired
15+
lateinit var testRestTemplate: TestRestTemplate
16+
17+
@LocalServerPort
18+
var port: Int = 0
19+
20+
@Test
21+
fun `given version 1 in query param when greeting then return v1 message`() {
22+
val response = testRestTemplate.getForEntity("http://localhost:$port/greeting?version=1", String::class.java)
23+
assertThat(response.statusCode).isEqualTo(HttpStatus.OK)
24+
assertThat(response.body).isEqualTo("Hello, welcome to the API v1!")
25+
}
26+
27+
@Test
28+
fun `given version 2 in query param when greeting then return v2 message`() {
29+
val response = testRestTemplate.getForEntity("http://localhost:$port/greeting?version=2", String::class.java)
30+
assertThat(response.statusCode).isEqualTo(HttpStatus.OK)
31+
assertThat(response.body).isEqualTo("Hello, welcome to the API v2!")
32+
}
33+
}

0 commit comments

Comments
 (0)