1111 <option value =" POST" >POST</option >
1212 </select >
1313 <select id =" api-call-resource" >
14- <option value =" v1/projects" >api/v1/projects</option >
15- <option value =" v1/projects/{id}" >api/v1/projects/{ id } </option >
16- <option value =" v1/defects" >api/v1/defects</option >
17- <option value =" v1/defects/{id}" >api/v1/defects/{ id } </option >
18- <option value =" v1/features" >api/v1/features</option >
19- <option value =" v1/features/{id}" >api/v1/features/{ id } </option >
20- <option value =" v1/incidents" >api/v1/incidents</option >
21- <option value =" v1/incidents/{id}" >api/v1/incidents/{ id } </option >
22- <option value =" v1/tasks" >api/v1/tasks</option >
23- <option value =" v1/tasks/{id}" >api/v1/tasks/{ id } </option >
14+ <optgroup >
15+ <option value =" v1/projects" >api/v1/projects</option >
16+ <option value =" v1/projects/{id}" >api/v1/projects/{ id } </option >
17+ <option value =" v1/releases" >api/v1/releases</option >
18+ <option value =" v1/releases/{id}" >api/v1/releases/{ id } </option >
19+ <option value =" v1/users" >api/v1/users</option >
20+ <option value =" v1/users/{id}" >api/v1/users/{ id } </option >
21+ <option value =" v1/customers" >api/v1/customers</option >
22+ <option value =" v1/customers/{id}" >api/v1/customers/{ id } </option >
23+ <option value =" v1/contacts" >api/v1/contacts</option >
24+ <option value =" v1/contacts/{id}" >api/v1/contacts/{ id } </option >
25+ </optgroup >
26+
27+ <optgroup >
28+ <option value =" v1/defects" >api/v1/defects</option >
29+ <option value =" v1/defects/{id}" >api/v1/defects/{ id } </option >
30+ <option value =" v1/features" >api/v1/features</option >
31+ <option value =" v1/features/{id}" >api/v1/features/{ id } </option >
32+ <option value =" v1/incidents" >api/v1/incidents</option >
33+ <option value =" v1/incidents/{id}" >api/v1/incidents/{ id } </option >
34+ <option value =" v1/tasks" >api/v1/tasks</option >
35+ <option value =" v1/tasks/{id}" >api/v1/tasks/{ id } </option >
36+ </optgroup >
37+
38+ <optgroup >
39+ <option value =" v1/defects/{id}/attachments" >api/v1/defects/{ id } /attachments</option >
40+ <option value =" v1/features/{id}/attachments" >api/v1/features/{ id } /attachments</option >
41+ <option value =" v1/incidents/{id}/attachments" >api/v1/incidents/{ id } /attachments</option >
42+ <option value =" v1/tasks/{id}/attachments" >api/v1/tasks/{ id } /attachments</option >
43+ <option value =" v1/attachments/{id}" >api/v1/attachments/{ id } </option >
44+ </optgroup >
2445 </select >
2546
2647 <span id =" api-call-id-label" >id:</span ><input type =" text" id =" api-call-id" value =" 1" />
3253 </div >
3354 </div >
3455
56+ <div id =' api-call-file-container' >
57+ <input type =" file" id =" api-call-file" />
58+ </div >
59+
3560 <div >
3661 <a href =" #" class =" btn" id =" api-call" >Make the API Call</a >
3762 </div >
3863
3964 <div >
4065 <textarea id =" api-call-results" disabled =" disabled" ></textarea >
4166 </div >
42-
43-
44- <h2 >Example Attachment Upload</h2 >
45- <form action =" @Model.GetUrl(" attachments " )" enctype =" multipart/form-data" method =" post" >
46- <input type =" file" name =" file" class =" input-file" />
47- <input type =" submit" value =" Upload Attachment" class =" btn" />
48- </form >
4967</div >
5068
5169<script type =" text/javascript" >
70+
5271// hide the id input unless it is needed for the selected API call
5372var idInputNode = $ (' #api-call-id' ),
5473 resourceInputNode = $ (' #api-call-resource' );
@@ -64,31 +83,53 @@ toggleIdInputNode();
6483resourceInputNode .change (toggleIdInputNode);
6584
6685// hide the JSON payload input unless it is needed for the selected API call
86+
87+ function postIsAttachmentAdd (){
88+ var resource = resourceInputNode .val ();
89+ return resource .indexOf (' {id}/attachments' ) !== - 1 ;
90+ }
91+
6792var methodInputNode = $ (' #api-call-method' );
6893
6994function togglePayloadInputNode (){
70- // we show the payload input node if the method is POST
71- var showPayloadInputNode = methodInputNode .val () === ' POST' ;
95+ // we show the payload input node if the method is POST, but not for attachment adds
96+ var showPayloadInputNode = methodInputNode .val () === ' POST' && ! postIsAttachmentAdd () ;
7297$ (' #api-call-payload-container' ).toggle (showPayloadInputNode);
98+
99+ // show the file input node if the method is POST, and it is an attachment add
100+ var showFileInputNode = methodInputNode .val () === ' POST' && postIsAttachmentAdd ();
101+ $ (' #api-call-file-container' ).toggle (showFileInputNode);
73102}
74103
75104togglePayloadInputNode ();
76105methodInputNode .change (togglePayloadInputNode);
106+ resourceInputNode .change (togglePayloadInputNode);
77107
78108// show example JSON payloads
79109var payloadInputNode = $ (' #api-call-payload' );
80110
81111var jsonPayloadExamples = {
82- " v1/projects" : ' {\n name : "Project Created from API Explorer"\n }' ,
83- " v1/projects/{id}" : ' {\n name : "Project Renamed from API Explorer"\n }' ,
84- " v1/defects" : ' {\n item:{\n name : "Defect Created from API Explorer",\n project:{id: 1 }\n }\n }' ,
85- " v1/defects/{id}" : ' {\n item:{\n name : "Defect Renamed from API Explorer"\n }\n }' ,
86- " v1/features" : ' {\n item:{\n name : "Feature Created from API Explorer",\n project:{id: 1 }\n }\n }' ,
87- " v1/features/{id}" : ' {\n item:{\n name : "Feature Renamed from API Explorer"\n }\n }' ,
88- " v1/incidents" : ' {\n item:{\n name : "Incident Created from API Explorer",\n project:{id: 1 }\n }\n }' ,
89- " v1/incidents/{id}" : ' {\n item:{\n name : "Incident Renamed from API Explorer"\n }\n }' ,
90- " v1/tasks" : ' {\n item:{\n name : "Task Created from API Explorer",\n project:{id: 1 }\n }\n }' ,
91- " v1/tasks/{id}" : ' {\n item:{\n name : "Task Renamed from API Explorer"\n }\n }'
112+ " v1/projects" : ' {\n name : "Project Created from API Explorer"\n }' ,
113+ " v1/projects/{id}" : ' {\n name : "Project Renamed from API Explorer"\n }' ,
114+ " v1/releases" : ' {\n name : "Release Created from API Explorer",\n release_type:{id : 1 }\n }' ,
115+ " v1/releases/{id}" : ' {\n name : "Release Renamed from API Explorer"\n }' ,
116+ " v1/users" : ' {\n login_id : "ApiExplorer",\n first_name : "API",\n last_name : "Explorer",\n security_roles : [ 1 ]\n }' ,
117+ " v1/users/{id}" : ' {\n first_name : "Renamed"\n }' ,
118+ " v1/customers" : ' {\n company_name : "Customer Created from API Explorer"\n }' ,
119+ " v1/customers/{id}" : ' {\n company_name : "Customer Renamed from API Explorer"\n }' ,
120+ " v1/contacts" : ' {\n first_name : "API",\n last_name : "Explorer",\n customer_id : 1\n }' ,
121+ " v1/contacts/{id}" : ' {\n first_name : "Renamed"\n }' ,
122+
123+ " v1/defects" : ' {\n item:{\n name : "Defect Created from API Explorer",\n project :{id : 1 }\n }\n }' ,
124+ " v1/defects/{id}" : ' {\n item:{\n name : "Defect Renamed from API Explorer"\n }\n }' ,
125+ " v1/features" : ' {\n item:{\n name : "Feature Created from API Explorer",\n project :{id : 1 }\n }\n }' ,
126+ " v1/features/{id}" : ' {\n item:{\n name : "Feature Renamed from API Explorer"\n }\n }' ,
127+ " v1/incidents" : ' {\n item:{\n name : "Incident Created from API Explorer",\n project :{id : 1 }\n }\n }' ,
128+ " v1/incidents/{id}" : ' {\n item:{\n name : "Incident Renamed from API Explorer"\n }\n }' ,
129+ " v1/tasks" : ' {\n item:{\n name : "Task Created from API Explorer",\n project :{id : 1 }\n }\n }' ,
130+ " v1/tasks/{id}" : ' {\n item:{\n name : "Task Renamed from API Explorer"\n }\n }' ,
131+
132+ " v1/attachments/{id}" : ' {\n description : "Description Updated from API Explorer"\n }'
92133};
93134
94135$ (' #api-call-payload-example' ).click (function (event ){
@@ -98,6 +139,28 @@ $('#api-call-payload-example').click(function(event){
98139payloadInputNode .val (jsonPayloadExamples[resource]);
99140});
100141
142+ // when a file is selected, load it in using FileReader
143+ var fileInputNode = $ (' #api-call-file' );
144+ var loadedFile;
145+
146+ fileInputNode .change (function (){
147+ loadedFile = null ;
148+ var file = fileInputNode .get (0 ).files [0 ];
149+
150+ var reader = new FileReader ();
151+ reader .onload = function (fileData ){
152+ loadedFile = {
153+ data: reader .result ,
154+ name: file .name ,
155+ };
156+ };
157+ reader .onerror = function (){
158+ alert (reader .error );
159+ };
160+
161+ reader .readAsBinaryString (file);
162+ });
163+
101164// process API calls
102165
103166function displayCallResults (jqXHR ){
@@ -115,6 +178,9 @@ function displayCallResults(jqXHR){
115178$ (' #api-call' ).click (function (event ){
116179event .preventDefault ();
117180
181+ // clear the results
182+ $ (' #api-call-results' ).val (' ' );
183+
118184// compose the url, substituting the id if needed
119185var url = ' @(Url.Action("Proxy"))?resource=' + resourceInputNode .val ();
120186 url = url .replace (' {id}' , idInputNode .val ());
@@ -134,11 +200,22 @@ $('#api-call').click(function(event){
134200
135201// send the data if POSTing
136202if (method === ' POST' ){
137- settings .contentType = ' application/json' ;
138- settings .data = payloadInputNode .val ();
203+ if (postIsAttachmentAdd ()){
204+ // we can add an attachment by posting a form the contents in the request as an octet-stream,
205+ // and passing the rest of the parameters in the URL
206+ settings .contentType = ' application/octet-stream' ;
207+ settings .data = loadedFile .data ;
208+ url = url + ' &file_name=' + encodeURIComponent (loadedFile .name );
209+ }
210+ else {
211+ // for all other request, we post a json object
212+ settings .contentType = ' application/json' ;
213+ settings .data = payloadInputNode .val ();
214+ }
139215 }
140216
141217// make the call to the Proxy action, which will forward the call to the OnTime API
142218$ .ajax (url, settings);
219+
143220});
144221 </script >
0 commit comments