-
-
Notifications
You must be signed in to change notification settings - Fork 481
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consumer Kotlin DSL API proposal #1352
Comments
I think this would be a great enhancement. One thing I would consider is to not wrap the existing DSL as it has been written based on the constraints imposed by Java. I think creating the Kotlin DSL as a first class citizen would be better. @abubics thoughts? |
Cool 😃
Sure. We wrote it this way because we didn't want to "touch the internals", but if it were to be added here, I agree that it should be a first-class citizen (like Groovy DSL). |
Great concept, I love it 🎉 As for Kotlin first-class, that also sounds great . . . the Java classes end up a bit clunky/brittle, so whatever we can do to avoid repeating/using those is a good step. |
For reference, this is my current set of helper wrappers, much less DSL-style, but lightweight enough: fun pactBuilder() = ConsumerPactBuilder
.consumer("REDACTED-api-test-consumer")
.hasPactWith("REDACTED-api")
fun buildPact(builder: PactDslWithProvider.() -> PactDslResponse): RequestResponsePact = pactBuilder().builder().toPact()
operator fun <R> BasePact.invoke(auth: Boolean = true, createCall: ApiClient.() -> Call<R>): R? {
println()
val result: PactVerificationResult = runConsumerTest(
this,
MockProviderConfig.createDefault(),
object : PactTestRun<Response<R>> {
override fun run(mockServer: MockServer, context: PactTestExecutionContext?): Response<R> {
val client = buildClient<ApiClient>(mockServer.getUrl(), auth)
return client.createCall().execute()
}
}
)
println("testPact result: $result")
return ((result as? Ok)?.result as? Response<R>?)?.body()
}
fun PactDslRequestWithPath.jsonHeader() =
matchHeader("Content-Type", "^application/json.*$", "application/json; charset utf-8")
fun PactDslRequestWithPath.authHeader() =
matchHeader("Authorization", "^Basic .*$", "Basic base64string")
fun oneOf(vararg values: String): String = values.joinToString("|")
fun LambdaDslObject.localDateTime(fieldName: String, example: String): LambdaDslObject = datetime(
fieldName,
"YYYY-MM-DD'T'HH:mm:SS",
LocalDateTime.parse(example).toInstant(ZoneOffset.of("+11:00"))
)
fun LambdaDslJsonBody.arrayLike(fieldName: String, eachBuilder: LambdaDslObject.() -> Unit): LambdaDslObject =
minArrayLike(fieldName, 1) { eachBuilder(it) }
infix fun PactDslRequestWithPath.jsonBody(bodyBuilder: LambdaDslJsonBody.() -> Unit): PactDslRequestWithPath =
body(LambdaDsl.newJsonBody(bodyBuilder).build())
infix fun PactDslResponse.jsonBody(bodyBuilder: LambdaDslJsonBody.() -> Unit): PactDslResponse =
body(LambdaDsl.newJsonBody(bodyBuilder).build()) As you can see, there's a bit of repetition where the Java DSL has a few classes with very similar interfaces, because they're not quite a mutable builder pattern. |
Thank you 😊
We considered many options before we came up with minus (e.g. other operators like We even considered using delegated properties ( In general, we put ease of reading first, and ease of writing second (where ease of writing was supposed to significantly surpass that of Groovy DSL, anyway). |
Nice work! I really like the idea of a first class kotlin DSL, especially one that is idiomatic to Kotlin. You might also be interested in the guideline here:
I'm nervous about the operator overloading (to me, it hinders readability, because I read it as |
Yes, thank you! I believe this actually rules the "declarative" flavor out.
Yes, it might be confusing at first, but once you get used to reading
You can actually see this even in official Kotlin DSL docs: https://kotlinlang.org/docs/type-safe-builders.html Having said all that, I understand the doubts - what worked in the context of my company (declarative flavor, overloaded minus) might not be the best option here (here, it may rather be: BDD flavor, infix function?). Like I said, we aimed for highest readability, and the declarative flavor with overloaded minus seemed most readable to us :) |
There are declarative and BDD-ish DSLs (in JS for example), so I don't see that first point actively ruling this out :) One would effectively be a simple alias/wrapper of the other, it's not a huge lib overhead. Since the intuitiveness of the In the end, whoever contributes something useful early is likely to gain some adoption, so I don't expect this conversation to really slow you down 😇 it's nice to get the opportunity to provide some feedback, and try to keep the platforms somewhat in sync. My final note is related to spec versions . . . whatever we end up with should tick all the boxes for at least v2 if not v3 or v4. I'm not sure if this is missing any v2 stuff, but I can't see a keyLike/eachKeyLike at the top |
You mean sth like this? obj(
"foo" to string("Foo"),
"bar" to obj(
"baz" to integer(1)
)
) ?
If you mean myself implementing this, I must admit I'd love doing so (I implemented the one for my company), but I'm sorry to say there's no way I'll find the time to do it in the coming months :(
What I've shown are the symbols that we needed. We didn't include some of them because we simply didn't feel we'd need them (like
Yes, here I actually have a question: does it make any sense to use obj(
eachNameLike = "map23_key",
eachValueLike = string("map23_string1")
) to make it more JSON-like (JSON doesn't really have maps - they are just objects). |
I'm adding a Does anyone think we need a provider specific module? |
The |
Hey team, The empty kotlin module created as part of this thread caused an empty readme page on the docs.pact.io page here 👇🏾 https://docs.pact.io/implementation_guides/jvm/consumer/kotlin Do we want to take some of the good stuff started and share, either in that example module readme/project, or in another format? |
Hi, I'd like to propose an API for consumer Kotlin DSL (in case you considered implementing one).
Flavors
There are two flavors, although they differ only slightly:
given
vs.{}
(inproviderStates
)uponReceiving
vs.request
willRespondWith
vs.response
BDD flavor
Declarative flavor
Full list of body symbols
PS. This is an API we implemented in my company (it's a wrapper over Pact DSL). We chose the declarative flavor. Unfortunately, I can't share the implementation without a permission from my employer.
PPS. I could share corresponding Pact DSLs, if you were interested.
The text was updated successfully, but these errors were encountered: