Iterating over a collection in a ZIS flow

In this tutorial, you'll create a ZIS integration that iterates over an array of JSON objects. To do this, you'll include aMap statein the integration's ZIS flow. The Map state runs each item in the array through a sequence of flow states that you specify.

What you'll need

To complete this tutorial, you'll need the following:

Creating the integration

The integration you create listens forTicket Status Changedevents in Zendesk. If the event's current ticket status is "solved", the integration redacts any attachments in the ticket's comments. If the event has another current ticket status, the integration takes no action.

  1. Create an OAuth connection named "zendesk". You'll use the connection to authenticate Zendesk API requests in the integration's ZIS flow.

    In a typical setup, an admin uses a private Zendesk app to create OAuth connections. For this tutorial, you'll create the "zendesk" connection without an app.

    To create the "zendesk" connection, follow the steps inCreating an OAuth connection for Zendesk. Then return here.

  2. Create a JSON file namedmy_zis_bundle.json.

  3. Add the following bundle skeleton tomy_zis_bundle.json:

                   
    {"name":"Example ZIS integration with Map state","description":"Redact attachments when ticket status changes to solved","zis_template_version":"2019-10-14","resources":{"GetComments":{"_placeholder_":"ZIS custom action definition goes here"},"RedactAttachment":{"_placeholder_":"ZIS custom action definition goes here"},"RedactAttachmentsOnSolvedFlow":{"_placeholder_":"ZIS flow goes here"},"RedactAttachmentsOnSolvedJobSpec":{"_placeholder_":“子工作规范”}}}

    You'll define the custom actions, ZIS flow, and job spec in the next steps.

  4. Inmy_zis_bundle.json, replace theGetCommentsplaceholder with the following custom action definition.

                   
    "GetComments":{"type":"ZIS::Action::Http","properties":{"name":"GetComments","definition":{"method":"GET","path.$":"/api/v2/tickets/{{$.ticket_id}}/comments.json","connectionName":"zendesk","headers":[{"key":"Content-Type","value":"application/json"}]}}},

    When called, the custom action makes a request to the Zendesk Support API'sList Commentsendpoint. The request requires a Zendesk ticket id. The request's response contains data for the ticket's comments, including any attachments.

  5. Replace theRedactAttachmentplaceholder with the following custom action definition.

                   
    "RedactAttachment":{"type":"ZIS::Action::Http","properties":{"name":"RedactAttachment","definition":{"method":"PUT","path.$":"/api/v2/tickets/{{$.ticket_id}}/comments/{{$.comment_id}}/attachments/{{$.attachment_id}}/redact","connectionName":"zendesk","headers":[{"key":"Content-Type","value":"application/json"}]}}},

    When called, the custom action makes a request to the Zendesk Support API'sRedact Comment Attachmentendpoint. The request removes an attachment from a ticket comment. It replaces the attachment with an empty "redacted.txt" file.

  6. Replace theRedactAttachmentsOnSolvedFlowplaceholder with the following ZIS flow definition. In the definition, replace "INTEGRATION" with your integration key.

    The flow contains a Map state, which is highlighted.

                   
    "RedactAttachmentsOnSolvedFlow":{"type":"ZIS::Flow","properties":{"name":"RedactAttachmentsOnSolvedFlow","definition":{"StartAt":"CheckStatus","States":{"CheckStatus":{"Type":"Choice","Choices":[{"Variable":"$.input.ticket_event.current","StringEquals":"solved","Next":"GetComments"}],"Default":"Finish"},"GetComments":{"Type":"Action","ActionName":“子:集成:行动:GetComments”,"Parameters":{"ticket_id.$":"$.input.ticket_event.ticket.id"},"ResultPath":"$.input.ticket_comments","Next":"SanitizeTicketComments"},"SanitizeTicketComments":{"Type":"Action","ActionName":"zis:common:transform:Jq","Parameters":{"expr":"[.comments[] | (.attachments[] | (.id? // (.[] | .id))) as $id | {\"attachment_id\": \"\\($id)\", \"comment_id\": \"\\(.id)\"}]","data.$":"$.input.ticket_comments"},"ResultPath":"$.input.ticket_comments","Next":"IncludeTicketId"},"IncludeTicketId":{"Type":"Action","ActionName":"zis:common:transform:Jq","Parameters":{"expr.$":"[.ticket_comments[] | (.ticket_id={{$.input.ticket_event.ticket.id}})]","data.$":"$.input"},"ResultPath":"$.input.ticket_comments","Next":"RedactAttachment"},"RedactAttachment":{"Type":"Map","ItemsPath":"$.input.ticket_comments","ResultPath":"$.redact_attachment_output","Iterator":{"StartAt":"Redact","States":{"Redact":{"Type":"Action","ActionName":"zis:INTEGRATION:action:RedactAttachment","Parameters":{"attachment_id.$":"$.attachment_id","comment_id.$":"$.comment_id","ticket_id.$":"$.ticket_id"},"Next":"Done"},"Done":{"Type":"Succeed"}}},"Next":"Finish"},"Finish":{"Type":"Succeed"}}}}},

    A Map state requires an array of JSON objects as input. The state can only access data in this input array. Before the Map state, the flow checks whether the event's current ticket status is "solved". If so, the flow gets data for the ticket's comments. The flow then usesTransformactions to change the comment data into an array of JSON objects with the following structure:

                   
    [{"attachment_id":1234567890123,"comment_id":123456,"ticket_id":1},{"attachment_id":4567890123456,"comment_id":789012,"ticket_id":1}]

    Each object in the array represents an attachment in the ticket's comments. If a comment doesn't contain an attachment, the flow omits the comment from the array.

    The flow's Map state runs each object in the array through an Action state. The Action state uses theRedactAttachmentcustom action to redact the object's attachment.

  7. Replace theRedactAttachmentsOnSolvedJobSpecplaceholder with the following job spec definition. In the definition, replace "INTEGRATION" with your integration key.

                   
    "RedactAttachmentsOnSolvedJobSpec":{"type":"ZIS::JobSpec","properties":{"name":"RedactAttachmentsOnSolvedJobSpec",“event_source”:"support","event_type":"ticket.StatusChanged","flow_name":"zis:INTEGRATION:flow:RedactAttachmentsOnSolvedFlow"}}

    The job spec tells ZIS to run the ZIS flow when it detects a Ticket Status Changed event.

  8. Savemy_zis_bundle.json. The file should now look like this:

                   
    {"name":"Example ZIS integration with Map state","description":"Redact attachments when ticket status changes to solved","zis_template_version":"2019-10-14","resources":{"GetComments":{"type":"ZIS::Action::Http","properties":{"name":"GetComments","definition":{"method":"GET","path.$":"/api/v2/tickets/{{$.ticket_id}}/comments.json","connectionName":"zendesk","headers":[{"key":"Content-Type","value":"application/json"}]}}},"RedactAttachment":{"type":"ZIS::Action::Http","properties":{"name":"RedactAttachment","definition":{"method":"PUT","path.$":"/api/v2/tickets/{{$.ticket_id}}/comments/{{$.comment_id}}/attachments/{{$.attachment_id}}/redact","connectionName":"zendesk","headers":[{"key":"Content-Type","value":"application/json"}]}}},"RedactAttachmentsOnSolvedFlow":{"type":"ZIS::Flow","properties":{"name":"RedactAttachmentsOnSolvedFlow","definition":{"StartAt":"CheckStatus","States":{"CheckStatus":{"Type":"Choice","Choices":[{"Variable":"$.input.ticket_event.current","StringEquals":"solved","Next":"GetComments"}],"Default":"Finish"},"GetComments":{"Type":"Action","ActionName":“子:集成:行动:GetComments”,"Parameters":{"ticket_id.$":"$.input.ticket_event.ticket.id"},"ResultPath":"$.input.ticket_comments","Next":"SanitizeTicketComments"},"SanitizeTicketComments":{"Type":"Action","ActionName":"zis:common:transform:Jq","Parameters":{"expr":"[.comments[] | (.attachments[] | (.id? // (.[] | .id))) as $id | {\"attachment_id\": \"\\($id)\", \"comment_id\": \"\\(.id)\"}]","data.$":"$.input.ticket_comments"},"ResultPath":"$.input.ticket_comments","Next":"IncludeTicketId"},"IncludeTicketId":{"Type":"Action","ActionName":"zis:common:transform:Jq","Parameters":{"expr.$":"[.ticket_comments[] | (.ticket_id={{$.input.ticket_event.ticket.id}})]","data.$":"$.input"},"ResultPath":"$.input.ticket_comments","Next":"RedactAttachment"},"RedactAttachment":{"Type":"Map","ItemsPath":"$.input.ticket_comments","ResultPath":"$.redact_attachment_output","Iterator":{"StartAt":"Redact","States":{"Redact":{"Type":"Action","ActionName":"zis:INTEGRATION:action:RedactAttachment","Parameters":{"attachment_id.$":"$.attachment_id","comment_id.$":"$.comment_id","ticket_id.$":"$.ticket_id"},"Next":"Done"},"Done":{"Type":"Succeed"}}},"Next":"Finish"},"Finish":{"Type":"Succeed"}}}}},"RedactAttachmentsOnSolvedJobSpec":{"type":"ZIS::JobSpec","properties":{"name":"RedactAttachmentsOnSolvedJobSpec",“event_source”:"support","event_type":"ticket.StatusChanged","flow_name":"zis:INTEGRATION:flow:RedactAttachmentsOnSolvedFlow"}}}}
  9. Upload the bundle to ZIS.

                   
    curl -X POST https://{subdomain}.zendesk.com/api/services/zis/registry/{integration}/bundles \-u {email}:{password} \-H "Content-Type: application/json" \-d @my_zis_bundle.json
  10. Install the job spec to enable the integration.

                   
    curl -X POST "https://{subdomain}.zendesk.com/api/services/zis/registry/job_specs/install?job_spec_name=zis:{integration}:job_spec:RedactAttachmentsOnSolvedJobSpec" \-u {email}:{password}

Testing the integration

To test the integration, create an open ticket with an attachment. Then verify the integration redacts the attachment when you change the ticket's status to "solved".

  1. Right-click the following image link and save it to your computer ascamera-pieces.png:

    [camera-pieces.png]

  2. In your shell, navigate to the folder where you saved the image. For example:

                   
    $ cd ~/Downloads
  3. Use the following request to upload the image as an attachment.

                   
    curl -X POST https://{subdomain}.zendesk.com/api/v2/uploads?filename=camera-pieces.png \-u {email}:{password} \-H "Content-Type: application/binary" \--data-binary @camera-pieces.png

    Save theupload.tokenvalue from the response. You'll use the token in the next step.

                   
    {"upload":{"token":"abcxyz","expires_at":"2099-05-06T00:00:00Z",...}}
  4. Use the following request to create an open ticket with the attachment. Replace "TOKEN" with the token you saved in the previous step.

                   
    curl -X POST https://{subdomain}.zendesk.com/api/v2/tickets \-u {email}:{password} \-H "Content-Type: application/json" \-d '{"ticket": {"subject": "My homemade camera fell apart!","status": "open","comment": {"body": "See attached.","uploads": ["TOKEN"]}}}'

    Save theticket.idvalue from the response. You'll use the id in the following steps.

                   
    {"ticket":{"url":"https://SUBDOMAIN.zendesk.com/api/v2/tickets/30.json","id":34,"external_id":null,...},...}
  5. Use the following request to fetch comments for the ticket you created. Replace "{ticket_id}" with the id you saved in the previous step.

                   
    curl -X GET https://{subdomain}.zendesk.com/api/v2/tickets/{ticket_id}/comments.json \-u {email}:{password}

    The response should contain an object in thecomments.attachmentsproperty. The object'sfile_nameproperty should contain the "camera-pieces.png" string.

                   
    {"comments":[{"id":4567890123456,..."attachments":[{"url":"https://SUBDOMAIN.zendesk.com/api/v2/attachments/1234567890123.json","id":1234567890123,“file_name”:"camera-pieces.png",...}],...}],...}

    You also can verify the attachment in the Zendesk Support agent interface.

  6. Use the following request to change the ticket's status to "solved." Replace "{ticket_id}" with the id you saved in step 4.

                   
    curl - x将https://{再分omain}.zendesk.com/api/v2/tickets/{ticket_id}.json \-u {email}:{password} \-H "Content-Type: application/json" \-d '{"ticket": {"status": "solved","comment": {"body": "Thanks for choosing Acme Co.","public": true}}}'
  7. Fetch the ticket's comments again. Replace "{ticket_id}" with the id you saved in step 4.

                   
    curl -X GET https://{subdomain}.zendesk.com/api/v2/tickets/{ticket_id}.json \-u {email}:{password}

    Thefile_nameproperty should now contain "redacted.txt".

                   
    {"comments":[{"id":4567890123456,..."attachments":[{"url":"https://SUBDOMAIN.zendesk.com/api/v2/attachments/1234567890123.json","id":1234567890123,“file_name”:"redacted.txt",...}],...}],...}

    You also can verify the redaction in the Zendesk Support agent interface.

Congratulations! You've created a ZIS integration that uses a Map state to iterate through a collection. For another example of a ZIS integration, see theZendesk app as an admin interfacetutorial series.