Junos Space SDK > Developer Guides > Junos Space Application Developer Guide > Programming with the Junos Space SDK > Developing Junos Space Applications > Creating REST Services

REST API Versioning

The Junos Space REST API provides a versioning mechanism that allows for updates to the API without breaking code written to previous versions and that, to a lesser extent, enables clients coded to use the new APIs to interoperate with systems using the older APIs. This page describes how versioning is implemented in the Junos Space SDK.

Versioning is implemented in the SDK at the following levels:

  1. API Versioning (includes Expiration)
  2. Data Object Versioning
  3. REST API Versioning
  4. Client Implementation

Versioning is an inherent part of discovery. The discovery mechanism is used to find out the different versioned Media Types, objects, and schemas used by a given web service.

API Versioning

API versioning is primarily achieved through Media Type versioning. In Junos Space, Media Type versioning is implemented by specifying versions along with the Media Type in the Accept Content-Type request header field. Following is the implementation of versioning for a particular API:

@Consumes(application/vnd.net.juniper.space.user-management.users;version=1)
 Public Users getUser(); 
@Consumes(application/vnd.net.juniper.space.user-management.users;version=2)
 Public Users getUser_V2();

Data Object Versioning

To support API versioning, it may be necessary to have particular APIs return different versions of a data object. Versioning in data objects is achieved by keeping their implementations in different package structures. The following example shows an implementation of data object versioning:

@Consumes(application/vnd.net.juniper.space.user-management.users;version=1)
 Public net.juniper.jmp.cmp.systemService.dto.v1.Users getUser(); 
@Consumes(application/vnd.net.juniper.space.user-management.users;version=2)
 Public net.juniper.jmp.cmp.systemService.dto.v2.Users getUser_V2();

REST API Versioning

Schema versioning is a mechanism that allows a user to have different versions of a given schema. It works in tandem with API versioning (Media Type versioning) and data object versioning. You can create different versions of API schema through the EJB-REST wizard, which uses a standard schemagen utility to generate schema for a particular data object. For more details refer to the
Using the EJB-REST Wizard topic.

The following naming convention is used to implement schema versioning:

  1. vnd.net.juniper.space.user-management.user_v1.xsd -> This is version 1 of the user schema.
  2. vnd.net.juniper.space.user-management.user_v2.xsd -> This is version 2 of the user schema.

Client Implementation

This section describes how a client would access different versions of the API(s) or Media Types. The following list provides examples for different scenarios:

1. A client implementation would use the following syntax to access version "1" of a particular API supported by the respective Media Type:

GET    : /users /HTTP/1.1 
Host   : vnd.net.juniper/ 
Accept : application/vnd.net.juniper.space.user-management.users;version=1

2. A client implementation would use the following syntax to access version "2" of a particular API supported by the respective Media Type:

GET    : /users /HTTP/1.1 
Host   : vnd.net.juniper/ 
Accept : application/vnd.net.juniper.space.user-management.users;version=2

3. A client implementation would use the following syntax to access version "2" of a particular API supported by the respective Media Type, if version "1" is not available.

GET    : /users /HTTP/1.1 
Host   : vnd.net.juniper/ 
Accept : application/vnd.net.juniper.space.user-management.users;version=1,application/vnd.net.juniper.space.user-management.users;version=2

4. A client implementation would use the following syntax to request version "1" of a particular API even if version "2" is available.

GET    : /users /HTTP/1.1 
Host   : vnd.net.juniper/ 
Accept : application/vnd.net.juniper.space.user-management.users;version=1,application/vnd.net.juniper.space.user-management.users;version=2

Code Example

In the following code example:

// Class Users
import java.util.Collection;
import javax.xml.bind.annotation.*;
@XmlRootElement(name = "users")
@XmlAccessorType(XmlAccessType.FIELD)
public class Users {
  /**
   * <pre>
   * <b>Class:</b>User
   * <b>Description:</b>This is a User Bean class.
   * </pre>
   *
   * @author 
   * @version 1.0
   */
  public static class User {
    private int id;
    private String name;
    private String primaryEmail;
    private String primaryPhone;
    /**
     * The default constructor
     */
    public User() {
    }
    public int getId() {
      return id;
    }
    public void setId(int id) {
      this.id = id;
    }
    public String getName() {
      return name;
    }
    public void setName(String name) {
      this.name = name;
    }
    public String getPrimaryEmail() {
      return primaryEmail;
    }
    public void setPrimaryEmail(String primaryEmail) {
      this.primaryEmail = primaryEmail;
    }
    public String getPrimaryPhone() {
      return primaryPhone;
    }
    public void setPrimaryPhone(String primaryPhone) {
      this.primaryPhone = primaryPhone;
    }
    private String link;
    /**
     * @return the link
     */
     @XmlAttribute(name = "href")
     public String getLink() {
      return link;
    }
    /**
     * @param link the link to set   
     */
     public void setLink(String link) {
       this.link = link;
     }
     public Users()
     {
     }
     public  User createUser() {
       return new User();
     }
     public Collection<User> getUser() {
       return user;
     }
     public void setUser(Collection<User> user) {
       this.user = user;
     }
     private Collection<User> user;
  }
}

The example below gives JSUserMgmtSvc interface code:

@Path("/")
public interface JSUserMgtSvc {
 @Path("/users")
 @GET	
 @Produces({"application/vnd.net.juniper.space.user-management.users+json;version=1",application/vnd.net.juniper.space.user-management.users+xml;version=1"})
  public Users getAllUsers();
}

Create JSUserMgmtSvcImpl as the Implementation class of the JSUserMgmtSvc interface.

public class JSUserMgmtSvcImpl {
  public Users getAllUsersByJSON ()
  {
    try
    {
      List<Users.User> userList = null;
      Users users = new Users();
      if (userManager != null) 
      {
        final UriContext restContext = ResteasyProviderFactory.getContextData( UriContext.class ); 
        // Support for Pagination/Sorting/Filtering
        PagingContext ctx = null;
        if (restContext != null && restContext.getPagingCtxt() != null)
          ctx = restContext.getPagingCtxt();
        Collection<UserTO> userToObj = userManager.getAllUsers(ctx);
        if(userToObj !=null && !userToObj.isEmpty())
        {
          userList = new ArrayList<Users.User>(userToObj.size());
          for (UserTO userTO : userToObj)
          {
            Users.User user = users.createUser();
            PropertyUtils.copyProperties(user, userTO);
            user.setLink("/user/"+user.getId());
            userList.add(user);
          }
          users.setUser(userList);
        }
        return users;
      } 
      else  
        throw new WebApplicationException();
    }
    catch (Exception e) {
      logger.debug("getAllUsers - Exception occurred while performing the get All User operation. :: " + e.getMessage());
      Response response = invalidResponse(Status.INTERNAL_SERVER_ERROR, UM_BACKEND_ERROR);
      throw new WebApplicationException(response);
    }
  }
}