This page describes how you can implement a data source to feed data to visualizations built on the Google Visualization API. The data that is served by a data source can be extracted from various resources, such as a file or database. The only restriction is that the extracted data can be placed in a two dimensional table with typed columns.
This page is intended primarily for developers who will be creating their own data source without the aid of the Google Visualization Data Source Library. If you are using that or any other helper libraries, read your library's documentation first.
This page is also intended for readers interested in understanding the wire protocol used for communication between a client visualization and a data source.
If you are creating or using a visualization, you do not need to read this page.
In order to read this document, you should understand basic JSON and HTTP request syntax. You should also have read the Using Visualizations and Creating Visualizations topics of the documentation, to understand how the client works.
A visualization data source is a web service that provides data to visualizations built on the Google Visualization API. This page describes the two essential aspects you'll need to know, in order to reply to a request for data:
How it works:
Note: All parameters and string constant values
listed in this document for requests and responses (such as
responseHandler and "ok") are lowercase, and case-sensitive.
When designing your data source, you'll need to consider how secure your data must be. You can use a variety of security schemes for your site, from simple password access to secure cookie authentication.
XSRF (cross-site request forgery) attacks are a risk with visualizations. A user might navigate to a page that holds a malicious script that then starts trying to make queries to various well-known sites, using the credentials of the current user. If the user has not logged out of a site, the script will be authenticated as the current user and have permissions on that site. One possible mitigation for this attack is to provide a non-obvious URL for your data source, especially one that is customized by user. Another is to require the user to manually re-authenticate for each request (although that can be annoying to the user if the visualization makes frequent requests). This is a problem only with sensitive data.
As an additional level of security, you might consider restricting requests to those coming from the same domain as your data source. This will considerably restrict the visibility of your data source, but if you have very sensitive data that should not be accessed from outside your domain, you should consider it. A data source that only allows requests from the same domain is called a restricted data source, as opposed to an unrestricted data source, which will accept queries from any domain. Here are some details on how to implement a restricted data source:
To ensure that a request is truly coming from within your domain, and not from an outside domain (or a browser inside the domain that's under XSRF attack):
A client sends an HTTP GET request with several parameters, including custom elements, an optional query string, signature, and other elements. You are only responsible for parsing out the parameters described in this section, and should be careful not to handle others to avoid malicious attacks.
Be sure to have default values for optional parameters (both standard and custom), and document all your defaults in your site documentation.
Here are a few sample requests (you can see more request and response samples at the end of this document in Examples):
Note: The following request strings, and those shown in the Examples section, should be url-escaped before sending.
Basic request, no parameters: http://www.example.com/mydatasource Request with the tqx parameter that contains two properties: http://www.example.com/mydatasource?tqx=reqId:0;sig:4641982796834063168 Request with a query string: http://www.example.com/mydatasource?tq=limit 1
Here are the list of all standard parameters in the request string. Note that both parameter names (such as "version") and constant string values (such as "ok", "warning", and "not_modified") are case-sensitive. The table also describes whether the parameter is required to be sent and, if sent, whether you are required to handle it.
| Parameter | Required in Request? |
Data Source Must Handle? |
Description |
|---|---|---|---|
| tq | No |
No |
A query written in Google Visualization API query language, specifying how to filter, sort, or otherwise manipulate the returned data. The string does not need to be quoted. Example: |
| tqx | No |
Yes |
A set of colon-delimited key/value pairs for standard or custom parameters. Pairs are separated by semicolons. Here is a list of the standard parameters defined by the Visualization protocol:
Example: |
| tqrt | No |
No |
Reserved: ignore this parameter. The method that was used to send the query. |
The format of the response depends on the request's out parameter,
which specifies the type of response expected. See the following sections to learn
how to respond to each request type:
DataTable constructor to populate it. This is by far the most
common request type, and the most important to implement properly.You can use the Google Visualization Data Source Library (java) or the visualization python library to generate these output formats for you.
The default response format is JSON if the request includes an "X-DataSource-Auth" header, and JSONP otherwise. Note that the Google Visualization client actually supports a modified version of JSON and JSONP; if you are using the Java or Python helper libraries, they will put out the proper code for you; if you are parsing responses by hand, see JSON Modifications below.
If you are enforcing same-domain requests, you should verify the presence of the "X-DataSource-Auth" header in the request and use authorization cookies.
This is the only response format specified by the Google Visualization API method google.visualization.Query.send().
You can see some example JSON requests and responses at the end of this page in Examples.
You can use the Java or Python helper libraries to
create this response string for you.
This response format is a UTF-8 encoded JSON
object (an object wrapped by by braces { } with each property separated by a comma)
that includes the properties in the table below (the data
is assigned to the table property). This JSON object should be wrapped
inside the responseHandler parameter
value from the request. So, if the request's responseHandler value
was
"myHandler", you should return a string like this (only one property
shown for brevity):
"myHandler({status:ok, ...})"
If the request did not include a responseHandler value, the default
value is "google.visualization.Query.setResponse", so you should return
a string like this (only one property shown for brevity):
"google.visualization.Query.setResponse({status:ok, ...})"
Here are the available response object members:
| Property | Required? |
Description |
|---|---|---|
| version | No |
A string number giving the Google Visualization wire protocol version number. If not specified, the client assumes the latest version. Example: |
| reqId | Yes* |
A string number indicating the ID of this request for this client. If this
was in the request, return the same value. See the
reqId description in the request section for
more details. * If this parameter was not specified in the request, you don't have to set it in the response. |
| status | Yes |
A string describing the success or failure of this operation. Must be one and only one of the following values:
Example: |
| warnings | Only if status=warning |
An array of one or more objects, each describing a non-fatal problem.
Required if
Example: |
| errors | Required if status=error |
An array of one or more objects, each describing an error. Required if The array has the following string members (return only one value for each member):
Example: |
| sig | No |
A hashed value of the table object. Useful for optimizing data transfer between the client and the data source. You can choose any hash algorithm you want. If you support this property, you should return the value passed in by the client if no data is returned, or return a new hash if new data is returned. Example: |
| table | No |
A {cols:[{id:'Col1',label:'',type:'number'}],
rows:[{c:[{v:1.0,f:'1'}]},
{c:[{v:2.0,f:'2'}]},
{c:[{v:3.0,f:'3'}]},
{c:[{v:1.0,f:'1'}]}
]
}
The Example: See Examples below. |
Google's helper libraries, and all queries sent to Google, return a slightly non-standard version of JSON/JSONP. If you are not parsing the returned code yourself, this should not matter to you. The Visualization API client supports both standard and the modified versions of JSON. Here is a summary of the differences:
Date(year,
month, day[,hour, minute, second[, millisecond]]) where everything after
day is optional, and months are zero-based.
If a client makes two requests, and the data has not changed between requests, it makes sense not to resend the data--doing so would waste bandwidth. To make requests more efficient, the protocol supports caching the data on the client, and sending a signal in the response if the data has not changed since the last request. Here's how this works:
DataTable as well as a hash of the DataTable object,
and returns both in its response (the hash is returned in the tqx.sig parameter).
The Google Visualization API client caches the DataTable and sig value.tqx.sig value.DataTable and new sig value hash.status=warning, reason=not_modified, sig=old_sig_value. DataTable by calling QueryResponse.getDataTable().
If the data is the same, it will simply be the cached version of the table.Note that this only works for JSON requests from visualizations built on the Google Visualization API.
If the request specifies out:csv, the response includes no metadata,
but simply a CSV representation of the data. A CSV table is typically
a comma-separated list, where each row of data is a comma-separated list of values,
ending in a UNIX newline character (\n). The cell values should have the same type
for each column. The first row is the column labels. Here's an example of a three-row,
three-column table:
A, B, C 1.0, "yes", true 2.0, "no", false 3.0, "maybe", true
The CSV format is not specified by this protocol; the data source is responsible for defining its CSV format. However, a common format is a set of values separated by commas (with no intervening spaces), and a newline (\n) at the end of every row. When a browser receives a CSV string reply, it might ask the user what application to use to open the string, or might simply render it on the screen.
If the request
includes an outFileName member of the tqx parameter,
you should try to include the specified file name in the response headers.
You cannot send a query for a CSV response using the google.visualization.Query object.
You must make a query for a CSV response using custom code, or by typing a URL
similar to this one in your browser:
Request
http://www.example.com/mydatasource?tqx=reqId:1;out:csv
Response
Label 1,Label2\n1,a\n2,b\n3,c\n4,d
If the request specifies out:tsv-excel, the response includes no
metadata, but simply a tab-separated representation of the data, utf-16
encoded. If the request
includes an outFileName member of the tqx parameter,
you should try to include the specified file name in the response headers.
If the request specifies out:html, the response should be an HTML
page defining an HTML table with the data. This is
useful for debugging your code, because the browser can render your result in a
readable format directly. You cannot
send a query for an HTML response using the google.visualization.Query object.
You must make a query for an HTML response using custom code, or by typing a URL
similar to this one in your browser:
Request
http://www.example.com/mydatasource?tqx=reqId:1;out:html
Response
<html><body><table border='1' cellpadding='2' cellspacing='0'><tr style='font-weight: bold; background-color: #aaa;'><td>label 1</td><td>label 2</td></tr><tr bgcolor='#f0f0f0'><td align='right'>1</td><td>a</td></tr><tr bgcolor='#ffffff'><td align='right'>2</td><td>b</td></tr><tr bgcolor='#f0f0f0'><td align='right'>3</td><td>c</td></tr><tr bgcolor='#ffffff'><td align='right'>4</td><td>d</td></tr></table></body></html>
Here are some example requests and responses. Note that
requests have not been url-escaped; that is typically done by either the browser,
or the google.visualization.Query object.
Simple request: Returns the basic information with a three column, four row table.
Request:
http://www.example.com/mydatasource
Response
google.visualization.Query.setResponse({version:'0.6',reqId:'0',status:'ok',sig:'5982206968295329967',table:{cols:[{id:'Col1',label:'',type:'number'},{id:'Col2',label:'',type:'number'},{id:'Col3',label:'',type:'number'}],rows:[{c:[{v:1.0,f:'1'},{v:2.0,f:'2'},{v:3.0,f:'3'}]},{c:[{v:2.0,f:'2'},{v:3.0,f:'3'},{v:4.0,f:'4'}]},{c:[{v:3.0,f:'3'},{v:4.0,f:'4'},{v:5.0,f:'5'}]},{c:[{v:1.0,f:'1'},{v:2.0,f:'2'},{v:3.0,f:'3'}]}]}});
Simple request with a response handler: Returns a three column, three row table with different data types.
Request:
http://www.example.com/mydatasource?tqx=responseHandler:myHandlerFunction
Response
myHandlerFunction({version:'0.6',reqId:'0',status:'ok',sig:'4641982796834063168',table:{cols:[{id:'A',label:'NEW A',type:'string'},{id:'B',label:'B-label',type:'number'},{id:'C',label:'C-label',type:'datetime'}],rows:[{c:[{v:'a'},{v:1.0,f:'1'},{v:new Date(2008,1,28,0,31,26),f:'2/28/08 12:31 AM'}]},{c:[{v:'b'},{v:2.0,f:'2'},{v:new Date(2008,2,30,0,31,26),f:'3/30/08 12:31 AM'}]},{c:[{v:'c'},{v:3.0,f:'3'},{v:new Date(2008,3,30,0,31,26),f:'4/30/08 12:31 AM'}]}]}});
Query with a simple query string: Request for a single column, returns a single column with four rows.
Request:
http://www.example.com/mydatasource?tq=select Col1
Response:
google.visualization.Query.setResponse({version:'0.6',reqId:'0',status:'ok',sig:'6099996038638149313',table:{cols:[{id:'Col1',label:'',type:'number'}],rows:[{c:[{v:1.0,f:'1'}]},{c:[{v:2.0,f:'2'}]},{c:[{v:3.0,f:'3'}]},{c:[{v:1.0,f:'1'}]}]}});
Data not modified error: Example of a not_modified error.
Request:
http://www.example.com/mydatasource?tqx=reqId:0;sig:4641982796834063168
Response:
google.visualization.Query.setResponse({version:'0.6',reqId:'0',status:'error',errors:[{reason:'not_modified',message:'Data not modified'}]});
Data truncated warning: Example of a data_truncated warning.
Notice that the request still returns data.
Request:
http://www.example.com/mydatasource?tq=limit 1
Response:
google.visualization.Query.setResponse({version:'0.6',reqId:'0',status:'warning',warnings:[{reason:'data_truncated',message:'Retrieved data was truncated'}],sig:'1928724788649668508',table:{cols:[{id:'A',label:'NEW A',type:'string'},{id:'B',label:'B-label',type:'number'},{id:'C',label:'C-label',type:'datetime'}],rows:[{c:[{v:'a'},{v:1.0,f:'1'},{v:new Date(2008,1,28,0,31,26),f:'2/28/08 12:31 AM'}]}]}});
Access denied error: Example of an access_denied error.
Request:
http://www.example.com/mydatasource
Response:
google.visualization.Query.setResponse({version:'0.6',reqId:'0',status:'error',errors:[{reason:'access_denied',message:'Access denied',detailed_message:'Access Denied'}]});
Invalid query string: Example of a request with an invalid query string. Note that the detailed message is a generic message, rather than the actual error message.
Request:
http://www.example.com/mydatasource?tq=select A
Response:
google.visualization.Query.setResponse({version:'0.6',reqId:'0',status:'error',errors:[{reason:'invalid_query',message:'Invalid query',detailed_message:'Bad query string.'}]});