Skip to content

Commit ba712bf

Browse files
committed
request validation docs
1 parent bb3b93e commit ba712bf

File tree

4 files changed

+168
-15
lines changed

4 files changed

+168
-15
lines changed

docs/docs/contract-testing.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,27 @@ Kappa has first-class support for testing if your API under testing conforms to
55

66
## Installation
77

8-
### Maven
9-
10-
```xml
11-
<dependency>
12-
<groupId>com.github.erosb</groupId>
13-
<artifactId>kappa-spring</artifactId>
14-
<version>2.0.0-RC15</version>
15-
</dependency>
16-
```
8+
=== "Maven"
9+
10+
```xml
11+
<dependency>
12+
<groupId>com.github.erosb</groupId>
13+
<artifactId>kappa-spring</artifactId>
14+
<version>2.0.0-RC16</version>
15+
</dependency>
16+
```
1717

18-
### Gradle
18+
=== "Gradle"
1919

20-
```kotlin
21-
testImplementation("com.github.erosb:kappa-spring:2.0.0-RC15")
22-
```
20+
```kotlin
21+
testImplementation("com.github.erosb:kappa-spring:2.0.0-RC16")
22+
```
2323

2424

2525

2626
## Add a contract-driven test
2727

28-
=== "Add an API definition"
28+
=== "Add an API description"
2929

3030
[`openapi/pets-api.yaml`](https://github.com/erosb/kappa-examples/blob/master/kappa-spring-boot-examples/src/main/resources/openapi/pets-api.yaml) :
3131

docs/docs/req-validation.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

docs/docs/request-validation.md

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,156 @@
11
# Request validation
22

3+
Kappa can validate your incoming HTTP requests against your OpenAPI descriptions. Malformed requests won't
4+
reach the spring controllers, hence the bad request will fail early. Still the HTTP client will receive a programmer-readable
5+
error description about what went wrong.
36

7+
## Installation
8+
9+
=== "Maven"
10+
11+
```xml
12+
<dependency>
13+
<groupId>com.github.erosb</groupId>
14+
<artifactId>kappa-spring</artifactId>
15+
<version>2.0.0-RC16</version>
16+
</dependency>
17+
```
18+
19+
=== "Gradle"
20+
21+
```kotlin
22+
testImplementation("com.github.erosb:kappa-spring:2.0.0-RC16")
23+
```
24+
25+
26+
## Enable OpenAPI-based HTTP request validation
27+
28+
=== "Add an API description"
29+
30+
[`openapi/pets-api.yaml`](https://github.com/erosb/kappa-examples/blob/master/kappa-spring-boot-examples/src/main/resources/openapi/pets-api.yaml) :
31+
32+
```yaml
33+
openapi: "3.1.0"
34+
info:
35+
title: "Pets API"
36+
version: 0.0.1
37+
paths:
38+
/api/pets:
39+
post:
40+
requestBody:
41+
content:
42+
application/json:
43+
schema:
44+
$ref: "#/components/schemas/CreatePetRequest"
45+
components:
46+
schemas:
47+
CreatePetRequest:
48+
type: object
49+
additionalProperties: false
50+
required:
51+
- name
52+
- owner
53+
properties:
54+
name:
55+
$ref: "#/components/schemas/Name"
56+
owner:
57+
$ref: "./common-types.yaml#/UserIdentifier"
58+
birthDate:
59+
type: string
60+
format: date
61+
Name:
62+
type: string
63+
minLength: 1
64+
```
65+
66+
=== "Configure Kappa"
67+
68+
[`KappaSpringBootExampleApplication.java`](https://github.com/erosb/kappa-examples/blob/master/kappa-spring-boot-examples/src/main/java/com/github/erosb/kappa/examples/KappaSpringBootExampleApplication.java):
69+
70+
```java
71+
@SpringBootApplication
72+
@EnableKappaRequestValidation // (1)
73+
public class KappaSpringBootExampleApplication {
74+
75+
public static void main(String[] args) {
76+
SpringApplication.run(KappaSpringBootExampleApplication.class, args);
77+
}
78+
79+
@Bean
80+
public KappaSpringConfiguration kappaConfig() {
81+
var kappaConfig = new KappaSpringConfiguration();
82+
var mapping = new LinkedHashMap<String, String>();
83+
mapping.put("/**", "/openapi/pets-api.yaml");
84+
kappaConfig.setOpenapiDescriptions(mapping);
85+
return kappaConfig;
86+
}
87+
}
88+
```
89+
90+
1. Sets up a servlet filter for validating incoming HTTP requests
91+
=== "Add the REST Controller"
92+
93+
```java
94+
record UserIdentifier(String id) {
95+
}
96+
97+
record CreatePetRequest(String name, UserIdentifier owner, LocalDate birthDate) {
98+
}
99+
100+
@RestController
101+
@RequestMapping("/api/pets")
102+
public class PetController {
103+
104+
@PostMapping
105+
void createPet(@RequestBody CreatePetRequest requestBody) {
106+
System.out.println("requestBody = " + requestBody);
107+
}
108+
}
109+
110+
```
111+
112+
## Try it out!
113+
114+
If you start `KappaSpringBootExampleApplication` and send a request with `curl` (or your preferred HTTP client), the request will
115+
also be validated:
116+
117+
```bash
118+
curl -XPOST http://localhost:8080/api/pets \
119+
-H 'content-type: application/json' \
120+
--data '{"name": null,"type":"cat","owner":{"id": -5},"birthDate":"20230708"}'
121+
```
122+
123+
the above command will print the following output:
124+
125+
```json
126+
{
127+
"errors" : [ {
128+
"dataLocation" : "$request.body#/type (line 1, position 22)",
129+
"schemaLocation" : "openapi/pets-api.yaml#/components/schemas/CreatePetRequest/additionalProperties",
130+
"dynamicPath" : "#/$ref/additionalProperties/false",
131+
"message" : "false schema always fails"
132+
}, {
133+
"dataLocation" : "$request.body#/name (line 1, position 10)",
134+
"schemaLocation" : "openapi/pets-api.yaml#/components/schemas/Name/type",
135+
"dynamicPath" : "#/$ref/properties/name/$ref/type",
136+
"message" : "expected type: string, actual: null"
137+
}, {
138+
"dataLocation" : "$request.body#/owner/id (line 1, position 43)",
139+
"schemaLocation" : "openapi/common-types.yaml#/Id",
140+
"dynamicPath" : "#/$ref/properties/owner/$ref/properties/id/$ref/minimum",
141+
"message" : "-5 is lower than minimum 0"
142+
}, {
143+
"dataLocation" : "$request.body#/birthDate (line 1, position 59)",
144+
"schemaLocation" : "openapi/pets-api.yaml#/components/schemas/CreatePetRequest/properties/birthDate/format",
145+
"dynamicPath" : "#/$ref/properties/birthDate/format",
146+
"message" : "instance does not match format 'date'"
147+
} ]
148+
}
149+
```
150+
151+
These json schema validation errors tell us the following problems with the json payload:
152+
153+
* the `"type"` field sent in the request is not recognized by the service
154+
* the `"name"` should be a string, never null, like in our request
155+
* the `"owner.id"` property should be non-negative, so `-5` is invalid
156+
* the `"birthDate"` also does not match the expected date format

docs/mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ theme:
1212
accent: light blue
1313
features:
1414
- content.code.annotate
15+
- content.code.copy
1516
markdown_extensions:
1617
- toc:
1718
permalink: true

0 commit comments

Comments
 (0)