Documenting byte[] response in Spring Rest Docs
Asked Answered
H

1

5

I am building an API and documenting it using Spring Rest Docs (1.1.1.RELEASE) and there is an api which returns an image as byte array.

I need to describe the response type in REST docs. I am not sure how this can be done using FieldDescriptor

When I try:

//get mock byte array
byte[] attachment = "Hello".getBytes();

FieldDescriptor[] contentFields = new FieldDescriptor[] {
            fieldWithPath("").type(byte[].class)
                    .description("bytes of the attachment ")};

    when(serviceMock.getImage("fe329638007b4ea3b2a5")).thenReturn(attachment);

    this.mockMvc
            .perform(RestDocumentationRequestBuilders.get("/api/v1/contents/{contentId}/images", "fe329638007b4ea3b2a5"))
            .andExpect(status().isOk()).andDo(document("{method-name}",
                    pathParameters(parameterWithName("contentId").description("The id of the Content")),
                    responseFields(contentFields)));

    verify(serviceMock, times(1)).getImage("fe329638007b4ea3b2a5");
    verifyNoMoreInteractions(serviceMock);

I get the below error

org.springframework.restdocs.payload.PayloadHandlingException: com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'Hello': was expecting ('true', 'false' or 'null')
 at [Source: [B@13866865; line: 1, column: 11]
at org.springframework.restdocs.payload.JsonContentHandler.readContent(JsonContentHandler.java:86)
at org.springframework.restdocs.payload.JsonContentHandler.findMissingFields(JsonContentHandler.java:52)
at org.springframework.restdocs.payload.AbstractFieldsSnippet.validateFieldDocumentation(AbstractFieldsSnippet.java:152)
at org.springframework.restdocs.payload.AbstractFieldsSnippet.createModel(AbstractFieldsSnippet.java:100)
at org.springframework.restdocs.snippet.TemplatedSnippet.document(TemplatedSnippet.java:64)
at org.springframework.restdocs.generate.RestDocumentationGenerator.handle(RestDocumentationGenerator.java:196)
at org.springframework.restdocs.mockmvc.RestDocumentationResultHandler.handle(RestDocumentationResultHandler.java:55)
at org.springframework.test.web.servlet.MockMvc$1.andDo(MockMvc.java:177)
at com.davita.comms.controller.CommsControllerTest.getThumbnailByContentId(CommsControllerTest.java:205)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.restdocs.JUnitRestDocumentation$1.evaluate(JUnitRestDocumentation.java:55)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:670)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Is there a way to mention in FieldDescriptor that the returned data is no json, so makes no sense to have a path.

Is there any other way we can document this without FieldDescriptors?

Haddad answered 30/8, 2016 at 16:10 Comment(0)
C
8

REST Docs doesn't have any support for documenting the contents of binary payloads. The request and response fields snippets are intended for documenting the structure of a JSON or XML payload.

I don't think you get much benefit from using REST Docs to generate the table to describe your binary response as there's not much to assert. Any response can be treated as a byte[] as that's what a response is in its most raw form. For example, JSON is a byte[] as is XML. They're just byte arrays with particular constraints on their contents.

Rather than trying to use REST Docs to generate a table to describe the binary response, I'd simply hardcode it in your .adoc file. If you want to include some assertions in your test about the contents of the response, then I'd use some of MockMvc's matchers. For example, you could assert that the body of the response matches the bytes that you've configured your mock service to return.

Clemente answered 30/8, 2016 at 19:14 Comment(3)
Thanks Andy!! That is what I am doing now. I will add the response type in the .adocHaddad
I prefer adding a responseBody() snippet method instead of writing in to the adoc. Response can be a string that express token, can be image, text etc..Garnish
Hard-coding responses (or request body) in adoc does add need to make it look same as generated snippets table of describing body. For example I would like to document POST request body with content type text/uri-list when associating two resources. Just make able to note multiplicity of urls in post body would be helpful. I like to have consistent looking documentation.Shackelford

© 2022 - 2024 — McMap. All rights reserved.