Skip to content

Commit 9e12ce9

Browse files
author
Jens Zettelmeyer
committed
Implement missing http verbs
1 parent 88ec615 commit 9e12ce9

File tree

11 files changed

+244
-9
lines changed

11 files changed

+244
-9
lines changed

src/main/kotlin/com/cjbooms/fabrikt/generators/client/JDKHttpSimpleClientGenerator.kt

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import com.cjbooms.fabrikt.generators.client.ClientGeneratorUtils.simpleClientNa
1313
import com.cjbooms.fabrikt.generators.client.ClientGeneratorUtils.toClientReturnType
1414
import com.cjbooms.fabrikt.model.*
1515
import com.cjbooms.fabrikt.util.KaizenParserExtensions.routeToPaths
16+
import com.cjbooms.fabrikt.util.toUpperCase
1617
import com.fasterxml.jackson.databind.ObjectMapper
1718
import com.github.javaparser.utils.CodeGenerationUtils
1819
import com.reprezen.kaizen.oasparser.model3.Operation
@@ -129,15 +130,28 @@ data class SimpleJDKClientOperationStatement(
129130
this.add("\nval requestBuilder: %T.Builder = HttpRequest.newBuilder()", "HttpRequest".toClassName(httpBasePackage))
130131
this.add("\n.uri(httpUri)")
131132

132-
/*when (val op = verb.toUpperCase()) {
133-
"PUT" -> this.addRequestSerializerStatement("put")
134-
"POST" -> this.addRequestSerializerStatement("post")
135-
"PATCH" -> this.addRequestSerializerStatement("patch")
136-
"HEAD" -> this.add("\n.head()")
137-
"GET" -> this.add("\n.get()")
138-
"DELETE" -> this.add("\n.delete()")
133+
when (val op = verb.toUpperCase()) {
134+
"PUT" -> {
135+
parameters.filterIsInstance<BodyParameter>().firstOrNull()?.let {
136+
this.add("\n.PUT(Publishers.jsonBodyPublisher(%N))", it.name)
137+
}
138+
}
139+
"POST" -> {
140+
parameters.filterIsInstance<BodyParameter>().firstOrNull()?.let {
141+
this.add("\n.POST(Publishers.jsonBodyPublisher(%N))", it.name)
142+
}
143+
}
144+
"PATCH" -> {
145+
parameters.filterIsInstance<BodyParameter>().firstOrNull()?.let {
146+
this.add("\n.method(\"PATCH\", Publishers.jsonBodyPublisher(%N))", it.name)
147+
}
148+
}
149+
"HEAD" -> this.add("\n.method(\"HEAD\", %T.noBody())", "BodyPublishers".toClassName("$httpBasePackage.HttpRequest"))
150+
"GET" -> this.add("\n.GET()")
151+
"DELETE" -> this.add("\n.DELETE()")
139152
else -> throw NotImplementedError("API operation $op is not supported")
140-
}*/
153+
}
154+
141155
return this
142156
}
143157

src/main/resources/templates/jdk-client-code/http-util.kt.hbs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package {{ client }}
22

33
import com.fasterxml.jackson.databind.ObjectMapper
4+
import jdk.internal.net.http.RequestPublishers
45
import java.io.IOException
56
import java.io.InputStream
67
import java.io.UncheckedIOException
@@ -55,3 +56,10 @@ class JsonBodyHandler<W>(val wClass: Class<W>) : BodyHandler<Supplier<W>> {
5556
return asJSON(wClass)
5657
}
5758
}
59+
60+
object Publishers {
61+
fun <W> jsonBodyPublisher(obj: W) : HttpRequest.BodyPublisher {
62+
val data = ObjectMapper().writeValueAsBytes(obj)
63+
return RequestPublishers.ByteArrayPublisher(data)
64+
}
65+
}

src/test/resources/examples/httpClient/api.yaml

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,22 @@ paths:
122122
responses:
123123
204:
124124
description: "Operation successful"
125+
delete:
126+
summary: "DELETE example path 3"
127+
response:
128+
200:
129+
description: "Operation successful"
130+
131+
/example-path-3/{path_param}/subresource/name:
132+
patch:
133+
summary: "PATCH example path 3"
134+
parameters:
135+
- $ref: "#/components/parameters/PathParam"
136+
requestBody:
137+
$ref: "#/components/requestBodies/PatchBody"
138+
responses:
139+
204:
140+
description: "Operation successful"
125141

126142
components:
127143
parameters:
@@ -224,7 +240,12 @@ components:
224240
application/json:
225241
schema:
226242
$ref: "#/components/schemas/FirstModel"
227-
243+
PatchBody:
244+
required: true
245+
content:
246+
application/json:
247+
schema:
248+
$ref: "#/components/schema/FirstModelPatch"
228249

229250
schemas:
230251
QueryResult:
@@ -290,11 +311,20 @@ components:
290311
second_model: "#/components/schemas/SecondModel"
291312
third_model: "#/components/schemas/ThirdModel"
292313

314+
FirstModelPatch:
315+
- type: "object"
316+
properties:
317+
name:
318+
description: "Same random name"
319+
type: string
293320
FirstModel:
294321
allOf:
295322
- $ref: "#/components/schemas/Content"
296323
- type: "object"
297324
properties:
325+
name:
326+
description: "Same random name"
327+
type: string
298328
extra_first_attr:
299329
description: "The attribute 1 for model 1"
300330
type: array

src/test/resources/examples/httpClient/client/ApiClient.kt

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import okhttp3.MediaType.Companion.toMediaType
1212
import okhttp3.OkHttpClient
1313
import okhttp3.Request
1414
import okhttp3.RequestBody.Companion.toRequestBody
15+
import kotlin.Any
1516
import kotlin.Boolean
1617
import kotlin.Int
1718
import kotlin.String
@@ -247,4 +248,68 @@ public class ExamplePath3SubresourceClient(
247248

248249
return request.execute(client, objectMapper, jacksonTypeRef())
249250
}
251+
252+
/**
253+
* DELETE example path 3
254+
*/
255+
@Throws(ApiException::class)
256+
public fun deleteExamplePath3PathParamSubresource(
257+
additionalHeaders: Map<String, String> =
258+
emptyMap(),
259+
): ApiResponse<Unit> {
260+
val httpUrl: HttpUrl = "$baseUrl/example-path-3/{path_param}/subresource"
261+
.toHttpUrl()
262+
.newBuilder()
263+
.build()
264+
265+
val headerBuilder = Headers.Builder()
266+
additionalHeaders.forEach { headerBuilder.header(it.key, it.value) }
267+
val httpHeaders: Headers = headerBuilder.build()
268+
269+
val request: Request = Request.Builder()
270+
.url(httpUrl)
271+
.headers(httpHeaders)
272+
.delete()
273+
.build()
274+
275+
return request.execute(client, objectMapper, jacksonTypeRef())
276+
}
277+
}
278+
279+
@Suppress("unused")
280+
public class ExamplePath3SubresourceNameClient(
281+
private val objectMapper: ObjectMapper,
282+
private val baseUrl: String,
283+
private val client: OkHttpClient,
284+
) {
285+
/**
286+
* PATCH example path 3
287+
*
288+
* @param firstModelPatch
289+
* @param pathParam The resource id
290+
*/
291+
@Throws(ApiException::class)
292+
public fun patchExamplePath3PathParamSubresourceName(
293+
firstModelPatch: Any,
294+
pathParam: String,
295+
additionalHeaders: Map<String, String> = emptyMap(),
296+
): ApiResponse<Unit> {
297+
val httpUrl: HttpUrl = "$baseUrl/example-path-3/{path_param}/subresource/name"
298+
.pathParam("{path_param}" to pathParam)
299+
.toHttpUrl()
300+
.newBuilder()
301+
.build()
302+
303+
val headerBuilder = Headers.Builder()
304+
additionalHeaders.forEach { headerBuilder.header(it.key, it.value) }
305+
val httpHeaders: Headers = headerBuilder.build()
306+
307+
val request: Request = Request.Builder()
308+
.url(httpUrl)
309+
.headers(httpHeaders)
310+
.patch(objectMapper.writeValueAsString(firstModelPatch).toRequestBody("application/json".toMediaType()))
311+
.build()
312+
313+
return request.execute(client, objectMapper, jacksonTypeRef())
314+
}
250315
}

src/test/resources/examples/httpClient/client/ApiService.kt

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import examples.httpClient.models.FirstModel
66
import examples.httpClient.models.QueryResult
77
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry
88
import okhttp3.OkHttpClient
9+
import kotlin.Any
910
import kotlin.Boolean
1011
import kotlin.Int
1112
import kotlin.String
@@ -143,4 +144,44 @@ public class ExamplePath3SubresourceService(
143144
withCircuitBreaker(circuitBreakerRegistry, circuitBreakerName) {
144145
apiClient.putExamplePath3PathParamSubresource(firstModel, pathParam, ifMatch, csvListQueryParam, additionalHeaders)
145146
}
147+
148+
@Throws(ApiException::class)
149+
public fun deleteExamplePath3PathParamSubresource(
150+
additionalHeaders: Map<String, String> =
151+
emptyMap(),
152+
): ApiResponse<Unit> =
153+
withCircuitBreaker(circuitBreakerRegistry, circuitBreakerName) {
154+
apiClient.deleteExamplePath3PathParamSubresource(additionalHeaders)
155+
}
156+
}
157+
158+
/**
159+
* The circuit breaker registry should have the proper configuration to correctly action on circuit
160+
* breaker transitions based on the client exceptions [ApiClientException], [ApiServerException] and
161+
* [IOException].
162+
*
163+
* @see ApiClientException
164+
* @see ApiServerException
165+
*/
166+
@Suppress("unused")
167+
public class ExamplePath3SubresourceNameService(
168+
private val circuitBreakerRegistry: CircuitBreakerRegistry,
169+
objectMapper: ObjectMapper,
170+
baseUrl: String,
171+
client: OkHttpClient,
172+
) {
173+
public var circuitBreakerName: String = "examplePath3SubresourceNameClient"
174+
175+
private val apiClient: ExamplePath3SubresourceNameClient =
176+
ExamplePath3SubresourceNameClient(objectMapper, baseUrl, client)
177+
178+
@Throws(ApiException::class)
179+
public fun patchExamplePath3PathParamSubresourceName(
180+
firstModelPatch: Any,
181+
pathParam: String,
182+
additionalHeaders: Map<String, String> = emptyMap(),
183+
): ApiResponse<Unit> =
184+
withCircuitBreaker(circuitBreakerRegistry, circuitBreakerName) {
185+
apiClient.patchExamplePath3PathParamSubresourceName(firstModelPatch, pathParam, additionalHeaders)
186+
}
146187
}

src/test/resources/examples/httpClient/client/jdk/ApiClient.kt

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import examples.httpClient.jdk.models.QueryResult
77
import java.net.URI
88
import java.net.http.HttpClient
99
import java.net.http.HttpRequest
10+
import java.net.http.HttpRequest.BodyPublishers
11+
import kotlin.Any
1012
import kotlin.Boolean
1113
import kotlin.Int
1214
import kotlin.String
@@ -37,6 +39,7 @@ public class ExamplePath1Client(
3739
val httpUri: URI = URI.create("$baseUrl/example-path-1")
3840
val requestBuilder: HttpRequest.Builder = HttpRequest.newBuilder()
3941
.uri(httpUri)
42+
.GET()
4043
additionalHeaders.forEach { requestBuilder.header(it.key, it.value) }
4144
return client.execute(requestBuilder.build())
4245
}
@@ -56,6 +59,7 @@ public class ExamplePath1Client(
5659
val httpUri: URI = URI.create("$baseUrl/example-path-1")
5760
val requestBuilder: HttpRequest.Builder = HttpRequest.newBuilder()
5861
.uri(httpUri)
62+
.POST(Publishers.jsonBodyPublisher(content))
5963
additionalHeaders.forEach { requestBuilder.header(it.key, it.value) }
6064
return client.execute(requestBuilder.build())
6165
}
@@ -86,6 +90,7 @@ public class ExamplePath2Client(
8690
val httpUri: URI = URI.create("$baseUrl/example-path-2/{path_param}")
8791
val requestBuilder: HttpRequest.Builder = HttpRequest.newBuilder()
8892
.uri(httpUri)
93+
.GET()
8994
additionalHeaders.forEach { requestBuilder.header(it.key, it.value) }
9095
return client.execute(requestBuilder.build())
9196
}
@@ -107,6 +112,7 @@ public class ExamplePath2Client(
107112
val httpUri: URI = URI.create("$baseUrl/example-path-2/{path_param}")
108113
val requestBuilder: HttpRequest.Builder = HttpRequest.newBuilder()
109114
.uri(httpUri)
115+
.method("HEAD", BodyPublishers.noBody())
110116
additionalHeaders.forEach { requestBuilder.header(it.key, it.value) }
111117
return client.execute(requestBuilder.build())
112118
}
@@ -128,6 +134,7 @@ public class ExamplePath2Client(
128134
val httpUri: URI = URI.create("$baseUrl/example-path-2/{path_param}")
129135
val requestBuilder: HttpRequest.Builder = HttpRequest.newBuilder()
130136
.uri(httpUri)
137+
.PUT(Publishers.jsonBodyPublisher(firstModel))
131138
additionalHeaders.forEach { requestBuilder.header(it.key, it.value) }
132139
return client.execute(requestBuilder.build())
133140
}
@@ -158,6 +165,50 @@ public class ExamplePath3SubresourceClient(
158165
val httpUri: URI = URI.create("$baseUrl/example-path-3/{path_param}/subresource")
159166
val requestBuilder: HttpRequest.Builder = HttpRequest.newBuilder()
160167
.uri(httpUri)
168+
.PUT(Publishers.jsonBodyPublisher(firstModel))
169+
additionalHeaders.forEach { requestBuilder.header(it.key, it.value) }
170+
return client.execute(requestBuilder.build())
171+
}
172+
173+
/**
174+
* DELETE example path 3
175+
*/
176+
@Throws(ApiException::class)
177+
public fun deleteExamplePath3PathParamSubresource(
178+
additionalHeaders: Map<String, String> =
179+
emptyMap(),
180+
): ApiResponse<Unit> {
181+
val httpUri: URI = URI.create("$baseUrl/example-path-3/{path_param}/subresource")
182+
val requestBuilder: HttpRequest.Builder = HttpRequest.newBuilder()
183+
.uri(httpUri)
184+
.DELETE()
185+
additionalHeaders.forEach { requestBuilder.header(it.key, it.value) }
186+
return client.execute(requestBuilder.build())
187+
}
188+
}
189+
190+
@Suppress("unused")
191+
public class ExamplePath3SubresourceNameClient(
192+
private val objectMapper: ObjectMapper,
193+
private val baseUrl: String,
194+
private val client: HttpClient,
195+
) {
196+
/**
197+
* PATCH example path 3
198+
*
199+
* @param firstModelPatch
200+
* @param pathParam The resource id
201+
*/
202+
@Throws(ApiException::class)
203+
public fun patchExamplePath3PathParamSubresourceName(
204+
firstModelPatch: Any,
205+
pathParam: String,
206+
additionalHeaders: Map<String, String> = emptyMap(),
207+
): ApiResponse<Unit> {
208+
val httpUri: URI = URI.create("$baseUrl/example-path-3/{path_param}/subresource/name")
209+
val requestBuilder: HttpRequest.Builder = HttpRequest.newBuilder()
210+
.uri(httpUri)
211+
.method("PATCH", Publishers.jsonBodyPublisher(firstModelPatch))
161212
additionalHeaders.forEach { requestBuilder.header(it.key, it.value) }
162213
return client.execute(requestBuilder.build())
163214
}

src/test/resources/examples/httpClient/client/jdk/HttpUtil.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package examples.httpClient.jdk.client
22

33
import com.fasterxml.jackson.databind.ObjectMapper
4+
import jdk.internal.net.http.RequestPublishers
45
import java.io.IOException
56
import java.io.InputStream
67
import java.io.UncheckedIOException
@@ -55,3 +56,10 @@ class JsonBodyHandler<W>(val wClass: Class<W>) : BodyHandler<Supplier<W>> {
5556
return asJSON(wClass)
5657
}
5758
}
59+
60+
object Publishers {
61+
fun <W> jsonBodyPublisher(obj: W) : HttpRequest.BodyPublisher {
62+
val data = ObjectMapper().writeValueAsBytes(obj)
63+
return RequestPublishers.ByteArrayPublisher(data)
64+
}
65+
}

src/test/resources/examples/httpClient/models/Models.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ public data class FirstModel(
111111
@param:JsonProperty("etag")
112112
@get:JsonProperty("etag")
113113
override val etag: String? = null,
114+
@param:JsonProperty("name")
115+
@get:JsonProperty("name")
116+
public val name: String? = null,
114117
@param:JsonProperty("extra_first_attr")
115118
@get:JsonProperty("extra_first_attr")
116119
public val extraFirstAttr: List<String>? = null,

src/test/resources/examples/httpClient/models/jdk/Models.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ public data class FirstModel(
111111
@param:JsonProperty("etag")
112112
@get:JsonProperty("etag")
113113
override val etag: String? = null,
114+
@param:JsonProperty("name")
115+
@get:JsonProperty("name")
116+
public val name: String? = null,
114117
@param:JsonProperty("extra_first_attr")
115118
@get:JsonProperty("extra_first_attr")
116119
public val extraFirstAttr: List<String>? = null,

0 commit comments

Comments
 (0)