Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
    Andy Wilkinson
    @wilkinsona
    Yes, that should work
    Eric Deandrea
    @edeandrea
    Thanks!
    Eric Deandrea
    @edeandrea
    A more generalized question - keeping human-readable documentation up to date with something like this (and especially the test-driven approach) seems like a huge win. Do you have any recommendations/advice/opinions on how do we keep our OpenAPI contracts in sync with the documentation? Questions like “what is the real source of truth” continually come up
    the human readable documentation is important, but so is the actual api contract (OpenAPI spec)
    everyone wants to do contract-first development, which is great when you are starting from scratch, but over time as a system evolves we now have the challenge of keeping the contract in sync with the code and keeping that in sync with the documentation
    Eric Deandrea
    @edeandrea
    Is restdocs meant to eliminate the contract entirely? Used in combination with Spring Cloud Contract would it eliminate it?
    Tools like Mulesoft/AWS Api Gateway can proxy an api simply by importing its OpenAPI contract
    Just wanted to get your thoughts on the matter
    Andy Wilkinson
    @wilkinsona
    I'm not a great person to ask about that as I'm not a fan of OpenAPI
    I know there are some tools for testing things to see if they're in sync. https://github.com/RobWin/assertj-swagger is one that comes to mind.
    Eric Deandrea
    @edeandrea
    yeah we actually use that. I’m trying to figure out the best way to tie the human-readable docs back to the actual API contract
    and which should be the “true” source of record
    Mathias Düsterhöft
    @mduesterhoeft
    Also there is this tool to test if a spec is in sync with the implementation - https://bitbucket.org/atlassian/swagger-request-validator
    If you like the test-driven approach of spring-restdocs, and still would like to have an OpenAPI spec you could also look at https://github.com/ePages-de/restdocs-api-spec
    Mathias Düsterhöft
    @mduesterhoeft
    @edeandrea I really like the test-driven approach of spring-restdocs - and I think it is superior over the usual introspection-driven approach that swagger takes. Using the tests to actually derive knowledge about your API is a very good idea. But the design first approach can also be a good fit. It is a good choice if you put an emphasis on your REST API and you want to make it public. Also if you want your development workflow to start with modelling the API. Here you design your API first and use specs like OpenAPI or RAML for this. Then you also need some guarantees to make sure your code is actually implementing this spec.
    Eric Deandrea
    @edeandrea
    Thanks @mduesterhoeft I totally agree. What I’m trying to figure out is what is the best way to only have to write it once :) I’d hate to write it as an OpenAPI/RAML spec and then have to do it again in my RestDocs spec, and then try and keep them in sync. Trying to pick people’s brains about what they are doing in the space so that we truly only have to write things once.
    Mathias Düsterhöft
    @mduesterhoeft
    @edeandrea no of course you would not write your specification twice. What I wanted to say is that there are different approaches:
    • design first - write your API spec up front - maybe using tools such as stoplight.io - that you implement the API. To make sure the implementation follows your specification you can use tools such as swagger-request-validator
    • test-driven - you describe and introspect your API in your test using spring-restdocs - you can use the extension restdocs-api-spec to also generate an openAPI specification for your API - so you rather generate the specification from the knowledge you put into your testt
    Jakub Kubryński
    @jkubrynski
    Hi! Is there any particular reason that HalLinkExtractor does not support links on embedded resources?
    Andy Wilkinson
    @wilkinsona
    IIRC, my reasoning was that the links should be documented for the resource in its main usage so having to document them again in an embedded usage would be unnecessary
    Jakub Kubryński
    @jkubrynski
    But if you document fields of embedded documents it'd be probably also good to not skip the links?
    Andy Wilkinson
    @wilkinsona
    I wouldn't document the fields either. You'll end up with lots of repetition.
    Jakub Kubryński
    @jkubrynski
    OK. I'll review if just linking to other parts of the documentation will be nice
    Jakub Kubryński
    @jkubrynski
    Is it possible to set the default value for the attribute? I want to use custom attribute that will be available only on few fields
    Andy Wilkinson
    @wilkinsona
    @jkubrynski There are a few options discussed in spring-projects/spring-restdocs#291
    Knut Schleßelmann
    @kschlesselmann
    Did anyone here ever setup RestDocs using kotlin and WebTestClient using JUnit5? I cannot get a running setup here :-(
    Andy Wilkinson
    @wilkinsona
    What's the problem?
    Knut Schleßelmann
    @kschlesselmann
    @wilkinsona org.junit.jupiter.api.extension.ParameterResolutionException: Failed to resolve parameter [org.springframework.web.context.WebApplicationContext webApplicationContext] using
    @ExtendWith(RestDocumentationExtension::class, SpringExtension::class)
    internal class DocTest {
    
        private var webTestClient: WebTestClient = WebTestClient.bindToServer().build()
    
        @BeforeEach
        fun setUp(webApplicationContext: WebApplicationContext , restDocumentation: RestDocumentationContextProvider) {
            this.webTestClient = WebTestClient.bindToApplicationContext(webApplicationContext)
                    .configureClient()
                    .filter(documentationConfiguration(restDocumentation))
                    .build()
        }
    
        @Test
        fun stuff() {
            this.webTestClient.get().uri("/").accept(MediaType.APPLICATION_JSON)
                    .exchange().expectStatus().isOk
                    .expectBody().consumeWith(document("index"))
        }
    }
    Would be even better to have some constructor injection setup so that webTestClient could be val
    ```
    @SpringBootTest
    @ActiveProfiles("test")
    @ExtendWith(RestDocumentationExtension::class, SpringExtension::class)
    internal class DocTest {
    doesn't help either
    Or even better: Have @AutoconfigureRestDocs working in webflux
    Andy Wilkinson
    @wilkinsona
    The injection of the WebApplicationContext doesn't have anything to do with REST Docs as it's not involved with that
    I assume that Spring Framework's JUnit 5 integration allows the application context to be injected like that, but I don't know for sure. You'll need some configuration that creates such an application context and I can't see any sign of that in your first example.
    Knut Schleßelmann
    @kschlesselmann
    @wilkinsona Shouldn't the seconad example have a context through @SpringBootTest?
    Knut Schleßelmann
    @kschlesselmann
    @wilkinsona I changed my definition to applicationContext: ApplicationContext and it works :-S
    Knut Schleßelmann
    @kschlesselmann
    Anyone an idea why my base url is still localhost:8080 if I use the following to bootstrap my RestDocs tests
    @SpringBootTest
    @ActiveProfiles("test")
    @ExtendWith(RestDocumentationExtension::class, SpringExtension::class)
    internal abstract class AbstractRestDocsTest {
    
        protected var webTestClient: WebTestClient = WebTestClient.bindToServer().build()
    
        @BeforeEach
        fun setUp(applicationContext: ApplicationContext, restDocumentation: RestDocumentationContextProvider) {
            webTestClient = WebTestClient.bindToApplicationContext(applicationContext)
                    .configureClient()
                    .baseUrl("https://${applicationContext.applicationName}.example.com")
                    .filter(documentationConfiguration(restDocumentation)
                            .operationPreprocessors()
                            .withRequestDefaults(prettyPrint())
                            .withResponseDefaults(prettyPrint()))
                    .build()
        }
    }
    Andy Wilkinson
    @wilkinsona
    Why are you creating it twice, once bound to a server and once bound to the application context?
    Knut Schleßelmann
    @kschlesselmann
    @wilkinsona So I can use var without null. Some kind of constructor injection would be nice … or @AutoConfigureRestDocs for WebTestClient :-)
    But does it matter since I override the instance later on?
    Andy Wilkinson
    @wilkinsona
    @AutoConfigureRestDocs already works with WebTestClient
    The duplicate configuration of WebTestClient matters in this context as it makes it harder to figure out what you're doing and why.
    Andy Wilkinson
    @wilkinsona
    Looks like we missed a doc update as part of https://github.com/spring-projects/spring-boot/pull/10969/. It's been supported since 2.0
    Knut Schleßelmann
    @kschlesselmann
    Good to know … never tried since it was missing in the docs :-)
    @wilkinsona So how would for example pretty print work with WebTestClient If I use @AutoConfigureRestDocs?
    Andy Wilkinson
    @wilkinsona
    You'd set it up with a RestDocsWebTestClientConfigurationCustomizer
    Knut Schleßelmann
    @kschlesselmann
    OK, let me try :-) @wilkinsona awesome work btw :thumbsup:
    Knut Schleßelmann
    @kschlesselmann

    @wilkinsona Works like a charm :-) The base url is still a problem though. I tried

    @TestConfiguration
    internal class RestDocsConfiguration : RestDocsWebTestClientConfigurationCustomizer {
    
        override fun customize(configurer: WebTestClientRestDocumentationConfigurer) {
            configurer.operationPreprocessors()
                    .withRequestDefaults(prettyPrint())
                    .withResponseDefaults(prettyPrint())
        }
    
        @Bean
        fun webTestClientBuilderCustomizer() = WebTestClientBuilderCustomizer {
            it
                    .baseUrl("https://fooo.bar")
        }
    }

    Pretty print is applied as expected … my snippets still refer to localhost:8080. Would those cusomizers be picked up by

    @SpringBootTest
    @ActiveProfiles("test")
    @AutoConfigureRestDocs
    @AutoConfigureWebTestClient
    @Import(RestDocsConfiguration::class)
    @ExtendWith(RestDocumentationExtension::class, SpringExtension::class)
    internal abstract class AbstractRestDocsTest {
    
        @Autowired
        protected lateinit var webTestClient: WebTestClient
    }

    at all?

    Andy Wilkinson
    @wilkinsona
    A WebTestClientBuilderCustomizer not being picked up sounds very similar to spring-projects/spring-boot#15132