繁体   English   中英

文档分层 JSON 有效负载 Spring REST 文档

[英]document hierarchical JSON payload with Spring REST Docs

我开始使用Spring REST Docs来记录一个简单的 REST API。我有一个具有某种层次结构的有效载荷,例如像这样(有员工的公司)。

{
    "companyName": "FooBar",
    "employee": 
    [
        {
            "name": "Lorem",
            "age": "42"
        },

        {
            "name": "Ipsum",
            "age": "24"
        }
    ]
}

我想将公司 object(员工姓名和数组)和员工 object(员工姓名和年龄)的文件分开。

这里解释的那样使用org.springframework.restdocs.payload.PayloadDocumentation.responseFields迫使我记录所有字段,但如果我只想记录员工字段 - 我该如何实现呢?

我可以在没有员工详细信息的情况下记录公司,因为如果一个字段是文档,则后代也被视为已记录。 但是我无法单独记录员工结构,并且在没有公司根 object 的情况下,我没有专门用于此结构的有效载荷。

受这个问题的启发,我实施了一项增强功能,使原来的答案(见下文)过时了。

如果使用1.0.0.BUILD-SNAPSHOT(可从https://repo.spring.io/libs-snapshot获得 ),则现在可以将字段标记为已忽略。 已记录忽略的字段数,但实际上没有出现在文档中。

鉴于您想要分离文档,有两个文档调用是有道理的。 首先,您可以记录公司名称和员工阵列。 在第二个中,您记录了employees数组并将公司名称标记为已忽略。

您的测试看起来像这样:

mockMvc.perform(get("/company/5").accept(MediaType.APPLICATION_JSON))
        .andExpect(status().isOk())
        .andDo(document("company",
                responseFields(
                        fieldWithPath("companyName").description(
                                "The name of the company"),
                        fieldWithPath("employee").description(
                                "An array of the company's employees"))))
        .andDo(document("employee",
                responseFields(
                        fieldWithPath("companyName").ignored(),
                        fieldWithPath("employee[].name").description(
                                "The name of the employee"),
                        fieldWithPath("employee[].age").description(
                                "The age of the employee"))));

您将最终得到两个片段目录,一个名为company ,另一个名为employee 然后,您可以使用每个的response-fields.adoc片段。

原始答案

当您记录请求或响应时,没有明确支持忽略字段,但我认为您可以通过使用预处理器删除您不想记录的字段来实现所需。

鉴于您想要分离文档,有两个document调用是有道理的。 首先,您可以记录公司名称和员工阵列。 在第二步中,您需要预处理请求以删除公司,然后记录employees数组。

您的测试看起来像这样:

mockMvc.perform(get("/company/5").accept(MediaType.APPLICATION_JSON))
        .andExpect(status().isOk())
        .andDo(document("company",
                responseFields(
                        fieldWithPath("companyName").description(
                                "The name of the company"),
                        fieldWithPath("employee").description(
                                "An array of the company's employees"))))
        .andDo(document("employee",
                preprocessResponse(removeCompany()),
                responseFields(
                        fieldWithPath("employee[].name").description(
                                "The name of the employee"),
                        fieldWithPath("employee[].age").description(
                                "The age of the employee"))));

请注意在第二个document调用中使用preprocessResponse removeCompany返回一个预处理器,它使用自定义ContentModifier从响应中删除公司名称:

private OperationPreprocessor removeCompany() {
    return new ContentModifyingOperationPreprocessor(new ContentModifier() {

        @Override
        public byte[] modifyContent(byte[] originalContent, MediaType contentType) {
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                Map<?, ?> map = objectMapper.readValue(originalContent, Map.class);
                map.remove("companyName");
                return objectMapper.writeValueAsBytes(map);
            }
            catch (IOException ex) {
                return originalContent;
            }
        }

    });
}

您将最终得到两个片段目录,一个名为company ,另一个名为employee 然后,您可以使用每个的response-fields.adoc片段。

虽然上述方法有效,但它比它需要的更难。 我已经打开了一个问题,因此不再需要修改响应内容的预处理。

这个答案是为那些现在带着同样的问题来到这里的人准备的。 使用 Spring Rest 文档的2.0.x版本,您可以执行以下操作:

  1. 使用PayloadDocumentation.relaxedResponseFields方法记录第一级(任何未记录的字段将被忽略):
  2. 使用PayloadDocumentation.beneathPath记录第二层,它将提取在给定路径下找到的 JSON 有效负载的子部分
  3. 这将生成一个response-fields.snippet文件和一个response-fields-beneath-employee.snippet文件
.consumeWith(document("company",
  PayloadDocumentation.relaxedResponseFields(
    PayloadDocumentation.fieldWithPath("companyName").description("The name of the company"),
    PayloadDocumentation.fieldWithPath("employee").description("An array of the company's employees")
      ),
  //Using PayloadDocumentation.beneathPath(..) to document separately employee parts
  PayloadDocumentation.responseFields(
    PayloadDocumentation.beneathPath("employee"),
    PayloadDocumentation.fieldWithPath("employee.name").description("The name of the employee"),
    PayloadDocumentation.fieldWithPath("employee.age").description("The age of the employee")
  )
)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM