<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mecomis</title>
    <description>The latest articles on DEV Community by Mecomis (@mecomis).</description>
    <link>https://dev.to/mecomis</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2715123%2Fb857ebd1-d0b4-4ea1-ac44-bc953d5ebf36.jpg</url>
      <title>DEV Community: Mecomis</title>
      <link>https://dev.to/mecomis</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mecomis"/>
    <language>en</language>
    <item>
      <title>Working with Helix ALM REST API Part 6: Automated Testing</title>
      <dc:creator>Mecomis</dc:creator>
      <pubDate>Mon, 17 Mar 2025 09:47:28 +0000</pubDate>
      <link>https://dev.to/mecomis/working-with-helix-alm-rest-api-part-6-automated-testing-43bm</link>
      <guid>https://dev.to/mecomis/working-with-helix-alm-rest-api-part-6-automated-testing-43bm</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwn5bkm2g7efzpv2n5f0z.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwn5bkm2g7efzpv2n5f0z.jpg" alt="Helix ALM logo" width="800" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today we'll conclude  our series of posts focusing on various features from Perforce's Helix ALM REST API. Today's feature is about working with a CI/CD (continuous integration/continuous delivery) pipeline for automated testing and integrating it with the API. If you are unfamiliar with Helix ALM, it is a modular suite of ALM tools that you can use to trace requirements, tests, and issues. ALM stands for Application Lifecycle Management, REST for Representational State Transfer, and API for Application Programming Interface.&lt;/p&gt;

&lt;p&gt;The Helix ALM REST API has several endpoints that developers can use for interfacing with their organization's Helix ALM instance. The wide variety of endpoints provide many possibilities for developers to create tools or scripts to aid in their organization's workflow, with few limitations.&lt;/p&gt;

&lt;p&gt;The REST API is available at:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://{organization}:{port}/helix-alm/api/v0/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and the Swagger UI interactive documentation tool is available at:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://{organization}:{port}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;where {organization} is the address of the REST API server. The address can be configured in the JSON configuration file of the REST API, typically located at:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;../Perforce/Helix ALM/helix-alm-rest-api/config/config.json&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;on the server that is running the Helix ALM instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automated Testing
&lt;/h2&gt;

&lt;p&gt;Helix ALM provides integration with CI/CD pipelines, allowing organizations to have full traceability between their builds and tests, and associating the results back to test cases. The system offers two primary methods for submitting build and test results: the Helix ALM Test Management plugin for Jenkins and a REST API for other testing tools and environments. For this article, we will focus on the latter.&lt;/p&gt;

&lt;p&gt;At the core of Helix ALM's automated testing framework are automation suites, which serve as containers for grouping related automated tests. These suites are logical organizations of a set of tests based on a common factor. The system supports both automatic and manual association of test results with test cases. Achieving this association using the REST API is a multi-step process.&lt;/p&gt;

&lt;p&gt;First, we need to create an automation suite, specifying the script ID prefix and any test cases we want to associate. It's also possible to associate the test cases later in a separate request to the &lt;/p&gt;

&lt;p&gt;&lt;code&gt;/{projectID}/automationSuites/{automationSuiteID}/testCases&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;endpoint. A successful creation will return an HTTP 201 response along with the created automation suite in the response body.&lt;/p&gt;

&lt;p&gt;With our automation suite created, we can now run our automated tests for a build and submit the results to the REST API. We need to send the results to the&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/{projectID}/automationSuites/{automationSuiteID}/submitBuild&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;endpoint, where the {automationSuiteID} is the ID we received in the response when we created the automation suite. The structure of the data that the endpoint is expecting is an Automation Build object with the following name-value pairs:&lt;br&gt;
Number (string)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Description&lt;/li&gt;
&lt;li&gt;Branch&lt;/li&gt;
&lt;li&gt;Start date&lt;/li&gt;
&lt;li&gt;Duration&lt;/li&gt;
&lt;li&gt;External URL&lt;/li&gt;
&lt;li&gt;Results, array of&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Where a Result object has its own name-value pairs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name&lt;/li&gt;
&lt;li&gt;Unique name&lt;/li&gt;
&lt;li&gt;Status&lt;/li&gt;
&lt;li&gt;Device&lt;/li&gt;
&lt;li&gt;Manufacturer&lt;/li&gt;
&lt;li&gt;Model&lt;/li&gt;
&lt;li&gt;OS&lt;/li&gt;
&lt;li&gt;OS version&lt;/li&gt;
&lt;li&gt;Browser&lt;/li&gt;
&lt;li&gt;Browser version&lt;/li&gt;
&lt;li&gt;Start date&lt;/li&gt;
&lt;li&gt;Duration (milliseconds)&lt;/li&gt;
&lt;li&gt;External URL&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is one more name-value pair named "properties" which accepts a JSON object of any name-value pair. This is for unique properties from the build process that do not match the REST API's structure, and can be included as part of the Automation Build or Result objects. The first name-value pair "name" is where we will associate the test from the build with our Helix ALM test case by appending the automation suite's script ID prefix to the test case's number. The unique name is the name of the test from the build process.&lt;/p&gt;

&lt;p&gt;The "status" value is a specific JSON object that the REST API expects. It's comprised of ID and label values. The ID and label follow the following convention:&lt;br&gt;
1 =&amp;gt; Passed&lt;br&gt;
2 =&amp;gt; Failed&lt;br&gt;
3 =&amp;gt; Skipped&lt;br&gt;
4 =&amp;gt; Blocked&lt;br&gt;
5 =&amp;gt; Unknown&lt;/p&gt;
&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Let's see how we can implement the above description of automation suites into a simple example.&lt;/p&gt;

&lt;p&gt;An automation suite item first needs a name, like "Alpha Tests" or "Final Tests"; then it needs a description; a true or false value if it is active; a list of test cases that are associated with the suite; a list of owners; and finally the script ID prefix, which can be like "Alpha-" or "Final-".&lt;/p&gt;

&lt;p&gt;Regardless of the programming language of choice, we want something, when serialized, to represent the following JSON object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"automationSuitesData"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example Test Suite"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Automation suite for grouping our automated tests."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"active"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"scriptIDPrefix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EX-"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"owners"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"lastName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"John"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"firstName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Doe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;135&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jdoe"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"testCases"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"testCasesData"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this we attach it to the body of our POST request and send it to the /{projectID}/automationSuites endpoint. Upon success, we will receive a response along with some JSON data in the body. What we need to record are the ID, associated test cases, and script ID prefix values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"automationSuitesData"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;135&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example Test Suite"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Automation suite for grouping our automated tests."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"active"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"scriptIDPrefix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EX-"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"testCases"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"testCasesData"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Either the build process triggers the creation of an automation suite when it is completed or the automation suite is created before the build process begins, and this will depend on the individual organization. Nonetheless, the outcome is the same because we begin the process of associating the results.&lt;/p&gt;

&lt;p&gt;The build process and the results of it will depend on what technology the organization is using. For this portion of the example, we will use a dummy test output for our automation suite process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Test Report
Start Date: 2025–01–01T14:30:00Z

Operating System: Windows 10 Pro (Version 21H2)

Test Suite: TC-1
Test Case: testValidLogin
Duration: 1.5 seconds
Result: Passed

Test Suite: TC-2
Test Case: testSearchWithInvalidKeyword
Duration: 1.8 seconds
Result: Failed
Error Message: Expected product count: 0 but found: 3
Stack Trace:
at com.example.tests.ProductSearchTests.testSearchWithInvalidKeyword(ProductSearchTests.java:42)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This dummy test report includes test cases 1 &amp;amp; 2, labelled as "test suite" in the dummy report. Our recently created automation suite should already have these test cases associated with it, if not, then we need to add them by making a POST to the &lt;/p&gt;

&lt;p&gt;&lt;code&gt;/{projectID}/automationSuites/{automationSuiteID}/testCases&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;endpoint.&lt;/p&gt;

&lt;p&gt;We now start the process of converting the test report into an automation build that can be accepted by the REST API. There will be a number of assumptions going forward and we will note them when clarity may be needed. First, we are assuming that the test report has already been parsed into a data structure that we can use. For this example, we will use C# and will map the dummy test report results to a list of Result records using a function that takes a "test suite" from the report and creates the appropriate Result. Recall that an Automation Build is an item with an array of Result items.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;MapTestSuite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TestSuite&lt;/span&gt; &lt;span class="n"&gt;testSuite&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;testSuite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestCases&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;testReportCase&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Result&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ScriptIdPrefix&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;testReportCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;UniqueName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;testReportCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;Duration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;testReportCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;OS&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;testSuite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;OsVersion&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;testSuite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OsVersion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;StartDate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;testSuite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;Status&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;ConvertTestResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;testReportCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="n"&gt;Properties&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ResultProperty&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"ErrorMessage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;testReportCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrorMessage&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"StackTrace"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;testReportCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StackTrace&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For simplicity, we are assuming that the duration has been converted to milliseconds.&lt;/p&gt;

&lt;p&gt;The "scriptIDPrefix" comes from when we created the automation suite, and it is needed to associate the test case with the result. Our test report calls the test case "test suite" in this example. We assume that the "TC-" prefix is removed when we are accessing the "Number" property, as shown on line 5.&lt;/p&gt;

&lt;p&gt;If you are unfamiliar with C#, line 2 uses the "Select" extension method to project each element of a sequence into a new form by incorporating the element's index.&lt;/p&gt;

&lt;p&gt;For line 12, we are assuming that the function "ConvertTestResult" converts the result of the test case to the "status" JSON object that the REST API is expecting. It follows the same pattern as mentioned above, where the ID: 1 =&amp;gt; Passed, 2 =&amp;gt; Failed, etc.&lt;/p&gt;

&lt;p&gt;For the Properties object, the items are stored in a simple list, and we are ignoring any checks if the test case from the report contains an error message or not. There can be additional properties from the test report that require their own entry; for example, "failure type" or "failure value".&lt;/p&gt;

&lt;p&gt;With the results created for the automation build, we can continue and add the remaining data: number, description, branch, start date, and the external URL where the test was run. All these values will depend on your individual organization. The only value required by the REST API is number, which it expects as a string and not a numeric value.&lt;/p&gt;

&lt;p&gt;Serializing the data we should get something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example build"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"branch"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example Branch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"startDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2025–01–01T07:58:33.074Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;533432&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"externalURL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://cicd.example.com:8080/job/ExampleJob/2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Additional Property"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Example value"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"results"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EX-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"uniqueName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"testValidLogin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"device"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"manufacturer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"os"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Windows 10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"osVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"21H2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"browser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"browserVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"startDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2025–01–01T07:58:33.074Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"externalURL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EX-2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"uniqueName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"testSearchWithInvalidKeyword"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"os"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Windows 10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"osVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"21H2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"startDate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2025–01–01T07:58:33.074Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Error Message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Expected product count: 0 but found: 3"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Stack Trace"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"at com.example.tests.ProductSearchTests.testSearchWithInvalidKeyword(ProductSearchTests.java:42)"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we attach it to the body of the POST request and send it to the &lt;/p&gt;

&lt;p&gt;&lt;code&gt;/{projectID}/automationSuites/{automationSuiteID}/submitBuild&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;endpoint. Upon success, we will receive a 201 response along with a &lt;br&gt;
builds data object containing the ID of the build we just submitted.&lt;br&gt;
Conclusion&lt;br&gt;
And that's all there is to it. The difficulty comes with mapping the test report produced by your CI/CD process. With proper planning and understanding of both your testing framework and the Helix ALM REST API structure, this integration can provide invaluable traceability between your development process and your test management system.&lt;/p&gt;




&lt;p&gt;This concludes our series about discussing various aspects about the Helix ALM REST API, we hope it has helped explain how things work and clarified any uncertainty. If you need help creating a solution for this process or need support with Helix ALM, contact us at Mecomis and we'll gladly help.&lt;/p&gt;

&lt;p&gt;Mecomis has over 20 years of experience with using Helix ALM, so if you have further questions about Helix ALM or a general inquiry, please contact us.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>restapi</category>
      <category>perforce</category>
      <category>helixalm</category>
    </item>
    <item>
      <title>Working with Helix ALM REST API Part 5: Test Steps Structure</title>
      <dc:creator>Mecomis</dc:creator>
      <pubDate>Fri, 14 Mar 2025 11:14:42 +0000</pubDate>
      <link>https://dev.to/mecomis/working-with-helix-alm-rest-api-part-5-test-steps-structure-37p7</link>
      <guid>https://dev.to/mecomis/working-with-helix-alm-rest-api-part-5-test-steps-structure-37p7</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj215f7w3p392nwt00sss.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj215f7w3p392nwt00sss.jpg" alt="Helix ALM Logo" width="800" height="222"&gt;&lt;/a&gt;&lt;br&gt;
Today we’ll be continuing our series of posts focusing on various features from Perforce’s Helix ALM REST API. Today’s feature is about the structure of test steps for test cases. If you are unfamiliar with Helix ALM, it is a modular suite of ALM tools that you can use to trace requirements, tests, and issues. ALM stands for Application Lifecycle Management, REST for Representational State Transfer, and API for Application Programming Interface.&lt;/p&gt;

&lt;p&gt;The Helix ALM REST API has several endpoints that developers can use for interfacing with their organization’s Helix ALM instance. The wide variety of endpoints provide many possibilities for developers to create tools or scripts to aid in their organization’s workflow, with few limitations.&lt;/p&gt;

&lt;p&gt;The REST API is available at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://{API URL}/helix-alm/api/v0/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the Swagger UI interactive documentation tool is available at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://{API URL}:{port}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where {API URL} is the address of the REST API server. The address can be configured in the JSON configuration file of the REST API, typically located at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;../Perforce/Helix ALM/helix-alm-rest-api/config/config.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;on the machine that is running the Helix ALM instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tests Steps Structures
&lt;/h2&gt;

&lt;p&gt;The Helix ALM REST API has two different types of test step objects: basic and detailed. Both are quite similar with a few key differences that we will go into depth on in the test case step structure section. Finally, we will look at manual test runs and the structure of the JSON object that the REST API provides.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test Case Step Structure
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Common Object Structures
&lt;/h4&gt;

&lt;p&gt;The general structure of the test case step shares a common base that resembles the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;steps&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(TestCaseStepContainer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object):&lt;/span&gt;&lt;span class="w"&gt;  
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;  
  &lt;/span&gt;&lt;span class="err"&gt;self:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;string&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="err"&gt;stepsData&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(TestCaseStepData&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object):&lt;/span&gt;&lt;span class="w"&gt;  
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;  
    &lt;/span&gt;&lt;span class="err"&gt;modifiedToCorrectSyntax:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;boolean&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="err"&gt;type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;basic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;detailed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="err"&gt;basic:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TestCaseBasicStepData&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;objects&lt;/span&gt;&lt;span class="w"&gt; 
    &lt;/span&gt;&lt;span class="err"&gt;detailed:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TestCaseDetailedStepData&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;objects&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;  
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is where the structure diverges, depending on the type of test case step data object that it is. Before we investigate the basic and detailed test case step data objects, let’s examine a few additional objects that are common to both basic and detailed test case steps.&lt;/p&gt;

&lt;h5&gt;
  
  
  FileReference Object Structure
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;fileReference:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;id:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;int&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;referenceType:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;attachment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;sourceFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  ExpectedResult Object Structure
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;expectedResult:&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="err"&gt;text:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;string&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="err"&gt;fileReferences:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;FileReference&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;objects&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  SharedStep Object Structure
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;shared:&lt;/span&gt;&lt;span class="w"&gt;  
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="err"&gt;testCaseID:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;int&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="err"&gt;link:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;string&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Basic
&lt;/h4&gt;

&lt;p&gt;First up is the TestCaseBasicStepData object, which represents test cases that have their view mode property set to basic to text.&lt;/p&gt;

&lt;p&gt;The TestCaseBasicStepData object resembles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;fileReferences&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;shared&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;comment:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;string&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;expectedResult:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ExpectedResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;fileReferences:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;FileReference&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;objects&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;shared:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;SharedStep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;step:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TestCaseBasicStep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expanding on the TestCaseBasicStep object, we see that it resembles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;step:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;number:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;int&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;text:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;string&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;stepRows:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TestCaseBasicStepRow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;objects&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Drilling down further for the stepRows name and examining the TestCaseBasicStepRow object, we see that it is comprised of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;expectedResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;expectedResult:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ExpectedResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Detailed
&lt;/h4&gt;

&lt;p&gt;Next is the TestCaseDetailedStepData object, which represents test cases with detailed grid view set on the view mode property.&lt;/p&gt;

&lt;p&gt;The TestCaseDetailedStepData object resembles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;shared&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;comment:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;string&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;shared:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;SharedStep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;step:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TestCaseDetailedStep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Like the basic test case step, the detailed object contains a further object for the test case step. It resembles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;step:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;number:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;int&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;text:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;string&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;stepRows:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TestCaseDetailedStepRow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;objects&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The TestCaseDetailedStepRow is similar to the TestCaseBasicStepRow. It resembles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;expectedResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;stepNote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;expectedResult:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ExpectedResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;stepNote:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;string&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Manual Test Run Step Structure
&lt;/h2&gt;

&lt;p&gt;Testers can enter results (Pass, Failed, or Undetermined) on each manual test run step in Detailed Grid View, but not in Text View or Grid View.&lt;/p&gt;

&lt;p&gt;The manual test run step object mostly resembles the same structure as the test case step one but with a few key differences.&lt;/p&gt;

&lt;p&gt;First, all objects follow the same naming pattern but are renamed to TestRun–. Test runs derived from basic test cases have some additional data that will be explored below. In addition, since there is a lot of overlap with test cases, we will exclude values that were shown in the previous section.&lt;/p&gt;

&lt;p&gt;TestRunStepsData object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;basic:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TestRunBasicStepData&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;comment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;step&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;expectedResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;fileReferences&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;problemStatement&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;expectedResult:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TestRunBasicExpectedResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;completed:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;boolean&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;problemStatement:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;string&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;detailed:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TestRunDetailedStepData&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;step:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TestRunStep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;stepRows:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;array&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TestRunStepRow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;objects&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;expectedResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;stepNote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;testCaseStepNote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;problemStatement&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;problemStatement:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;string&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;testCaseStepNote:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;string&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;stepResult:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;TestRunStepResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;dateTime:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;DateTime&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;result:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;undetermined&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;user:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;actualResult:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ExpectedResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;object&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see, there are quite a few differences, but, at the same time, quite a few similarities too. Keep the following in mind when working with manual test runs:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Step results are only returned if they have a value. To add a step result, you must add it to the step and update the manual test run. You cannot delete a step result.
Step notes must be added before expected results.
Step text is read-only and cannot be edited. However, some data can be manipulated depending on the test run type. Consult the table below.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Test Run type&lt;/th&gt;
&lt;th&gt;Available editing actions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Text View (basic)&lt;/td&gt;
&lt;td&gt;None; read-only.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Grid View (basic)&lt;/td&gt;
&lt;td&gt;Change the “completed” property.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Add, edit, &amp;amp; delete “problemStatement”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Detailed Grid View (detailed)&lt;/td&gt;
&lt;td&gt;Add, edit, delete “problemStatement”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Add, edit, &amp;amp; delete “actualResults”&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Add, edit, &amp;amp; delete “stepNote”[1]&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Add or modify the TestRunStepResult’s “result”&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;[1] Not to be confused with the “testCaseStepNote”, which is read-only.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;In conclusion, the Helix ALM REST API provides a robust and flexible way to interact with test steps in both test cases and manual test runs. By understanding the different object structures for basic and detailed test steps, as well as the nuances between test case steps and manual test run steps, developers can effectively read, write, and manipulate test step data programmatically.&lt;/p&gt;

&lt;p&gt;By leveraging the Helix ALM REST API and these test step structures, organizations can build custom tools and integrations to streamline their test management processes. Whether it’s automatically generating test cases, aggregating test results, or synchronizing data with other systems, the possibilities are vast. As always, refer to the official Helix ALM REST API documentation for the most up-to-date and detailed information.&lt;/p&gt;




&lt;p&gt;Thank you for reading our article about the Helix ALM REST API, we hope it has helped explain the error and response codes that you will run into when using the API. In part 6 we will conclude this series by looking at automated testing.&lt;/p&gt;

&lt;p&gt;Mecomis has over 20 years of experience with using Helix ALM, so if you have further questions about Helix ALM or a general inquiry, please &lt;a href="https://mecomis.com/contact/" rel="noopener noreferrer"&gt;contact us&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>restapi</category>
      <category>perforce</category>
      <category>programming</category>
      <category>helixalm</category>
    </item>
    <item>
      <title>Working with Helix ALM REST API Part 4: Error and Response Codes</title>
      <dc:creator>Mecomis</dc:creator>
      <pubDate>Fri, 31 Jan 2025 14:24:00 +0000</pubDate>
      <link>https://dev.to/mecomis/working-with-helix-alm-rest-api-part-4-error-and-response-codes-45kn</link>
      <guid>https://dev.to/mecomis/working-with-helix-alm-rest-api-part-4-error-and-response-codes-45kn</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdfs0eqywrr3vkl5hfa3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdfs0eqywrr3vkl5hfa3.jpg" alt="Helix ALM Logo" width="800" height="222"&gt;&lt;/a&gt;&lt;br&gt;
Helix ALM LogoToday we'll be continuing our series of posts focusing on various features from Perforce's Helix ALM REST API. Today's feature is about the API's error and response codes. If you are unfamiliar with Helix ALM, it is a modular suite of ALM tools that you can use to trace requirements, tests, and issues. ALM stands for Application Lifecycle Management, REST for Representational State Transfer, and API for Application Programming Interface.&lt;/p&gt;

&lt;p&gt;The Helix ALM REST API has several endpoints that developers can use for interfacing with their organization's Helix ALM instance. The wide variety of endpoints provide many possibilities for developers to create tools or scripts to aid in their organization's workflow, with few limitations.&lt;/p&gt;

&lt;p&gt;The REST API is available at:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://{API URL}/helix-alm/api/v0/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and the Swagger UI interactive documentation tool is available at:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://{API URL}:{port}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;where {API URL} is the address of the REST API server. The address can be configured in the JSON configuration file of the REST API, typically located at:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;../Perforce/Helix ALM/helix-alm-rest-api/config/config.json&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;on the machine that is running the Helix ALM instance.&lt;/p&gt;
&lt;h1&gt;
  
  
  Error and Response Codes
&lt;/h1&gt;

&lt;p&gt;The Helix ALM REST API has three kinds of response codes, two of which are error codes. Responses may include a JSON object in the body providing additional information. The first kind of response codes has to do with the 200 range of HTTP responses, the second covers client error codes of the 400 range, and the last are server error codes of the 500 range.&lt;/p&gt;
&lt;h2&gt;
  
  
  Success Codes
&lt;/h2&gt;
&lt;h3&gt;
  
  
  200 - Success
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;200&lt;/code&gt; status code indicates that the request was successful. The response returned is unique to the specific request and may contain data or other relevant information. Typically, for a GET or PUT endpoint response, the data is a JSON object with a single item or a list of items. In the case of the search POST endpoint, it is a list of items that match the search query.&lt;/p&gt;

&lt;p&gt;For example, the GET endpoint for querying a list of projects returns a JSON object that looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"projects"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{project name}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"uuid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{UUID}"&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{project name}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="nl"&gt;"uuid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{UUID}"&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="err"&gt;etc…&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"projectsLoading"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PUT requests generally return the status code 200 when updating a list of objects; otherwise, the PUT request returns status code 204 when updating a specific item. The JSON object returned upon updating a list of items is the same list of the items but a reduced object with only a few name/value pairs in each item. An example of this looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"{item types}"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;XX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;YYY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"tag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ZZ-ZZZ"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"self"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://{organization}:{port}/helix-alm/api/v0/{project id}/{item type}/{id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ttstudioURL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ttstudio://{organization}:{port}//{project id}/dfct?recordID={id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"httpURL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://{organization}/ttweb/index.html#Default/{project id}/{item type}/{id}/"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;etc…&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  201 - Success (Created Item)
&lt;/h3&gt;

&lt;p&gt;When a request to create a new item is successful, the API returns a &lt;code&gt;201&lt;/code&gt; status code. Similar to the &lt;code&gt;200&lt;/code&gt; code, the response is specific to the request and may include additional details about the newly created item.&lt;/p&gt;

&lt;p&gt;An example of this looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"{item types}"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;XX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"number"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;YYY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"tag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ZZ-ZZZ"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"self"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://{organization}:{port}/helix-alm/api/v0/{project id}/{item type}/{id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ttstudioURL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ttstudio://{organization}:{port}//{project id}/dfct?recordID={id}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"httpURL"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://{organization}/ttweb/index.html#Default/{project id}/{item type}/{id}/"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;etc…&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  204 - Success (Updated Item)
&lt;/h3&gt;

&lt;p&gt;If an item is successfully updated through an API request, a &lt;code&gt;204&lt;/code&gt; status code is returned. In this case, no additional information is provided in the response.&lt;/p&gt;

&lt;h3&gt;
  
  
  206 - Partial Success
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;206&lt;/code&gt; status code signifies that the request was partially successful, this error may occur when a PUT or POST request with multiple items has a problem with one item, but changes to or creation of other items are successful. The response contains details about which parts of the request succeeded and which failed.&lt;/p&gt;

&lt;p&gt;The response data is an errorResponseArray object, comprised of two parts: the error array and the items array of the updated or created items.&lt;/p&gt;

&lt;p&gt;An example where the Steps field is missing a formattedString property looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"errors"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The Steps field must have a formattedString property."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"statusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bad Request"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"errorElementPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/{item type}/{index in items array}/fields/{index in fields array}"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"{item types}"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;…&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: the items array is excluded for brevity and resembles the response body from code 201.&lt;/p&gt;

&lt;h2&gt;
  
  
  Client Error Codes
&lt;/h2&gt;

&lt;p&gt;When a request is unsuccessful, the server will return one of these error codes. The object in the body depends on the nature of the error. Typically, the object consists of an HTTP status code, a description of the code, along with the error message itself. Some error codes may include the path to the element that caused the error.&lt;/p&gt;

&lt;h3&gt;
  
  
  400 - Bad Request
&lt;/h3&gt;

&lt;p&gt;When a request is missing required parameters or contains invalid information, the API returns a &lt;code&gt;400&lt;/code&gt; status code. This indicates that the client needs to modify the request before sending it again.&lt;br&gt;
An example of the error response object returned looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Validation errors. Invalid parameter (issues): Value failed JSON Schema validation. Expected type string but found type integer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"statusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bad Request"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"errorElementPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/issues/0/fields/1/label"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The "errorElementPath" value indicates the location of where the offending data was incorrect in the request object.&lt;br&gt;
In our example the error path is "/issues/0/fields/1/label". "issues" is the item type; 0 is the index of the issue in the zero-based array object; "fields" is the object where the error occurred, in the second field object (denoted by 1), at the label value.&lt;/p&gt;
&lt;h3&gt;
  
  
  401 - Unauthorized
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;401&lt;/code&gt; status code means that access is denied due to incorrect or unrecognized credentials, such as an invalid username/password combination or an expired access token.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Access denied"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"statusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Unauthorized"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  403 - Forbidden
&lt;/h3&gt;

&lt;p&gt;If a user doesn't have the necessary permissions to perform the requested action, a &lt;code&gt;403&lt;/code&gt; status code is returned. This could be due to various reasons, such as not having a valid license, not being part of the requested project, or lacking the required security commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"You cannot log in to this project."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"statusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Forbidden"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  404 - Not Found
&lt;/h3&gt;

&lt;p&gt;When the requested record or resource cannot be found, the API returns a &lt;code&gt;404&lt;/code&gt; status code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "message": "No project found with name \"Unknown Project\"",
  "statusCode": 404,
  "code": "Not Found"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  409 - Conflict
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;409&lt;/code&gt; status code indicates that a conflict occurred while processing the request. This could happen if the record is locked by another user or if the project is locked by an administrator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "message": "Record is locked for editing by another user.",
  "statusCode": 409,
  "code": "Conflict"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  429 - Too Many Requests
&lt;/h3&gt;

&lt;p&gt;If a user sends too many requests within a specified rate limiting timeframe, the API may return a &lt;code&gt;429&lt;/code&gt; status code to prevent abuse or overload.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The rate limit has been exceeded. Retry in X seconds."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"statusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;429&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Rate limit exceeded"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Server Error Codes
&lt;/h2&gt;

&lt;p&gt;These error codes generally indicate an issue on the server side of the Helix ALM REST API.&lt;/p&gt;

&lt;h3&gt;
  
  
  500 - Internal Server Error
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;500&lt;/code&gt; status code is a generic error indicating that something went wrong on the server side. The error message included in the response may provide more details about the specific issue.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The server experienced an error handling the request."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"statusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Internal Server Error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"errorElementPath"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/{item type}/{index}"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  503 - Service Unavailable
&lt;/h3&gt;

&lt;p&gt;When the API server is unavailable or busy, a &lt;code&gt;503&lt;/code&gt; status code is returned. This could be caused by throttling or a server lock due to high traffic or maintenance.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The service is currently overloaded."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"statusCode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;503&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Service Unavailable"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Understanding the various response and error codes in the Helix ALM REST API is essential for effective integration and troubleshooting. The API follows standard HTTP status code conventions, with success codes (200–206) indicating successful operations, client error codes (400–429) helping developers identify and fix issues in their requests, and server error codes (500–503) signaling server-side problems. Each response type is accompanied by detailed JSON objects that provide specific information about the operation's outcome or the nature of any errors encountered. By familiarizing themselves with these codes and their associated response formats, developers can build more robust applications that properly handle both successful operations and potential error scenarios when interacting with the Helix ALM platform.&lt;/p&gt;




&lt;p&gt;Thank you for reading our article about the Helix ALM REST API, we hope it has helped explain the error and response codes that you will run into when using the API. In part 5 we will look at constructing test steps for test cases.&lt;/p&gt;

&lt;p&gt;Mecomis has over 20 years of experience with using Helix ALM, so if you have further questions about Helix ALM or a general inquiry, please &lt;a href="https://mecomis.com/contact" rel="noopener noreferrer"&gt;contact us&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>restapi</category>
      <category>programming</category>
      <category>helixalm</category>
      <category>perforce</category>
    </item>
    <item>
      <title>Working with Helix ALM REST API Part 3: Conventions &amp; Exceptions</title>
      <dc:creator>Mecomis</dc:creator>
      <pubDate>Mon, 27 Jan 2025 09:21:38 +0000</pubDate>
      <link>https://dev.to/mecomis/working-with-helix-alm-rest-api-part-3-conventions-exceptions-man</link>
      <guid>https://dev.to/mecomis/working-with-helix-alm-rest-api-part-3-conventions-exceptions-man</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo7paw5p4iethpf0y27vt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo7paw5p4iethpf0y27vt.jpg" alt="Helix ALM logo" width="800" height="222"&gt;&lt;/a&gt;Today we'll be continuing our series of posts focusing on various features from Perforce's Helix ALM REST API. Today's feature is about the API's conventions and exceptions. If you are unfamiliar with Helix ALM, it is a modular suite of ALM tools that you can use to trace requirements, tests, and issues. ALM stands for Application Lifecycle Management, REST for Representational State Transfer, and API for Application Programming Interface.&lt;/p&gt;

&lt;p&gt;The Helix ALM REST API has several endpoints that developers can use for interfacing with their organization's Helix ALM instance. The wide variety of endpoints provide many possibilities for developers to create tools or scripts to aid in their organization's workflow, with few limitations.&lt;/p&gt;

&lt;p&gt;The REST API is available at:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://{API URL}/helix-alm/api/v0/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and the Swagger UI interactive documentation tool is available at:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://{API URL}:{port}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;where &lt;code&gt;{API URL}&lt;/code&gt; is the address of the REST API server. The address can be configured in the JSON configuration file of the REST API, typically located at:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;../Perforce/Helix ALM/helix-alm-rest-api/config/config.json&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;on the machine that is running the Helix ALM instance.&lt;/p&gt;

&lt;h1&gt;
  
  
  API Conventions and Exceptions
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Case Sensitivity
&lt;/h2&gt;

&lt;p&gt;The API is case sensitive except for field names in the following areas, which are not case sensitive:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Search parameters&lt;/li&gt;
&lt;li&gt;PUT and POST fields array&lt;/li&gt;
&lt;li&gt;'fields' parameter that indicates the fields to return (URL parameter and POST search)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What this means in terms of constructing the request is that the URL's search and field query parameter can look like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/{endpoint}?search=PRODUCT = 'Wysi CRM'&lt;/code&gt;&lt;br&gt;
&lt;code&gt;/{endpoint}?fields=sUmMaRy,DESCRIPTION,product&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Note: the specified criteria of the search parameter is still subject to case sensitivity.&lt;/p&gt;

&lt;p&gt;The fields array in a PUT or POST body is the same as the above example in terms of case insensitivity and applies to the label value in the field object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"fields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"SUMMARY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"New issue from REST API"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prOduCt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"menuItem"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Activity Professional Suite (APS)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: the label of the menu item object is case sensitive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Date Formatting
&lt;/h2&gt;

&lt;p&gt;Date and date/time values are always specified in ISO 8601 extended format for UTC (GMT) time. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2025–01–01&lt;/li&gt;
&lt;li&gt;2025–01–01T00:00:00Z&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Helix ALM REST API returns dates and date/time information in the above format when requested. Serializing dates and date/time depends on the programming language used. In C#, serializing DateTime objects to ISO 8601 is done by default. An example of one such language that does not support the format by default is Python. To achieve this in Python, it requires the use of the datetime's "isoformat()" method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="n"&gt;current_time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;iso8601_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;current_time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isoformat&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;json_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;timestamp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;iso8601_string&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be sure to check the documentation of your chosen programming language to ensure that Datetime objects match Helix's format.&lt;/p&gt;

&lt;h2&gt;
  
  
  Numbers
&lt;/h2&gt;

&lt;p&gt;Numeric values must be represented in a consistent format regardless of the locale or region where the Helix ALM REST API is being used. Different locales may have different conventions for representing numbers, such as using commas or periods as decimal separators. However, the API expects decimal numbers to always use a period (.) as the decimal separator, regardless of the locale.&lt;br&gt;
Valid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"decimal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;3.1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Decimal Field"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"decimal"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Invalid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"decimal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Decimal Field"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"decimal"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Special Characters and Spaces in Field Names
&lt;/h2&gt;

&lt;p&gt;Field names and values that contain spaces or special characters may cause searches to fail and return 400. In order for searches to work properly with these fields, the names and values must include quotes around them.&lt;br&gt;
In terms of the search query parameters in a URL, this looks like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/{endpoint}?search='Versions Impacted' = '1.0'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Note: for readability, the spaces and special characters are not URL-escaped.&lt;/p&gt;

&lt;p&gt;In a POST search, the query would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"search"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"'Versions Impacted' = '1.0'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"fields"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"status"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"page"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"per_page"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"formattedText"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Field names that contain commas are not supported in URL search query parameters. Instead, use the POST search endpoint because JSON supports commas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Understanding these API conventions and exceptions is crucial for successful integration with the Helix ALM REST API. By following the guidelines for case sensitivity, date formatting, number representation, and handling of special characters, you can avoid common pitfalls and ensure their API requests are properly formatted. Remember to pay special attention to field naming conventions, use appropriate date formats based on your programming language, maintain consistent number formatting regardless of locale, and properly quote fields containing spaces or special characters. When working with complex field names, particularly those containing commas, utilize the POST search endpoint instead of URL parameters. These standards help maintain consistency and reliability across all API interactions.&lt;/p&gt;




&lt;p&gt;Thank you for reading our article about the Helix ALM REST API, we hope it has helped explain some of  the idiosyncrasies of the API. In part 4 we will look at the API's errors and response codes.&lt;/p&gt;

&lt;p&gt;Mecomis has over 20 years of experience with using Helix ALM, so if you have further questions about Helix ALM or a general inquiry, please &lt;a href="https://mecomis.com/contact" rel="noopener noreferrer"&gt;contact us&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>perforce</category>
      <category>restapi</category>
      <category>helixalm</category>
      <category>programming</category>
    </item>
    <item>
      <title>Working with Helix ALM REST API Part 2: Filtering</title>
      <dc:creator>Mecomis</dc:creator>
      <pubDate>Wed, 22 Jan 2025 10:44:04 +0000</pubDate>
      <link>https://dev.to/mecomis/working-with-helix-alm-rest-api-part-2-filtering-23i6</link>
      <guid>https://dev.to/mecomis/working-with-helix-alm-rest-api-part-2-filtering-23i6</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc1wsvwiigpg9rqqkivba.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc1wsvwiigpg9rqqkivba.jpg" alt="Helix ALM logo" width="800" height="222"&gt;&lt;/a&gt;&lt;br&gt;
Today we'll be continuing our  series of posts focusing on various features from Perforce's Helix ALM REST API. Today's feature is about using filters to limit the number of items returned by a request. If you are unfamiliar with Helix ALM, it is a modular suite of ALM tools that you can use to trace requirements, tests, and issues. ALM stands for Application Lifecycle Management, REST for Representational State Transfer, and API for Application Programming Interface.&lt;/p&gt;

&lt;p&gt;The Helix ALM REST API has several endpoints that developers can use for interfacing with their organization's Helix ALM instance. The wide variety of endpoints provide many possibilities for developers to create tools or scripts to aid in their organization's workflow, with few limitations.&lt;/p&gt;

&lt;p&gt;The REST API is available at:&lt;br&gt;
&lt;code&gt;https://{API URL}/helix-alm/api/v0/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and the Swagger UI interactive documentation tool is available at:&lt;br&gt;
&lt;code&gt;https://{API URL}:{port}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;where {API URL} is the address of the REST API server. The address can be configured in the JSON configuration file of the REST API, typically located at:&lt;br&gt;
&lt;code&gt;../Perforce/Helix ALM/helix-alm-rest-api/config/config.json&lt;/code&gt;&lt;br&gt;
on the machine that is running the Helix ALM instance.&lt;/p&gt;
&lt;h1&gt;
  
  
  REST API Features
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Filtering
&lt;/h2&gt;

&lt;p&gt;When throughput or bandwidth is an issue, or a subset of items is needed, the Helix ALM REST API allows calls to pass a set of query parameters to return a limited amount of items.&lt;/p&gt;
&lt;h2&gt;
  
  
  Fields
&lt;/h2&gt;

&lt;p&gt;The fields parameter returns only the specified fields back with the items. The parameter is an array of strings and comma separated. The fields parameter is included after the URL of the endpoint.&lt;br&gt;
An example looks like:&lt;br&gt;
&lt;code&gt;…/issues?fields=Status,Summary,Description&lt;/code&gt;&lt;br&gt;
Here we are returning only the fields "Status", "Summary", and "Description" with each Issue item. If a field has a space then it must be wrapped in single quotes, e.g. 'Has Attachments'.&lt;br&gt;
Lists of fields can be gotten from the Fields endpoints,&lt;br&gt;
&lt;code&gt;/{projectID}/configs/fields/{fieldItemType}/customFields&lt;/code&gt;&lt;br&gt;
and&lt;br&gt;
&lt;code&gt;/{projectID}/configs/fields/{fieldItemType}/systemFields&lt;/code&gt;&lt;br&gt;
where &lt;code&gt;{fieldItemType}&lt;/code&gt; is one of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;document fields&lt;/li&gt;
&lt;li&gt;issue fields&lt;/li&gt;
&lt;li&gt;requirement fields&lt;/li&gt;
&lt;li&gt;test case fields&lt;/li&gt;
&lt;li&gt;test run fields&lt;/li&gt;
&lt;li&gt;test variant fields&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Search
&lt;/h2&gt;

&lt;p&gt;The search parameter queries the API for items that match the specified criteria. The parameter is a string of fields with search operators and the search value. The search parameter is included after the URL of the endpoint.&lt;br&gt;
Let's look at an example.&lt;br&gt;
&lt;code&gt;…/testCases?search=Summary CONTAINS 'text in summary'&lt;/code&gt;&lt;br&gt;
This example searches for test case items where the summary field contains the specified text. To chain multiple search terms together a logical operator of "and", "or", or "not" needs to be used. &lt;br&gt;
For example:&lt;br&gt;
&lt;code&gt;…?search=Summary CONTAINS 'text in summary' AND Status = 'Open'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This example will look for items that contain the specified text in the summary field and also have the "Open" status. More detail about the search operators below. The logical operator is case-insensitive. &lt;br&gt;
It's important to note that a search query must be properly encoded for the URL, with the following characters escaped with their percent sign values:&lt;/p&gt;

&lt;p&gt;/ ? : @ - . _ ~ ! $ &amp;amp; ' ( ) * + , ; =&lt;/p&gt;

&lt;p&gt;Taking our previous example, the query now becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;…?search&lt;span class="o"&gt;=&lt;/span&gt;Summary%20CONTAINS%20%27text%20in%20summary%27%20and%20Status%20%3D%20%27Open%27
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be careful escaping the initial '=' after search as this is needed to indicate the start of the search query, and any subsequent '&amp;amp;' symbols for combining URL parameters, such as &lt;code&gt;'search=…&amp;amp;fields=…'&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Paging
&lt;/h2&gt;

&lt;p&gt;Paging can be used to reduce the amount of items returned per request. By default, the API returns 300 items per page unless the "per_page" parameter is set. The page parameter is used for navigating between the pages and fetching the next batch of items.&lt;br&gt;
In the response object, there is an additional section with paging information.&lt;br&gt;
The paging object looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"paging"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"page"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;number&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pageLimit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;limit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;per&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;page&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"totalCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;items&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"totalPages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"links"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"self"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{url}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"first"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{url}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"last"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{url}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"next"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"href"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{url}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GET"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Page number is the current page number of the response. Page limit is the number of items per page. Total count is how many items there are in total. Total pages is how many pages there are in total.&lt;br&gt;
The page and per_page parameters are included in the query. An example of the query in the URL looks like:&lt;br&gt;
&lt;code&gt;…?page=1&amp;amp;per_page=10&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Operator syntax
&lt;/h2&gt;

&lt;p&gt;There are three logical operators and ten comparison operators for constructing a query.&lt;br&gt;
The logical operators are: "and", "not", and "or".&lt;br&gt;
The comparison operators are:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EQUALS&lt;/strong&gt; or &lt;strong&gt;=&lt;/strong&gt;&lt;br&gt;
This operator looks for an exact match of the value from the specified field&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOT EQUALS&lt;/strong&gt; or &lt;strong&gt;!=&lt;/strong&gt;&lt;br&gt;
A combination of the logical "not" and the equals comparison operator.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GREATER&lt;/strong&gt; or &lt;strong&gt;&amp;gt;&lt;/strong&gt;&lt;br&gt;
Applies to numeric and date-date/time fields&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GREATER_EQUAL&lt;/strong&gt; or &lt;strong&gt;&amp;gt;=&lt;/strong&gt;&lt;br&gt;
Applies to the same fields as GREATER&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LESS&lt;/strong&gt; or &lt;strong&gt;&amp;lt;&lt;/strong&gt;&lt;br&gt;
Applies to the same fields as GREATER&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LESS_EQUAL&lt;/strong&gt; or &lt;strong&gt;&amp;lt;=&lt;/strong&gt;&lt;br&gt;
Applies to the same fields as GREATER&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IN&lt;/strong&gt; or &lt;strong&gt;:&lt;/strong&gt;&lt;br&gt;
Applies to lists, folder, and number fields.&lt;br&gt;
Syntax is: &lt;code&gt;Field IN ('value-1', 'value-2')&lt;/code&gt;, equivalent to &lt;code&gt;Field = 'value-1', or Field = value-2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IN_RECURSE&lt;/strong&gt; or &lt;strong&gt;:?&lt;/strong&gt;&lt;br&gt;
Performs a recursive comparison in folders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CONTAINS&lt;/strong&gt; or &lt;strong&gt;~&lt;/strong&gt;&lt;br&gt;
Applies to text only fields for a case-insensitive comparison of the supplied string value with the specified field.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CONTAINS_CASE&lt;/strong&gt; or &lt;strong&gt;^&lt;/strong&gt;&lt;br&gt;
Applies to text only fields for a case-sensitive comparison of the supplied string value with the specified field.&lt;/p&gt;

&lt;p&gt;In addition to these operators, Boolean values are "true" and "false".&lt;/p&gt;

&lt;p&gt;For menu fields that have not been assigned a value, the value "NOT_SET" can be used, e.g. &lt;code&gt;Product = NOT_SET.&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The Helix ALM REST API provides developers with powerful and flexible ways to interact with their Helix ALM instance through various filtering mechanisms. By utilizing fields, search parameters, and paging options, developers can efficiently retrieve and manage data while optimizing performance. The API's comprehensive set of operators - including logical, comparison, and specialized operators for different data types - enables precise querying capabilities. This flexibility, combined with proper URL encoding and pagination handling, makes the API a robust tool for integrating Helix ALM into an organization's development workflow. &lt;/p&gt;

&lt;p&gt;Whether developers need to retrieve specific fields, search for particular items, or manage large datasets through paging, the API provides the necessary functionality to create effective tools and automation scripts.&lt;/p&gt;




&lt;p&gt;Thank you for reading our article about the Helix ALM REST API, we hope it has helped explain filtering with the API. In part 3 we will look at the API's conventions and exceptions.&lt;/p&gt;

&lt;p&gt;Mecomis has over 20 years of experience with using Helix ALM, so if you have further questions about Helix ALM or a general inquiry, please &lt;a href="https://mecomis.com/contact/" rel="noopener noreferrer"&gt;contact us&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>perforce</category>
      <category>restapi</category>
      <category>helixalm</category>
      <category>programming</category>
    </item>
    <item>
      <title>Working with Helix ALM REST API Part 1: Authentication</title>
      <dc:creator>Mecomis</dc:creator>
      <pubDate>Mon, 20 Jan 2025 11:20:20 +0000</pubDate>
      <link>https://dev.to/mecomis/working-with-helix-alm-rest-api-part-1-authentication-mj1</link>
      <guid>https://dev.to/mecomis/working-with-helix-alm-rest-api-part-1-authentication-mj1</guid>
      <description>&lt;p&gt;Today we’ll be starting a series of posts focusing on various features from Perforce’s Helix ALM REST API. Today’s feature is about authenticating a client. If you are unfamiliar with Helix ALM, it is a modular suite of ALM tools that you can use to trace requirements, tests, and issues. ALM stands for Application Lifecycle Management, REST for Representational State Transfer, and API for Application Programming Interface.&lt;/p&gt;

&lt;p&gt;The Helix ALM REST API has several endpoints that developers can use for interfacing with their organization’s Helix ALM instance. The wide variety of endpoints provide many possibilities for developers to create tools or scripts to aid in their organization’s workflow, with few limitations.&lt;/p&gt;

&lt;p&gt;The REST API is available at:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://{API URL}/helix-alm/api/v0/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and the Swagger UI interactive documentation tool is available at:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://{API URL}:{port}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;where {API URL} is the address of the REST API server. The address can be configured in the JSON configuration file of the REST API, typically located at:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;../Perforce/Helix ALM/helix-alm-rest-api/config/config.json&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;on the machine that is running the Helix ALM instance.&lt;/p&gt;

&lt;h1&gt;
  
  
  REST API Features
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Authentication
&lt;/h2&gt;

&lt;p&gt;There are several ways to authenticate with the REST API. However, to first make any requests the user must belong to a security group that has Allow Login via SOAP enabled in order to use the API. The RBAC (role-based access control) for the security group and user will depend on the your organization, but for this series we will be assuming that there are no restrictions on what the security group can access. It is also recommended to create an API key for the user, but it is not strictly necessary for authentication. If the API key is created, note it down somewhere because the key’s secret is only shown once. For both the security group and API key, an administrator must create these in the Helix ALM client application.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Authentication
&lt;/h3&gt;

&lt;p&gt;Basic authentication is done with the user’s username and password and attached in the request header. The value of the username and password must be Base64 encoded and conform to:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Authorization: Basic username:password&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  API Key Authentication
&lt;/h3&gt;

&lt;p&gt;Key authentication is similar to basic authentication but instead of including username and password in the header, the API key is sent instead. The value for the authorization header must conform to:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Authorization: ApiKey apiKey:apiSecret&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Access Token
&lt;/h3&gt;

&lt;p&gt;Regardless of which authentication method is chosen, all endpoints will require an access token — the only endpoints which do not require an access token are the projects and the token endpoints.&lt;/p&gt;

&lt;p&gt;To receive the access token, make a GET request to the endpoint:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;https://{API URL}/helix-alm/api/v0/{projectID}/token&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The project ID can be gotten from the /projects endpoint. Alternatively, the project name may be used instead but if there are spaces in the project’s name then these must be URL escaped.&lt;/p&gt;

&lt;p&gt;The response from the REST API is an access token object, shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tokenType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"expiresOn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2000–00–00T00:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"accessToken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eyJhbGciOiJIUzI1NiIsInR5… "&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The access token then needs to be included in the Authorization header with “Bearer” preceding the value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /helix-alm/api/v0/{ProjectID}/{Endpoint} HTTP/1.1
&amp;gt; Host: {Your host}
&amp;gt; accept: application/json
&amp;gt; Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In C#, setting the access token to the header might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SetRequestAccessToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt; &lt;span class="n"&gt;HttpRequestMessage&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AccessToken&lt;/span&gt; &lt;span class="n"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;authorization&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"Bearer &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AccessToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;authorization&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Server Certificate Validation Callback
&lt;/h2&gt;

&lt;p&gt;When any request is made to the Helix ALM REST API it will return a response with an SSL certificate. By default, it is a self-signed certificate that is created by the API the first time the server is launched. If a non-default certificate is used, then the configuration file must be modified to reflect this choice. This setting is found in the config file.&lt;/p&gt;

&lt;p&gt;How the program interfacing with the API handles the certificate callback is highly dependent on the programming language chosen. For our examples, we will ignore validation for now.&lt;/p&gt;

&lt;p&gt;In C# that might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;HttpClientHandler&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpClientHandler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClientCertificateOptions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ClientCertificateOption&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Manual&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServicePointManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServerCertificateValidationCallback&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
  &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;certificate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sslPolicyErrors&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;httpClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Python, ignoring the certificate can be done with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ssl_context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_default_context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;ssl_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;check_hostname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
&lt;span class="n"&gt;ssl_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify_mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CERT_NONE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then passing the "ssl_context" to the context parameter in the &lt;code&gt;urllib.request.urlopen()&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;In Go, initializing a transport and then passing it to the client can look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Transport&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;TLSClientConfig&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;InsecureSkipVerify&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;Transport&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using the REST API
&lt;/h2&gt;

&lt;p&gt;Now, let’s look at an example of how to use the REST API. This example will demonstrate authenticating with the “Traditional Template” project provided by Perforce. For other organizations, these item types may be named differently, but here the default terms of “issue”, “requirement”, “test case”, and “test run” will be used. The example code will be in C#, but it should be relatively straightforward to translate it into another programming language.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initialization
&lt;/h3&gt;

&lt;p&gt;First, we initialize the HTTP client with the base address and set the media type header.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Using the handler we created earlier for the server certificate callback&lt;/span&gt;
&lt;span class="n"&gt;HttpClient&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseAddress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://{API URL}/helix-alm/api/v0/"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Make sure the headers are clear&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultRequestHeaders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Clear&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Add "application/json" media type to the header&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultRequestHeaders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MediaTypeWithQualityHeaderValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Access Token
&lt;/h3&gt;

&lt;p&gt;Next, we will get an access token using the API key that was created for the REST API user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Be sure to URL escape the space&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Traditional Template/token"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;HttpRequestMessage&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpRequestMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpMethod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;authorization&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;$"ApiKey &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ApiKey&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;authorization&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;AccessToken&lt;/span&gt; &lt;span class="n"&gt;responseBody&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;SendRequest&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AccessToken&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, the third line may be substituted with the basic authentication approach if desired.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SendRequest&amp;lt;T&amp;gt;()&lt;/code&gt; is our method that uses our HttpClient object to send the request to the specified endpoint using the &lt;code&gt;HttpClient.SendAsync()&lt;/code&gt; method. &lt;code&gt;T&lt;/code&gt; is a generic object type that the method expects returned from the response. Here, we have specified that the object to return is of type &lt;code&gt;AccessToken&lt;/code&gt;. So what happens in our method is that it sends the request to the API, waits for a response, deserializes the JSON data into our &lt;code&gt;AccessToken&lt;/code&gt; class, and returns the data to the caller.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;AccessToken&lt;/code&gt; class is relatively simple, as we saw earlier from the JSON data in the API’s response, containing only a token type, expiration date, and the token itself. This is easy for a JSON deserializer to handle. For more complex data that need serialization, we can pass JSON serializer options, from the &lt;code&gt;System.Text.Json&lt;/code&gt; namespace, to our &lt;code&gt;SendRequest&amp;lt;T&amp;gt;()&lt;/code&gt; method, depending on which object we are deserializing. For your programming language of choice, you will have to consult the documentation for how to handle de/serializing data in JSON.&lt;/p&gt;

&lt;p&gt;Nonetheless, we now have our access token, which we will attach in the header for all subsequent HTTP requests. To attach the access token to the header, we can use a method such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;SetRequestAccessToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpRequestMessage&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AccessToken&lt;/span&gt; &lt;span class="n"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;authorization&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bearer {0}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AccessToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;authorization&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;    
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this example we looked at how to authenticate a client. We first initialized our HTTP client, attached our API key in the authorization header, sent our GET request to the /token endpoint, and received an access token for our future requests.&lt;/p&gt;

&lt;p&gt;There are more features and endpoints not covered here because their use will largely depend on the requirements of the individual organization in regards to its workflow and project management. However, this example should be enough to help anyone new to the Helix ALM REST API to get started.&lt;/p&gt;




&lt;p&gt;Thank you for reading our article about the Helix ALM REST API, we hope you have become a little bit more knowledgeable about authenticating a client for the API. In part 2 we will look at retrieving items using the REST API and how to limit the number of items returned.&lt;/p&gt;

&lt;p&gt;Mecomis has over 20 years of experience with using Helix ALM, so if you have further questions about Helix ALM or a general inquiry, please &lt;a href="https://mecomis.com/contact/" rel="noopener noreferrer"&gt;contact us&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>restapi</category>
      <category>perforce</category>
      <category>applicationlifecycle</category>
      <category>programming</category>
    </item>
    <item>
      <title>API Security: Vulnerability and Prevention</title>
      <dc:creator>Mecomis</dc:creator>
      <pubDate>Wed, 15 Jan 2025 13:56:50 +0000</pubDate>
      <link>https://dev.to/mecomis/api-security-vulnerability-and-prevention-10n4</link>
      <guid>https://dev.to/mecomis/api-security-vulnerability-and-prevention-10n4</guid>
      <description>&lt;p&gt;Cyber security is a frequent topic in the news and among developers. Today we will look at some security topics for APIs (application programming interfaces), how vulnerabilities can exist and some preventative measures. There are many different definitions of API, but as a simple definition for API, as the name suggests, is a programming interface that allows applications to communicate with each other. So how does this lead to security issues? Let's have a look.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication
&lt;/h2&gt;

&lt;p&gt;Authentication is the process of verifying the identity of the client making the API request. It answers the question: "Are you who you say you are?" The client proves their identity, commonly by providing an authenticator (username &amp;amp; password, security token, etc).&lt;/p&gt;

&lt;h3&gt;
  
  
  Vulnerabilities
&lt;/h3&gt;

&lt;p&gt;A common vulnerability is not having any measures in place to limit the number of log in attempts nor using a second authenticator. This vulnerability allows an attacker to brute force his way in by guessing or using stolen usernames and passwords. Other vulnerabilities are the lack of multi-factor authentication, sending passwords in URLs, weak password storage practices, and improper token validation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prevention
&lt;/h3&gt;

&lt;p&gt;First and foremost, it's important to have a complete understanding of all the possible authentication flows in one's system. Have multi-factor authentication where possible, especially for sensitive operations. Implementing anti-brute force mechanisms, rate limits, and lockout protections, using standard conventions for password storing, and token generation can go a long way for preventing potential incidents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authorization
&lt;/h2&gt;

&lt;p&gt;Authorization answers the question: "Are you allowed to do what you're trying to do?" The API  checks the client's permissions to decide if the requested operation should be permitted or denied.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vulnerabilities
&lt;/h3&gt;

&lt;p&gt;There are roughly three main types of authorization vulnerabilities that one should be aware of: broken object level authorization (BOLA) where users access unauthorized objects, broken function level authorization (BFLA) where users access unauthorized functions, and broken object property level authorization (BOPLA) where users modify unauthorized object properties.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prevention
&lt;/h3&gt;

&lt;p&gt;Authorization vulnerabilities can be solved by applying the principle of least privilege; although, this does not solve all authorization vulnerabilities, it is an important first step in controlling them. One BOLA preventative measure is performing a check on all actions that a client submits. BFLA prevention should deny all access by default, only opened where necessary. For BOPLA specifically, implement property-level checks and careful object serialization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resource Consumption
&lt;/h2&gt;

&lt;p&gt;APIs consume resources such as network bandwidth, memory, or storage, and when exploited such things can result in financial loss.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vulnerabilities
&lt;/h3&gt;

&lt;p&gt;APIs are vulnerable to large resource consumption if there are no restrictions in place to limit client calls. Unrestricted requests will quickly consume an API's network bandwidth, CPU, memory, and storage. Secondary effects could see the business incur costs associated with downstream, third-party API requests or storage providers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prevention
&lt;/h3&gt;

&lt;p&gt;Implement rate limiting, request throttling, configure spending limits for third-party services, and limit payload data size.&lt;/p&gt;

&lt;h2&gt;
  
  
  API Configurations
&lt;/h2&gt;

&lt;p&gt;It can be a tricky task to configure an API on first setup, maybe time is short or you just aren't familiar with the technology. In either case, misconfiguration can make an API vulnerable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vulnerabilities
&lt;/h3&gt;

&lt;p&gt;Common misconfiguration include: unchanged default settings, like default admin credentials or left open ports; unnecessary enabled features, like less secure endpoints used for testing; improper CORS headers, allowing cross-origin reads of sensitive API data; lack of encryption, such as no TLS support; and overly detailed error messages that expose system internals.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prevention
&lt;/h3&gt;

&lt;p&gt;Implement security throughout the API lifecycle with regular configuration reviews, automated assessments, proper encryption, restricted HTTP verbs, well-defined CORS policies, and careful error handling to prevent information leakage.&lt;/p&gt;




&lt;p&gt;Thank you for reading our article about API security, we hope you have become a little bit more knowledgeable in the fields of cyber security and APIs. If you would like to read our full article about API security, have further questions, or a general inquiry, please &lt;a href="https://mecomis.com/contact/" rel="noopener noreferrer"&gt;contact us&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>api</category>
      <category>softwaredevelopment</category>
      <category>cybersecurity</category>
    </item>
  </channel>
</rss>
