【问题标题】:Versioning REST APIs and vendor specific content type版本控制 REST API 和供应商特定的内容类型
【发布时间】:2012-10-13 15:56:10
【问题描述】:

我阅读了很多关于版本控制 REST API 的文章,例如在这个线程中:Best practices for API versioning?

因此,我想使用 HTTP-Accept-Header 来指示客户端要求的版本。 但是我怎样才能在我的应用程序中应用它呢?因此做出了哪些改变?编组器如何知道应该使用哪个版本?我必须注册我的类型吗?

我所知道的是我必须更改@Produces-Annotation 的内容

@GET
@Path("/locations")
@Produces("application/vnd.mycompany-v1+xml")
Location[] getLocations();

但是还有什么需要改变的呢?

【问题讨论】:

    标签: java rest http-headers versioning jax-rs


    【解决方案1】:

    您可以使用 JAX-RS 的Variant 机制。

    @GET
    @Path("/locations/{id}")
    @Produces(value = {"application/vnd.mycompany-v2+json", // current version
                       "application/vnd.mycompany-v1+json", // old version
                       MediaType.APPLICATION_JSON})         // fallback
    public Response getLocation(@PathParam("id") Integer id,
                                @Context Request request) {
        MediaType vndTypeV1 = new MediaType("application", "vnd.mycompany-v1+json");
        MediaType vndTypeV2 = new MediaType("application", "vnd.mycompany-v2+json");
        Variant variant1 = new Variant(vndTypeV1, null, null);
        Variant variant2 = new Variant(vndTypeV2, null, null);
        Variant variantJson = new Variant(MediaType.APPLICATION_JSON_TYPE, null, null);
        List<Variant> variants = new ArrayList<Variant>();
        variants.add(variant1);
        variants.add(variant2);
        variants.add(variantJson);
    
        Variant selectedVariant = request.selectVariant(variants);
    
        Location location = someBackendService.getLocation(id);
    
        // Manipulate location according to which variant is the selectedVariant.
        // ...
    
        return Response.ok("{}")
            .header(HttpHeaders.CONTENT_TYPE, selectedVariant.getMediaType())
            .build();
    }
    

    也可以查看Java EE 6 Tutorial

    编辑

    没有根据所选变体自动编组实体的方法。这需要一些手工工作。例如:

    String version = extractVersionFromVariant(selectedVariant);
    if ("v1".equals(version)) {
        location.setSomeV1Propery("only in v1);
    } else if ("v2".equals(version)) {
        location.setSomeV2Propery("only in v2);
    }
    return Response.ok(location)
                   .header(HttpHeaders.CONTENT_TYPE, selectVariant.getMediaType())
                   .build();
    

    如果版本足够不同,我会为每个版本使用 JAXB 注释类。然后每个这样的类将只包含对这个版本有效的那些属性。 JAX-RS 负责将它们编组为 JSON。

    【讨论】:

    • 感谢您的回答。但是我如何处理这些东西:@POST @Path("/locations") @Consumes({"application/vnd.mycompany-v2+json","application/vnd.mycompany-v1+json"}) void createLocation(Location location); 编组器如何使用正确的对象版本,例如我得到了 v1 的位置对象和 v2 的另一个位置对象?
    • 再次感谢您。您答案的最后两句话听起来很有趣,实际上是我想要达到的目的。如果我有以下 REST 服务并且客户端要求 v2:@GET @Path("/locations") @Produces({"application/vnd.mycompany-v1+xml", "application/vnd.mycompany-v2+xml"}) Location[] getLocations(); 此外,我在不同的包中获得了两个 Objekts,例如 entities.v1.Locationentities.v2.Location。我如何告诉带有 JAXB 注释的编组器使用 Objekt entities.v2.Location 因为客户要求这样做??
    • 只需在if 中创建一个正确的Location 类的实例,然后在ok() 中返回它。如果 Location 类具有正确的 JAXB 注释,则 JAX-RS 应将其编组为 JSON。
    【解决方案2】:

    据我所知,您不能使用 JAX-RS 根据 http 标头自动路由到不同的方法。

    您可以在您的方法中读取标题(在@context 上使用@HeaderParam 或HttpHeaders 参见here)并调用适当的版本

    【讨论】:

    • 感谢您的回答。实际上我不想使用该版本将请求路由到不同的方法。我只想使用该版本来生成指定版本中的位置对象。也许 v2 的 Location 比 v1 多了一个属性……就是这样
    • 那你可以根据我上面说的来确定你需要返回哪个版本
    猜你喜欢
    • 2013-09-28
    • 1970-01-01
    • 2012-10-20
    • 2016-03-12
    • 2014-08-29
    • 2012-05-31
    • 2016-01-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多