ThrustCurve API

This page presents an example of using the ThrustCurve API to find motors and download data for them. See the API documentation page for high-level info; this page contains a specific example app.

This demo uses the metadata, search and download API endpoints through JSON directly in the browser. The API also supports XML, but JSON will be more commonly used for web mashups.

You may also like to explore the API through SwaggerHub.

These demos assume JQuery, but any other way of issuing requests will work just fine. Note that the API doesn't require being called from a browser nor does it require any headers to be sent.

1. Get Metadata

We want to create a search form, but need to know how to populate the select inputs. The natural way to get that info is through the metadata API. We'll access this through a GET method since we don't need to provide inputs. Try it out by pressing the "Metadata" button below.

 // use GET to download metadata for all motors
 $.get('', function(data) {
   console.log('metadata response:', data);

   // populate the combo boxes in the search form
   let form = $('form[name=search]');

   let select = form.find('select[name=manufacturer]');
   select.empty().append($('<option selected>(all)</option>'));
   data.manufacturers.forEach(mfr => {
     select.append($(`<option value="${mfr.abbrev}">${}</option>`));

   select = form.find('select[name=diameter]');
   select.empty().append($('<option selected>(all)</option>'));
   data.diameters.forEach(diam => {

   select = form.find('select[name=impulseClass]');
   select.empty().append($('<option selected>(all)</option>'));
   data.impulseClasses.forEach(cls => {

2. Search for Motors

The combo boxes of this form get populated by the code above. Make sure to run it at least once by pressing the "Metadata" button above. Then choose some combination of search criteria and press the "Search" button below.

The execute the search API, we use the POST method supplying the search criteria as a JSON object.

 // pick up criteria from the form above
 let form = $('form[name=search]');
 let req = {};
 ['commonName', 'manufacturer', 'diameter', 'impulseClass'].forEach(prop => {
   let v = form.find(':input[name=' + prop + ']').val();
   if (v != null && v.trim() !== '' && v !== '(all)')
     req[prop] = v;
 console.log('search request:', req);

 // use POST with the criteria as the JSON body
   url: '',
   method: 'POST',
   data: JSON.stringify(req),
   success: function(data) {
     console.log('search response:', data);

     // put key data for each motor into the table
     let motors = $('table.motors tbody');
     function num(v, d) {
       return v > 0 ? v.toFixed(d) : "";
     let summary = data.criteria.length < 1 ? 'no' : data.criteria.length;
     summary += ' search criteria: ';
     if (data.results != null && data.results.length > 0) {
       data.results.forEach(r => {
         let tr = $(`<tr>
                      <td><input type="radio" name="motorId" value="${r.motorId}"></td>
                      <td>${num(r.totImpulseNs, 1)}</td>
                      <td>${num(r.burnTimeS, 2)}</td>
       if (data.results.length == data.matches)
         summary += `all ${data.results.length} matches`;
         summary += `${data.results.length} of ${data.matches} matches`;
     } else {
       summary += 'no matches';
     $('table.motors tfoot td').text(summary);

3. Download Data

This table gets populated by the search form above. Once you've executed a search that matches existing motors, click on one of the radio buttons in the first column to choose that motor and press the "Download" button below.

Pick Manufacturer Designation Diameter Impulse Burn Time Files
(no search yet)

To execute the download API, we use the POST method supplying the motor ID as a JSON object.

 let motorId = $('table.motors input:checked').val();
 if (motorId == null) {
   alert('Pick a motor in the above table (Search first if needed).');
 } else {
   // use POST with the motor ID as the JSON body
   let req = {
     motorId: motorId, // motor to find files for
     data: 'samples',  // we want just the parsed data points
   console.log('download request:', req);
     url: '',
     method: 'POST',
     data: JSON.stringify(req),
     success: function(data) {
       console.log('download response:', data);

       // overall all data files into an line chart
       let title = 'no data files';
       let series = [];
       if (data.results != null && data.results.length > 0) {
         title = data.results.length > 1 ? data.results.length + ' data files' : 'one data file';

         // make a unique name for each file
         let names = [];
         function name(result) {
           let name = result.format + ' ' + result.source;
           if (names.indexOf(name) >= 0) {
             let n = 1, alt;
               alt = name + ' ' + ++n;
             while (names.indexOf(alt) >= 0);
             name = alt;
           return name;

         // build the series data points from the thrust/time values
         data.results.forEach(result => {
           let data = => [s.time, s.thrust]);
           if (data[0][0] > 0.001)
             data.splice(0, 0, [0, 0]);
             type: 'line',
             smooth: true,
             name: name(result),
             showSymbol: true,
             data: data,
         title: {
           text: title,
         tooltip: {
           formatter: params => `time: ${[0]}s, thrust: ${[1]}Ns`,
         legend: {
           right: 10,
           orient: 'vertical',
           align: 'left'
         xAxis: {
           name: 'Time (s)',
         yAxis: {
           name: 'Thrust (Ns)',

The data points from the download files are displayed in this chart.

The interesting parts of the code are displayed in the sections above, but you can always View Source to see the setup code if you like. It's also helpful to open your browser developer tools to see the request and response JSON objects and any errors that occur.