Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Documenting byte[] response in Spring Rest Docs

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?

like image 871
Tatha Avatar asked Aug 30 '16 16:08

Tatha


1 Answers

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.

like image 140
Andy Wilkinson Avatar answered Oct 28 '22 09:10

Andy Wilkinson