Relativity Services API (RSAPI) DTOs have been deprecated and are no longer supported. For more information and alternative APIs, see RSAPI deprecation process.

Build your first Services API client

This tutorial helps you to create a simple program that uses the Services API to perform CRUD and query operations. It illustrates how to extend the functionality provide by a sample application developed using the Application Deployment System.

The tutorial uses a Custodian object to demonstrate how to create Relativity Dynamic Objects (RDOs) using a typed class in the kCura.Relativity.Client.DTOs namespace. The Custodian class represents a person and its Fields store data such as a phone number and first and last name.

This page contains the following information:

Before you begin

To run this sample program, complete the following tasks to set up your development environment:

  • Confirm that you have the required software. See Set up your development environment.
  • Create a workspace in your target Relativity instance. You don't need to add documents to the workspace.
  • Confirm that you have these permissions:
    • Relativity system admin rights to log in to Relativity through Services API
    • Relativity system admin rights to install an application
  • Download RSAPIGettingStartedTutorial.zip file. This file contains the application and source code for this sample program.
  • Unzip the Services API Tutorial Application, and install the RA_Tutorial_20130711213312.xml file to your workspace. For more information, see Installing applications on the Relativity Server2021 Documentation site.
  • Create a C# console application in Visual Studio. See Set up a project in Visual Studio.

Note: The code for this program references several constants that represent GUID and string values. The TutorialConstants class provides a complete list of these constants. To view this class, open the Program.cs file included in the RSAPIGettingStartedTutorial.zip file.

Add directives for required namespaces

Add using directives to your applications. The directive reference the namespaces that contain the classes used to create a proxy and work with DTOs. If these Services API namespaces aren't available in your application, see Get started with the Services API.

using System;
using System.Collections.Generic;
using System.Linq;
using kCura.Relativity.Client;
using DTOs = kCura.Relativity.Client.DTOs;
        

Add the Main method

The sample program has a Main() method that includes code for calls to subsequent methods for creating the proxy, querying for workspaces, creating an RDO, and performing other tasks.

public static void Main(string[] args)
{
     // Create a client which uses Windows Authentication
     // to log in to the Relativity Services on the local machine.
     // Set up the current Windows user as a Relativity System
     // Administrator for the purposes of this tutorial.
      
     using (IRSAPIClient client = CreateClient())
     {
          // Query for a workspace and access it.
          // Change the following string to the name of a workspace in your copy of Relativity.
          FindAndEnterWorkspace(client, TutorialConstants.TARGET_WORKSPACE_NAME);
           
          // Create a Custodian RDO in the context of the workspace.
          Int32 rdoID = CreateRdo(client);
           
          // Create an Address Field on the Custodian.
          Int32 fieldID = CreateField(client);
           
          // Update the RDO with new data.
          UpdateRdo(client, rdoID, fieldID);
           
          // Read the updated RDO.
          ReadRdo(client, rdoID);
           
          // Query for the ArtifactIDs of all Custodians.
          QueryRdo(client);
           
          // Delete the newly added Field from the Custodian RDO.
          DeleteField(client, fieldID);
           
          // Delete the newly created RDO.
          DeleteRdo(client, rdoID);
          // Log out is handled by the RSAPIClient object.
     } // Exiting the using block calls the Dispose() method on the RSAPIClient, which ensures the client is cleaned up.
      
     PauseBeforeExit();
}
        

Create the RSAPIClient proxy

You must be authenticated before you can manipulate objects in Relativity through the Services API. You need to create an instance of the RSAPIClient class to hold the session data. The overloaded constructor for the class provides you with the ability to choose the combination of endpoint type, authentication method, and optional configuration settings appropriate for your application development goals. The proxy automatically logs in to Relativity using the specified AuthenticationType so you don't need to call a login method.

Note: This is a standalone console application example, and you cannot use Relativity API helper classes to create the proxy, which is the recommended way for agents, event handlers, and custom pages. For more information Connect to the Services API and Best practices for the Services API.

This code sample illustrates how to instantiate the proxy with a constructor that uses integrated Windows authentication.

public static IRSAPIClient CreateClient()
{
     // Create a new instance of RSAPIClient. The first parameter indicates the endpoint Uri, 
     // which indicates the scheme to use. The second parameter indicates the
     // authentication type. The RSAPIClient members page in the Services API class library
     // documents other possible constructors. The constructor also ensures a logged in session.
      
     string localHostFQDN = System.Net.Dns.GetHostEntry("localhost").HostName;
     Uri endpointUri = new Uri(string.Format("http://{0}/relativity.services", localHostFQDN));
     IRSAPIClient rsapiClient = new RSAPIClient(endpointUri, new IntegratedAuthCredentials());
      
     Console.WriteLine("\tClient created and logged in.");
      
     return rsapiClient;
}
        

Query for a workspace

Each instance of the RSAPIClient class has an APIOptions property. Before you can use a workspace, you must set the WorkspaceID property on APIOptions to its ArtifactID. You can perform a query on the name of the workspace to return its ArtifactID.

The following code sample illustrates how to use the Query DTO with a TextCondition to search for a workspace by name and then sets its ArtifactID on the APIOptions. This code uses a Like text condition, but you could also an EqualTo condition. Both are available in the TextConditionEnum enumeration. Since workspace names aren't required to be unique, the code sample calls the Any() method on the Results object.

This workspace provides the context for other operations.

private static void FindAndEnterWorkspace(IRSAPIClient client, string workspaceName)
{
     Console.WriteLine("\n\tFinding and entering Workspace...");
      
     // Use the TextCondition to match workspaces with names similar to the specified string.
     var workspaceCondition = new TextCondition(DTOs.ArtifactFieldNames.TextIdentifier,
     TextConditionEnum.Like, workspaceName);
      
     // Build a query with the workspaceCondition.
     var query = new DTOs.Query<DTOs.Workspace> { Condition = workspaceCondition };
     query.Fields = DTOs.FieldValue.NoFields;
      
     // Send the query and receive results.
     DTOs.QueryResultSet<DTOs.Workspace> results = client.Repositories.Workspace.Query(query);
      
     if (!results.Success)
     {
          WriteFailedResultAndExit(results, client);
     }
      
     if (!results.Results.Any())
     {
          // No Workspace with the specified name exists.
          WriteErrorAndExit("No Workspace matching condition found.", client);
     }
      
     // To begin using this workspace, set the WorkspaceID of your instance of APIOptions to the
     //  ArtifactID of the Workspace.
     client.APIOptions.WorkspaceID = results.Results.First().Artifact.ArtifactID;
}
        

Create a Relativity Dynamic Object DTO

To develop a custom application, you can create RDOs and other objects using the typed classes in the kCura.Relativity.Client.DTOs namespace. The classes in this namespace are called DTOs. See Basic Services API concepts.

This sample code shows you how to create Custodian RDO by completing the following steps that are also common to other DTOs:

  • Set all required properties for a new DTO.
  • Call the Create() method.
  • Confirm that the object was created successfully.
  • Save or return the ArtifactID for future use.
private static Int32 CreateRdo(IRSAPIClient client)
{
     Console.WriteLine("\n\tCreating RDO... ");
      
     var rdo = new DTOs.RDO();
     rdo.TextIdentifier = DateTime.Now.Ticks.ToString();
     rdo.Fields.Add(new DTOs.FieldValue(TutorialConstants.FIRST_NAME_FIELD_GUID,
     TutorialConstants.CUSTODIAN_FIRST_NAME_VALUE));
     rdo.Fields.Add(new DTOs.FieldValue(TutorialConstants.LAST_NAME_FIELD_GUID,
     TutorialConstants.CUSTODIAN_LAST_NAME_VALUE));
     rdo.Fields.Add(new DTOs.FieldValue(TutorialConstants.PHONE_NUMBER_FIELD_GUID,
     TutorialConstants.CUSTODIAN_PHONE_NUMBER_VALUE));
      
     // Set the ArtifactTypeName, ArtifactTypeID, or ArtifactTypeGuids for any new RDO.
     rdo.ArtifactTypeGuids = new List<Guid>() { TutorialConstants.CUSTODIAN_TABLE_GUID };
      
     DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Create(rdo);
      
     // Check for success of Create() method.
     if (!results.Success)
     {
          WriteFailedResultAndExit(results, client);
     }
     if (!results.Results.Any())
     {
          WriteErrorAndExit("FAILURE: RDO creation succeeded but returned no Artifacts.", client);
     }
      
     // Get the ArtifactID of the new Custodian.
     Int32 rdoID = results.Results.Single().Artifact.ArtifactID;
     Console.WriteLine("\tArtifactID of new RDO: {0}", rdoID);
      
     return rdoID;
}
        

Create a Field on an RDO

You can create Fields on DTOs to store metadata and other information about them. Add a Field to the Custodian RDO. The name of the Field includes the word "Address" followed by the count of CPU ticks since 12:00:00 midnight on Jan 1, 2001. This ensures that Field name is unique, such as Address 635133920940413625. For more information, see Field.

private static Int32 CreateField(IRSAPIClient client)
{
     Console.WriteLine("\n\tCreating Field... ");
      
     DTOs.Field field = new DTOs.Field();
     field.ObjectType = new DTOs.ObjectType(TutorialConstants.CUSTODIAN_TABLE_GUID);
     field.Name = string.Format("Address {0}", DateTime.Now.Ticks);
     field.FieldTypeID = FieldType.FixedLengthText;
     field.Length = 255;
     field.IsRequired = false;
     field.IncludeInTextIndex = false;
     field.Unicode = true;
     field.AllowHTML = false;
     field.OpenToAssociations = false;
     field.Linked = false;
     field.AllowSortTally = true;
     field.Wrapping = true;
     field.AllowGroupBy = false;
     field.AllowPivot = false;
     field.IgnoreWarnings = true;
     field.Width = "10";
      
     DTOs.WriteResultSet<DTOs.Field> results = client.Repositories.Field.Create(field);
     if (!results.Success)
     {
          WriteFailedResultAndExit(results, client);
     }
     if (!results.Results.Any())
     {
          WriteErrorAndExit("FAILURE: Field creation succeeded but returned no Artifacts.", client);
     }
      
     Int32 fieldID = results.Results.Single().Artifact.ArtifactID;
     Console.WriteLine("\tArtifactID of new Field: {0}", fieldID);
      
     return fieldID;
}
        

Update Fields on an RDO

You can update specific Fields on a DTO. This code sample creates a new DTO with the same ArtifactID as the one that you want to update. It illustrates how to update value of the Last Name and Text Identifier fields, and sets the value for the newly created Address field, which is currently blank.

The ArtifactTypeGuids property indicates the object type of the RDO, which is Custodian. You can use ArtifactGuid instead of ArtifactID, and ArtifactTypeID or ArtifactTypeName instead of ArtifactTypeGuids. We recommend using GUIDs since they are unique across Relativity and they can't be modified. See .

This code sample updates the Last Name and Text Identifier fields on the Custodian RDO. It also sets the Address, which is blank.

private static void UpdateRdo(IRSAPIClient client, Int32 rdoID, Int32 fieldID)
{
     Console.WriteLine("\n\tUpdating RDO... ");
      
     // rdoID is the ArtifactID of the RDO that you want to update. 
     // The ArtifactTypeGuids indicates object type of the RDO, which is Custodian.
     // You can use an ArtifactGuid instead of the ArtifactID.
     var updatedRdo = new DTOs.RDO(rdoID);
      
     // You can replace the ArtifactTypeGuids with either ArtifactTypeID or ArtifactTypeName.
     // Use GUIDs because they are unique across all of Relativity and can't be modified.
     updatedRdo.ArtifactTypeGuids = new List<Guid>() { TutorialConstants.CUSTODIAN_TABLE_GUID };
      
     // List all Fields to be updated and their new values.
     // Any Fields not listed remain unchanged.
     updatedRdo.Fields = new List<DTOs.FieldValue>();
     updatedRdo.Fields.Add(new DTOs.FieldValue(TutorialConstants.LAST_NAME_FIELD_GUID,
          TutorialConstants.UPDATED_CUSTODIAN_LAST_NAME_VALUE));
     updatedRdo.Fields.Add(new DTOs.FieldValue(TutorialConstants.TEXT_IDENTIFIER_FIELD_GUID,
          TutorialConstants.UPDATED_CUSTODIAN_TEXT_IDENTIFIER_VALUE));
     updatedRdo.Fields.Add(new DTOs.FieldValue(fieldID, TutorialConstants.UPDATED_CUSTODIAN_ADDRESS_VALUE, true));
      
     // Send updated RDO and receive results.
     DTOs.WriteResultSet<DTOs.RDO> results = client.Repositories.RDO.Update(updatedRdo);
      
     if (!results.Success)
     {
          WriteFailedResultAndExit(results, client);
     }
     Console.WriteLine("\tLast Name, Text Identifier, and Address [...] values updated.");
}
        

Read an RDO

To read, call the Read() method which takes a DTO of type RDO as an argument. The following code sample reads the ArtifactTypeName of the Custodian RDO.

private static void ReadRdo(IRSAPIClient client, Int32 rdoID)
{
     Console.WriteLine("\n\tReading RDO... ");
     DTOs.ResultSet<DTOs.RDO> results =
          client.Repositories.RDO.Read(new DTOs.RDO(TutorialConstants.CUSTODIAN_TABLE_GUID, rdoID));
      
     if (!results.Success)
     {
          WriteFailedResultAndExit(results, client);
     }
     if (!results.Results.Any())
     {
          WriteErrorAndExit("FAILURE: RDO read succeeded but returned no Artifacts.", client);
     }
      
     // The following line prints "ArtifactTypeName of RDO is 'Custodian'."
     Console.WriteLine("\tArtifactTypeName of RDO is '{0}'.", results.Results.Single().Artifact.ArtifactTypeName);
}
        

Query for RDOs

You can perform searches for RDOs by using the Query DTO. In addition, you can return specific Field values on an Artifact by adding them to the query:

query.Fields.Add(new DTOs.FieldValue("Phone Number"));
        

You can use this sample code to query for all Custodians and then print their ArtifactIDs. If your workspace contains only the newly added Custodian, then this code prints just its ArtifactID. For information about available fields, see Constant Field names.

private static void QueryRdo(IRSAPIClient client)
{
     Console.WriteLine("\n\tQuerying RDO... ");
      
     var rdoQuery = new DTOs.Query<DTOs.RDO>();
     rdoQuery.ArtifactTypeGuid = TutorialConstants.CUSTODIAN_TABLE_GUID;
     rdoQuery.Fields = DTOs.FieldValue.NoFields;
      
     // To obtain more details about an Artifact, add Fields to the query. 
     // For example, you might add: query.Fields.Add(new DTOs.FieldValue("Phone Number"));
      
     // Send the Query to Relativity.
     DTOs.QueryResultSet<DTOs.RDO> results = client.Repositories.RDO.Query(rdoQuery);
      
     if (!results.Success)
     {
          WriteFailedResultAndExit(results, client);
     }
     if (!results.Results.Any())
     {
          WriteErrorAndExit("FAILURE: RDO query succeeded but returned no Artifacts.", client);
     }
     Console.WriteLine("\tArtifactID of each Custodian:");
      
     foreach (var res in results.Results)
     {
          Console.WriteLine("\t  {0}", res.Artifact.ArtifactID);
     }
}
        

Delete a Field on an RDO

You can remove a Field from an RDO by calling the Delete() method and passing the ArtifactID of the Field to it. To confirm the deletion, this code sample attempts to read the Field.

private static void DeleteField(IRSAPIClient client, Int32 fieldID)
{
     Console.WriteLine("\n\tDeleting Field... ");
      
     // Delete the Custodian RDO's newly added Field.
     DTOs.WriteResultSet<DTOs.Field> deleteResult = client.Repositories.Field.Delete(new DTOs.Field(fieldID));
      
     // Try to read the same Field.
     DTOs.ResultSet<DTOs.Field> readResult = client.Repositories.Field.Read(new DTOs.Field(fieldID));
     if (!deleteResult.Success)
     {
          WriteFailedResultAndExit(deleteResult, client);
     }
     else if (readResult.Success)
     {
          WriteErrorAndExit("FAILURE: Reading back the deleted Field should not have succeeded.", client);
     }
}
        

Delete an RDO

You remove a DTO from Relativity by calling the Delete() method and passing the ArtifactID of the object to it. This code sample deletes the Custodian RDO and then attempts to perform a read operation to confirm that this object no longer exists.

private static void DeleteRdo(IRSAPIClient client, Int32 rdoID)
{
     Console.WriteLine("\n\tDeleting RDO... ");
      
     // Delete the Custodian with ArtifactID of rdoID.
     DTOs.WriteResultSet<DTOs.RDO> deleteResult = 
          client.Repositories.RDO.Delete(new DTOs.RDO(TutorialConstants.CUSTODIAN_TABLE_GUID, rdoID));
      
     // Try to read the same Custodian.
     DTOs.ResultSet<DTOs.RDO> readResult = 
          client.Repositories.RDO.Read(new DTOs.RDO(TutorialConstants.CUSTODIAN_TABLE_GUID, rdoID));
      
     if (!deleteResult.Success)
     {
          WriteFailedResultAndExit(deleteResult, client);
     }
     else if (readResult.Success)
     {
          WriteErrorAndExit("FAILURE: Reading back the deleted Custodian should not have succeeded.", client);
     }
}
        

Exit the program

When you finish a session, you don't need to complete any additional steps to log out or close the proxy. The RSAPIClient automatically completes these tasks. This sample code requests a response from the user before the program closes.

public static void PauseBeforeExit()
{
     Console.WriteLine("\nPlease press enter to end the program.");
     Console.ReadLine();
}
        

Write success and failure messages

The following sample code illustrates how to write out messages that indicate the success or failure of the program, as well as how to log out if an error occurs.

Obtain a result message

This sample code attempts to find the first Result in ResultSets with a non-empty, non-whitespace message. The individual Results usually contain a message indicating when a failure occurs. However, this code shows the overall message for the ResultSet when a more specific failure message isn’t available. This code can be used to read the most specific messaging from any ResultSet. However, this program only attempts to read messaging from failed operations, because successful operations rarely contain messaging. See Obtain an error message.

private static string GetResultMostSpecificResultSetMessage<T>(DTOs.ResultSet<T> results) where T : DTOs.Artifact
{
     string resultMessage = results.Results.Any(result => !string.IsNullOrWhiteSpace(result.Message))
          ? results.Results.First().Message
          : results.Message;
      
     return resultMessage;
}
        

Stop the program due to an error

This sample code writes out a message and then logs out of the proxy when an error occurs.

private static void WriteErrorAndExit(String message, IRSAPIClient client)
{
     Console.WriteLine(message);
      
     PauseBeforeExit();
      
     Environment.Exit(1);
}
        

Obtain an error message

This sample code illustrates how to obtain an error message from a ResultSet object, and how to write out the message before terminating the program. For more information about this code, see Obtain a result message.

private static void WriteFailedResultAndExit<T>(DTOs.ResultSet<T> results, 
     IRSAPIClient client) where T : DTOs.Artifact
{
     string failureMessage = GetResultMostSpecificResultSetMessage(results);
      
     WriteErrorAndExit(string.Format("FAILURE: {0}", failureMessage), client);
}
        

Build and run the program

You can download the complete source code for building and running the client in Visual Studio. To download the complete code for this sample client, click here.

Note: You need to install the application as well as update the username and password so the sample program can run in your Relativity environment. See Before you begin.

After running your program, you should see results similar to that displayed here, but with different ArtifactIDs:

Proxy created.

 

Logged in.

 

Finding and entering Workspace.

 

Creating RDO...

ArtifactID of new RDO: 1042640

 

Creating Field...

ArtifactID of new Field: 1042641

 

Updating RDO...

Last Name, Text Identifier, and Address […] values updated.

 

Reading RDO...

ArtifactTypeName of RDO is 'Custodian'

 

Querying RD...

ArtifactID of each Custodian: 1042640

 

Deleting Field…

 

Deleting RDO…

 

Please press enter to end the program.