Clarity

 View Only
  • 1.  Using JSON inside process

    Posted Aug 28, 2024 02:43 PM

    I am fairly new to using API/JSON and improving my knowledge.

    I have started to use JSON messages within processes.  The JSON gets its data from SQL within the script.  Has anyone experienced the JSON failing with error 400 in Clarity but if I take the resulting JSON that has been stored in the logs and post this using Postman it is successful (200)?

    Also, unlike XOG which will pause a process from continuing if it errors, when a JSON message fails the process will carry on and complete.  Is there any way for the process to error and pause like XOG errors do?



  • 2.  RE: Using JSON inside process

    Posted Aug 28, 2024 06:46 PM

    Did you set all the correct headers? 

    A 400 means Bad Request, so there's probably something missing on your side. Try sending the same headers Postman does.

    As far as I know there's not a way to pause the script unless something throws an error. I achieved something similar by wrapping everything but <gel:script>

    in a for loop that goes from 0 to 0 and breaking when there's any error -- keep in mind this doesn't pause it, it simply ends the execution:

    <gel:script xmlns:gel="jelly:com.niku.union.gel.GELTagLibrary" xmlns:core="jelly:core" xmlns:sql="jelly:sql">
    
      <core:forEach begin="0" end="0">
    	
        <gel:parameter var="basic_token"/>
    	  
        <core:if test="${basic_token == null}">
          <gel:log level="ERROR">Cannot login to Clarity.</gel:log>
          <core:break/> <!-- should break the outer loop and stop the execution --> 
        </core:if>
    	  
        <core:set var="basic_token" value="Basic ${basic_token}"/>
    	  
    	 
        <core:invokeStatic className="com.niku.union.config.ConfigurationManager" method="getInstance" var="config"/>
        <core:set var="app_url" value="${config.getProperties().getWebServer().getWebServerInstance(0).getEntryUrl()}"/>
    
    
    	<!-- dummy query to get 3 tasks from a project and update them with the same data -->
        <gel:setDataSource dbId="niku"/>
        <sql:query var="result" escapeText="false">
    		<![CDATA[SELECT
    					TSK.prid,
    					TSK.prstatus
    				FROM
    					prtask TSK
    				WHERE
    					tsk.prprojectid = ?
    				LIMIT 3]]>
    		<sql:param value="${gel_objectInstanceId}"/>
    	</sql:query>
        <core:if test="${result.rowCount <= 0}">
          <gel:log level="INFO">NO ROWS TO UPDATE.</gel:log>
          <core:break/>
        </core:if>
    	  
    	<!--
    	BUILD SOMETHING LIKE:
    	{
    		'd': [
    			{'_internalId': 000000, 'status': 1},
                ...,
    		]
    	}
    	-->
        <core:new className="org.json.JSONObject" var="conn_payload"/>
        <core:forEach items="${result.rows}" var="row">
          <core:new className="org.json.JSONObject" var="payload"/>
          <core:expr value="${payload.put('_internalId', row.prid)}"/>
          <core:expr value="${payload.put('status', row.prstatus)}"/>
    		
          <core:expr value="${conn_payload.append('d', payload)}"/>
        </core:forEach>
    	  
        <gel:log level="INFO">PAYLOAD: ${conn_payload.toString()}</gel:log>
    	  
        <core:set var="url" value="${app_url}/ppm/rest/v1/projects/${gel_objectInstanceId}/tasks"/>
        <gel:log level="INFO">HITTING URL: ${url}</gel:log>
    
        <core:new className="java.net.URL" var="remote_url">
          <core:arg value="${url}"/>
        </core:new>
    	  
        <core:set var="conn" value="${remote_url.openConnection()}"/>
        <core:expr value="${conn.setRequestMethod('PUT')}"/>  <!-- For SaaS, PATCH doesn't seem to work?? so we use PUT + x-api-force-patch header set to true -->
        <core:expr value="${conn.setDoOutput(true)}"/>
        <core:expr value="${conn.setDoInput(true)}"/>
        <core:expr value="${conn.setConnectTimeout(3000)}"/>
        <core:expr value="${conn.setReadTimeout(6000)}"/>
        <core:expr value="${conn.setRequestProperty('x-api-force-patch', 'true')}"/> 
        <core:expr value="${conn.setRequestProperty('accept', 'application/json')}"/>
        <core:expr value="${conn.setRequestProperty('content-type', 'application/json')}"/>
        <core:expr value="${conn.setRequestProperty('Authorization', basic_token)}"/> <!-- Replace this line and all the basic_token stuff if you're using any other auth method -->
    
        <core:new className="java.io.OutputStreamWriter" var="writer">
          <core:arg value="${conn.getOutputStream()}"/>
        </core:new>
        <core:expr value="${conn_payload.write(writer)}"/>
        <core:expr value="${writer.flush()}"/>
        <core:expr value="${conn.connect()}"/>
    	<!-- read all the response body to String -->
        <core:invokeStatic className="org.apache.commons.io.IOUtils" method="toString" var="resp">
          <core:arg value="${conn.getInputStream()}" type="java.io.InputStream"/>
          <core:arg value="utf-8"/>
        </core:invokeStatic>
    	<!-- parse it to JSON -->
        <core:new className="org.json.JSONObject" var="resp">
          <core:arg value="${resp}"/>
        </core:new>
    	  
        <core:set var="status_code" value="${conn.getResponseCode()}"/>
        <core:expr value="${conn.close()}"/>
    
    	  
        <core:set var="errs" value="${resp.optJSONArray('_errors')}"/>
        <core:if test="${errs != null}">
          <gel:log level="ERROR">Got status code: ${status_code}</gel:log>
          <core:forEach items="${errs}" var="err">
            <gel:log level="ERROR">${err.toString()}</gel:log>
          </core:forEach>
        </core:if>
    
    
        <core:if test="${status_code != 200}">
          <gel:log level="ERROR">Got status code: ${status_code}</gel:log>
        </core:if>
      </core:forEach>
    </gel:script>

    That's how I would normally do it, without all the exception catching and token getting stuff.

    Cheers,

    Mauro.




  • 3.  RE: Using JSON inside process

    Posted Aug 29, 2024 10:18 AM

    Thanks for replying Mauro.  I will give the loop a try

    Regards to the 400 issue.  It is only produced for on one project so I suspect that it is a piece of data but it is confusing as it will 200 in postman and also the Clarity Rest API




  • 4.  RE: Using JSON inside process

    Posted Aug 30, 2024 01:07 PM

    Have you tried logging the response body? It may give you some hints as to what the request is missing




  • 5.  RE: Using JSON inside process

    Posted Sep 12, 2024 12:18 PM

    Hi.  I figured this out eventually.  The content of the JSON was being generated by SQL and I had neglected to add conditions to strip out special characters on a text attribute

    Thanks