javaspring-bootspring-testspring-restdocs

How can I fix a RestDocumentationGenerationException: java.io.FileNotFoundException: /curl-request.adoc (Read-only file system) in my Spring Boot app?


Would you believe googling this returned a whopping two results!

I'm trying to use Spring REST Docs (spring-restdocs-mockmvc) to generate API documentation for my service.

Running on a macbook pro with M2 processor. I've read that this issue happens because / is the root directory on a mac, and that is read only. I don't know why that path is being used though.
I have the system property org.springframework.restdocs.outputDir set, and when I check it the path is correct: /Users/me/workspace/my-service/target/generated-snippets.

My code looks like this:

@SpringBootTest()
@ExtendWith(RestDocumentationExtension.class)
class ExampleControllerTest {

    @Autowired
    private WebApplicationContext context;

    private MockMvc mvc;

    @BeforeEach
    public void setUp(RestDocumentationContextProvider restDocumentation) {
        System.out.println("Output Directory: " + System.getProperty("org.springframework.restdocs.outputDir"));
        this.mvc = MockMvcBuilders.webAppContextSetup(this.context)
                                      .apply(MockMvcRestDocumentation.documentationConfiguration(restDocumentation))
                                      .build();
    }

    @Test
    public void index() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON))
           .andExpect(status().isOk()).andExpect(content().string(containsString("\"name\":\"Example Service\"")))
           .andDo(MockMvcRestDocumentation.document("/",
                                                    responseFields(
                                                            fieldWithPath("name").description("The name of the service"),
                                                            fieldWithPath("list").description("A list of Integers"),
                                                            fieldWithPath("calledTimes").description(
                                                                    "A count of the number of times this resource has been called"),
                                                            fieldWithPath("deployEnvironment").description(
                                                                    "The environment the service is deployed to")
                                                    )
                  )
           );
    }
}

I'm at a total loss as to what to do here.

When I pause the code with the debugger I can see that the RestDocumentationContextProvider passed into the setup method has a value called outputDirectory that is null. So it seems to me that it's not picking up the system property for some reason.
If I look in valuesStore.storedValues there is one key/value pair with the key class org.springframework.restdocs.ManualRestDocumentation and a value that contains (among other things) outputDirectory set to target/generated-snippets.


Solution

  • The problem's caused by your use of / when calling MockMvcRestDocumentation.document("/"). The javadoc describes it as "an identifier for the API call that is being documented". The reference documentation describes how this identifier is used when creating the names of the snippet files that are generated.

    When the identifier starts with / it is already absolute so the configured output directory is ignored. I would recommend using something like index or root as the identifier instead. This will result in a directory named index or root being created in the configured output directory. This directory will contain all of the snippets for the API operation that you're documenting.