REST

From Request Tracker Wiki
Revision as of 07:38, 2 September 2010 by Djsmiley (talk)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

REST Interface

Abstract

The REST Interface gives you access to your RT Database. The complete communication is encapsulated in the HTTP protocol.

Interface

The interface should be accessible in your installation. Just enter the following URL: /REST/1.0/. The default response should be:

RT/3.4.5 200 Ok # Invalid object specification: 'index.html' id: index.html

Authentication

The REST Interface does not support HTTP-Authentication. So you must get a valid Session-Token and submit the cookie each request. You usually get a Session-Cookie by submitting the default login form.

Convenience libraries

There are libraries which do much of the low-level work shown in the examples below for you, and provide an easier programming interface for dealing with RT. For perl, there is RT::Client::REST, available on CPAN (perl -MCPAN -e install RT::Client::REST). For ruby, there is the rt-client gem, available on rubyforge (gem install rt-client) http://rt-client.rubyforge.org/ , or Roart, a ruby interface inspired by ActiveRecord, (gem install roart) http://rubygems.org/gems/roart .

Example: perl

To get the results of a single request (without setting the Session-Cookie) -- assuming you've set:

  • $uri to your RT REST URL
  • $access_user to your username
  • $access_password to your password
  • $ticketNumber to the ticket you want to see my $ua = LWP::UserAgent->new; $ua->timeout(10); $ua->agent("YOURUSERAGENTHERE"); my $response = $ua->post( $uri . "ticket/$ticketNumber", [ 'user' => $access_user, 'pass' => $access_password, ], 'Content_Type' => 'form-data' ); if ($response->is_success) { print $response->decoded_content; }

Example: Java

import java.io.IOException;

import org.apache.commons.httpclient.HttpClient;

import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.methods.multipart.StringPart;

public class RtTicketCreator {

static final String BASE_URI = "http://rt.xxx.com/REST/1.0";

public static void main(String[] args) throws IOException {

PostMethod mPost = new PostMethod(BASE_URI + "/ticket/new?user=username&pass=password");

Part[] parts = { new StringPart("content", "Queue: General\nSubject: 123") };

mPost.setRequestEntity(new MultipartRequestEntity(parts, mPost.getParams()));

HttpClient cl = new HttpClient();

cl.executeMethod(mPost);

System.out.println(mPost.getResponseBodyAsString());

}

}

Example: Python

import cookielib import urllib import urllib2 # creates a cookie for the rtserver with the credentials given at initialization. # trying login on rt server cj = cookielib.LWPCookieJar() opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cj)) urllib2.install_opener(opener) data={'user':access_user,'pass':access_password} ldata = urllib.urlencode(data) login = urllib2.Request(uri, ldata) try: response = urllib2.urlopen(login) print response.read() print "login successful" except urllib2.URLError: # could not connect to server print "Not able to login"

Example: ruby

require 'net/http' require 'net/https' http = Net::HTTP.new('tickets.yoursite.com', 443) http.use_ssl = true user = 'rt_user' pass = 'rt_pass' # Log in to RT and get some data login = "user=#{user}&pass=#{pass}" headers = { 'Content-Type' => 'application/x-www-form-urlencoded' } resp, data = http.post('/REST/1.0/ticket/123/show',login,headers) # display what we got puts "HTTP response code: #{resp.code}" puts "HTTP message: #{resp.message}" puts "Response:" resp.each do |key,val| puts "#{key} => #{val}" end puts "Data:" puts data

Example: php

$username = rt_user;

$password = rt_pass;
$url = "http://server.domain.tld/REST/1.0/ticket/<ticket id>/show?user=$username&pass=$password";

$request = new HttpRequest($url, HTTP_METH_GET);

/* if you want's to pass additional parameters */
$request->addQueryData( array() );
$response = $request->send();
print_r($response);

and

$username = rt_user;

$password = rt_pass;
$url = "http://server.domain.tld/REST/1.0/ticket/new?user=$username&pass=$password";

$request = new HttpRequest($url, HTTP_METH_POST);

$post_data=array("content"=>"Queue: General\nRequestor: user@domain\nSubject: REST test 1\nOwner: userX\nAdminCc: userX\nText: This is a REST test\n");
$request->addPostFields( $post_data );

$response = $request->send();

try {

   echo $request->send()->getBody();
} catch (HttpException $ex) {
   echo $ex;
}

Queries

Ticket/show

Gets the data for a single ticket, not including the history and comments.

Request: /REST/1.0/ticket/<ticket-id>/show

RT/3.4.5 200 Ok

id: ticket/<ticket-id>

Queue: <...>
Owner: <...>
Creator: <...>
Subject: <...>
Status: <...>
Priority: <...>
InitialPriority: <...>
FinalPriority: <...>
Requestors: <...>
Cc: <...>
AdminCc: <...>
Created: <...>
Starts: <...>
Started: <...>
Due: <...>
Resolved: <...>
Told: <...>
TimeEstimated: <...>
TimeWorked: <...>
TimeLeft: <...>

Ticket/links/show

Gets the ticket links for a single ticket.

Request: REST/1.0/ticket/<ticket-id>/links/show

RT/3.8.2 200 Ok

id: ticket/<ticket-id>/links

HasMember: fsck.com-rt://your.server.com/ticket/<another-id>
ReferredToBy: fsck.com-rt://your.server.com/ticket/<another-id>
DependedOnBy: fsck.com-rt://your.server.com/ticket/<another-id>
MemberOf: fsck.com-rt://your.server.com/ticket/<another-id>
RefersTo: fsck.com-rt://your.server.com/ticket/<another-id>
DependsOn: fsck.com-rt://your.server.com/ticket/<another-id>

Ticket/attachments

Gets a list of all attachments related to the ticket

Request: /REST/1.0/ticket/<ticket-id>/attachments

RT/3.8.0 200 Ok

id: ticket/<ticket-id>/attachments

Attachments: <attachment-id>: (Unnamed) (text/plain / 312b),

             <attachment-id>: (Unnamed) (multipart/mixed / 0b),
             <attachment-id>: (Unnamed) (text/html / 25b),
             <attachment-id>: <filename1> (application/octet-stream / 442b),
             <attachment-id>: <filename2> (application/octet-stream / 1.7k),
             <attachment-id>: <filename3> (application/octet-stream / 185b),
             <attachment-id>: <filename4> (application/octet-stream / 17.9k),
             ....

Ticket/attachment

Gets the metadata and content of a specific attachment.

Request: /REST/1.0/ticket/<ticket-id>/attachments/<attachment-id>

RT/3.8.0 200 Ok

id: <attachment-id>

Subject:
Creator: <user-id>
Created: <timestamp>
Transaction: <transaction-id>
Parent: <parent-id>
MessageId:
Filename: <filename>
ContentType: application/octet-stream
ContentEncoding: none

Headers: MIME-Version: 1.0

         X-Mailer: MIME-tools 5.427 (Entity 5.427)
         Content-Type: application/octet-stream;
           name="<filename>"
         Content-Disposition: inline; filename="<filename>"
         Content-Transfer-Encoding: base64
         Content-Length: <length in bytes>

Content: ...

         ...
         ...

NOTE: RT returns the content indented with 9 spaces on each line, so that it lines up with the "Content:" header. Even if you strip this out with a regexp, the content is still UTF-8, which is probably not what you want. To get the original binary data back, strip out the 9 spaces with a regexp, strip off the 3 carriage returns at the end, and then convert the whole thing from UTF-8 to the native character encoding of the attachment, whatever that is. RT doesn't tell you, so you have know. If the attachments were uploaded by a U.S. Windows system, odds are that Windows-1252 is what you want. If you can't get the binary back intact, see the next method below....

Ticket/attachment/content

Gets the attachment data content without additional metadata or whitespace characters

Request: /REST/1.0/ticket/<ticket-id>/attachments/<attachment-id>/content

RT/3.8.0 200 Ok

...

...
...

So to get the original content you still have to strip the first 2 lines of the response.

Ticket/history

Gets a list of all the history items for a given ticket.

Request: /REST/1.0/ticket/<ticket-id>/history

RT/3.4.5 200 Ok # <history-count>/<history-count> (/total) <history-id>: <history-name> <history-id>: <history-name> ....

You will get an additional row, for each history entry found. The first entry is usually: "Ticket created by ...".

There are two ways to get history item detail: you can do one of these and then recursively perform ticket/history/id/<history-id> for each history-id from this REST call, but that is extremely wasteful and will scale horribly. What you really want to do is one REST call but get the long format:

Request: /REST/1.0/ticket/<ticket-id>/history?format=l

RT/3.8.2 200 Ok # <n>/<n> (id/<history-id>/total) id: <history-id> Ticket: <ticket-id> TimeTaken: <...> Type: <...> Field: <...> OldValue: <...> NewValue: <...> Data: <...> Description: <...> Content: <...> Creator: <...> Created: <...> Attachments: <attachment-id>: <filename> (<size>) <attachment-id>: <filename> (<size>) -- # <n>/<n> (id/<history-id>/total) ...

NOTE: the double dash "--" will occur in the long format between each history item. You can split the output on "--" and iterate over it, parsing out the data with an RFC822 parser, such as an email handling library.

Ticket/history/id/<history-id>

Gets the history information for a single history item. Note that the history item must actually correspond to the ticket!

Request: /REST/1.0/ticket/<ticket-id>/history/id/<history-id>

RT/3.4.5 200 Ok # 70/70 (id/114856/total) id: <history-id> Ticket: <ticket-id> TimeTaken: <...> Type: <...> Field: <...> OldValue: <...> NewValue: <...> Data: <...> Description: <...> Content: <lin1-0> <line-1> ... <line-n> Creator: <...> Created: <...> Attachments: <...>

IMPORTANT NOTE: At least with RT 3.8.0, when you request a history item with this method AND you have attached a file that has Mime type text/plain to the same item (eg. a comment with an attachement), RT will return the complete content of the attachment for the key "Content:" and not your real comment that you can see in the web frontend. This may lead to some problems if the requestor does not expect to get a comment content that is for example 1.8MBytes of text. With other Mime type attachments this however seems to work. I don't know if this is a feature or a bug.

search/ticket

Request: /REST/1.0/search/ticket?query=<query>&orderby=<sort-order>&format=<format>

Parameters

query

You can use any query generated by the query builder - or feel free to write your own. Here an exanple that will do the following: Find all tickets that have no owner and the status new or open

query= Owner = 'Nobody' AND ( Status = 'new' OR Status = 'open' )

Example: to get all the tickets in "fooQueue" you'd access:

/REST/1.0/search/ticket?query=Queue='fooQueue'

orderby

By this parameter you can change the sort field and order of the search result. To sort a list ascending just put a + before the fieldname, otherwise a -. Eg: -Created (will put the newest tickets at the beginning).

format

  • i: ticket/<ticket-id>
  • s: <ticket-id>: <ticket-subject>
  • l: supposed to be a multi-line format, but this action does not work for me (error)(update by Cris: works for me on 3.8.4)

user/show

Gets the data for a single user.

Request: /REST/1.0/user/<user-id>

RT/3.8.4 200 Ok

id: user/<user-num>

Name: <...>
Password: ********
EmailAddress: <...>
RealName: <...>
Organization: <...>
Privileged: <...>
Disabled: <...>

Edit Tickets

To update an existing ticket: post on /REST/1.0/ticket/<ticket-id>/edit with a variable named "content", containing "key: value" line by line (like the one displayed when issuing ticket/<ticket-id>/show). Example:

Priority: 5

TimeWorked: 15

Edit Ticket Links

To update links on an existing ticket: post on /REST/1.0/ticket/<ticket-id>/links with a variable named "content", containing "key: value" line by line (like the one displayed when issuing ticket/<ticket-id>/links). Example:

DependsOn: 54354

RefersTo: http://some.external/link

Comment on Tickets

To add a comment to an existing ticket: post on /REST/1.0/ticket/<ticket-id>/comment with a variable name content", containing "key: value" line by line:

id: <ticket-id>

Action: comment
Text: the text comment
Attachment: an attachment filename/path

Action can be "comment" or "correspond" For a list of fields you can use in correspondence, try "/opt/rt3/bin/rt correspond ticket/1"

If you used "Attachment", you must add to your POST a variable attachment_1 that contains the raw attachment.

Reply to Tickets

Same as comment...: post on /REST/1.0/ticket/<ticket-id>/comment with a variable name content", containing "key: value" line by line:

id: <ticket-id>

Action: correspond
Text: the text comment
Cc: <...>
Bcc: <...>
TimeWorked: <...>
Attachment: an attachment filename/path

Cc and Bcc are for this reply only (I think)

Create Tickets

To create a new ticket: post on /REST/1.0/ticket/new with a variable named "content", containing "key: value" line by line, example:

id: ticket/new

Queue: <queue name>
Requestor: <requestor email address>
Subject: <subject>
Cc: <...>
AdminCc: <...>
Owner: <...>
Status: <...>
Priority: <...>
InitialPriority: <...>
FinalPriority: <...>
TimeEstimated: <...>
Starts: <...>
Due: <...>
Text: <The ticket content>
cf-CustomFieldName: <Custom field value>