Over a million developers have joined DZone.

Implementing Versioning Support in Restful Web-Services

· Integration Zone

Build APIs from SQL and NoSQL or Salesforce data sources in seconds. Read the Creating REST APIs white paper, brought to you in partnership with CA Technologies.

Versioning Restful Web-services:

For maintaing backward compatibilty, at times you may need to support multiple versions of restful web-service resources (here after refered to as resources). It may be desirable at that point to be able to have resources versioned at package, class or individual method level. Annotations come handy in fulfillinhg this need. Here is summary of the steps to add versioning support:

  • Create a custom Annotation:

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.TYPE, ElementType.PACKAGE, ElementType.METHOD})

public @interface Versioned{

    String[] versions();

}

  • Annotate Resources:
@Versioned(versions = {"1.0","2.0"})
@Path("user")
@Produces({"application/xml","application/json"})
public class UserResource{…}
  • Finally create an interceptor that intercepts requests, checks if supported version is passed in Accept header (e.g. Accept: application/xml;ver=1.0) and returns response code 415 for unsupported versions (example uses JBoss jax-rs implementation):

@Provider

@ServerInterceptor

public class VersionCheckInterceptor implements PreProcessInterceptor{

    private static final Pattern pattern = Pattern.compile("ver\\s*=\\s*([\\d]+.[\\d]+)");

    public static final String ALLOW_ALL = "ALLOW_ALL";

 

    @Override

    public ServerResponse preProcess(HttpRequest httpRequest, ResourceMethod resourceMethod) throws Failure, WebApplicationException{

        Versioned methodAnnotation = resourceMethod.getMethod().getAnnotation(Versioned.class);

        if(methodAnnotation != null && methodAnnotation.versions() != null && ArrayUtils.contains(methodAnnotation.versions(), ALLOW_ALL))return null;

        Versioned classAnnotation = resourceMethod.getResourceClass().getAnnotation(Versioned.class);

        Versioned packageAnnotation = resourceMethod.getResourceClass().getPackage().getAnnotation(Versioned.class);

        Versioned annotation = methodAnnotation != null?methodAnnotation:(classAnnotation != null?classAnnotation:packageAnnotation);

        if(annotation == null) return null;

        List<String> acceptHeaders = httpRequest.getHttpHeaders().getRequestHeader("Accept");

        boolean reqContainsSupportedVersion = false;

        for(String version : acceptHeaders){

            Matcher matcher = pattern.matcher(version);

            if(!matcher.find()) continue;

            String versNum = matcher.group(1);

            if(versNum == null) continue;

            versionPasssed = true;

            if(ArrayUtils.contains(supportedVersions, versNum)){

                reqContainsSupportedVersion = true;

            }

            break;

        }

        if(!reqContainsSupportedVersion) throw new NotFoundException ();

        return null;

    }

}

The Integration Zone is brought to you in partnership with CA Technologies.  Use CA Live API Creator to quickly create complete application backends, with secure APIs and robust application logic, in an easy to use interface.

Topics:

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}