Skip to content

Commit cf641f7

Browse files
committed
Add POST verb to create a greeting (beside GET verb)
1 parent fd11ec0 commit cf641f7

6 files changed

Lines changed: 58 additions & 8 deletions

File tree

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,6 @@ Analyses have to be POSTed first to the microservice before you can GET their re
2323

2424
## Swagger / OpenAPI
2525
There is an OpenAPI (former: Swagger) specification created, which is available at <http://localhost:8080/swagger/greeter-microservice-0.1.0.yml> (or somewhere in the jar file). It can easily be pasted into the [Swagger Editor](https://editor.swagger.io) which provides a live demo for [Swagger UI](https://swagger.io/tools/swagger-ui/), but also offers to create client libraries via [Swagger Codegen](https://swagger.io/tools/swagger-codegen/).
26-
27-
## Add greeting
28-
Actually, there is no POST endpoint in this simple example. But if there was one, a POST request could be sent like this:
29-
```
30-
$ curl -X POST -d @upload.json -H "Content-Type: application/json" -H "Accept: application/json" http://localhost/greetings/
31-
```
3226

3327
## Get greeting
3428
To get an appropriate greeting for a person, send a GET request to the service:
@@ -47,5 +41,11 @@ $ curl -X GET -H "Content-Type: application/json" -H "Accept: application/json"
4741
}
4842
```
4943

44+
## Add greeting
45+
In this example, a greeting can also be POSTed. This way, the payload is transferred in the body as JSON (which is often a better idea than putting it in the URL or parameters, due to URL encoding issues).
46+
```
47+
$ curl -X POST -d '{"name":"Max", "language":"de_DE"}' -H "Content-Type: application/json" -H "Accept: application/json" http://localhost/greetings/
48+
```
49+
5050
# Configuration
5151
There is a `application.yml` included in the jar file. Its content can be modified and saved as a separate `application.yml` on the level of the jar file. Configuration can also be applied via the other supported ways of Micronaut (see <https://docs.micronaut.io/latest/guide/index.html#config>). For Docker, the configuration via environment variables is the most interesting one (see `docker-compose.yml`).

src/main/kotlin/de/debuglevel/greeter/greeting/GreetingController.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package de.debuglevel.greeter.greeting
22

33
import io.micronaut.http.annotation.Controller
44
import io.micronaut.http.annotation.Get
5+
import io.micronaut.http.annotation.Post
56
import io.micronaut.security.annotation.Secured
67
import io.micronaut.security.rules.SecurityRule
78
import mu.KotlinLogging
@@ -27,6 +28,16 @@ class GreetingController(private val greetingService: GreetingService) {
2728
return greetingService.greet(name, language)
2829
}
2930

31+
/**
32+
* Get a greeting for a person. If given, the greeting is localized in a language.
33+
* @return A greeting for a person in a given language
34+
*/
35+
@Post("/")
36+
fun postOne(greetingRequest: GreetingRequest): Greeting {
37+
logger.debug("Called postOne($greetingRequest)")
38+
return greetingService.greet(greetingRequest.name, greetingRequest.language)
39+
}
40+
3041
/**
3142
* Gets some greetings.
3243
* @return Some greetings
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package de.debuglevel.greeter.greeting
2+
3+
data class GreetingRequest(
4+
val name: String,
5+
val language: String?
6+
)

src/test/kotlin/de/debuglevel/greeter/greeting/GreetingClient.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package de.debuglevel.greeter.greeting
22

33
import io.micronaut.http.annotation.Get
4+
import io.micronaut.http.annotation.Post
45
import io.micronaut.http.client.annotation.Client
56
import io.reactivex.Single
67
import javax.validation.constraints.NotBlank
@@ -11,6 +12,9 @@ interface GreetingClient {
1112
@Get("/{name}{?language}")
1213
fun getOne(@NotBlank name: String, language: String?): Single<GreetingDTO>
1314

15+
@Post("/")
16+
fun postOne(greetingRequest: GreetingRequest): Single<GreetingDTO>
17+
1418
// @Get
1519
// fun getList(): Set<GreetingDTO>
1620
}

src/test/kotlin/de/debuglevel/greeter/greeting/GreetingClientTests.kt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class GreetingClientTests {
1616

1717
@ParameterizedTest
1818
@MethodSource("validNameAndLanguageProvider")
19-
fun `greet valid names in various languages`(testData: TestDataProvider.NameTestData) {
19+
fun `greet valid names in various languages (GET)`(testData: TestDataProvider.NameTestData) {
2020
// Arrange
2121

2222
// Act
@@ -26,6 +26,19 @@ class GreetingClientTests {
2626
Assertions.assertThat(greeting.greeting).isEqualTo(testData.expected)
2727
}
2828

29+
@ParameterizedTest
30+
@MethodSource("validNameAndLanguageProvider")
31+
fun `greet valid names in various languages (POST)`(testData: TestDataProvider.NameTestData) {
32+
// Arrange
33+
val greetingRequest = GreetingRequest(testData.name, testData.language)
34+
35+
// Act
36+
val greeting = greetingClient.postOne(greetingRequest).blockingGet()
37+
38+
// Assert
39+
Assertions.assertThat(greeting.greeting).isEqualTo(testData.expected)
40+
}
41+
2942
fun validNameAndLanguageProvider() = TestDataProvider.validNameAndLanguageProvider()
3043

3144
// do not test "invalid" names (i.e. "" and " ") as their HTTP call would translate to "/greetings/" which then returns the getList() stuff

src/test/kotlin/de/debuglevel/greeter/greeting/GreetingControllerTests.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package de.debuglevel.greeter.greeting
22

3+
import io.micronaut.http.HttpRequest
34
import io.micronaut.http.client.HttpClient
45
import io.micronaut.http.client.annotation.Client
56
import io.micronaut.http.uri.UriBuilder
@@ -23,7 +24,7 @@ class GreetingControllerTests {
2324

2425
@ParameterizedTest
2526
@MethodSource("validNameAndLanguageProvider")
26-
fun `greet valid names in various languages`(testData: TestDataProvider.NameTestData) {
27+
fun `greet valid names in various languages (GET)`(testData: TestDataProvider.NameTestData) {
2728
// Arrange
2829

2930
// Act
@@ -38,6 +39,21 @@ class GreetingControllerTests {
3839
Assertions.assertThat(greeting).contains(testData.expected)
3940
}
4041

42+
@ParameterizedTest
43+
@MethodSource("validNameAndLanguageProvider")
44+
fun `greet valid names in various languages (POST)`(testData: TestDataProvider.NameTestData) {
45+
// Arrange
46+
val greetingRequest = GreetingRequest(testData.name, testData.language)
47+
48+
// Act
49+
val uri = UriBuilder.of("/").build()
50+
val greeting = httpClient.toBlocking()
51+
.retrieve(HttpRequest.POST(uri, greetingRequest), GreetingDTO::class.java)
52+
53+
// Assert
54+
Assertions.assertThat(greeting.greeting).isEqualTo(testData.expected)
55+
}
56+
4157
fun validNameAndLanguageProvider() = TestDataProvider.validNameAndLanguageProvider()
4258

4359
// do not test "invalid" names (i.e. "" and " ") as their HTTP call would translate to "/greetings/" which then returns the getList() stuff

0 commit comments

Comments
 (0)