You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
6.1 KiB
Markdown
153 lines
6.1 KiB
Markdown
8 years ago
|
# Data API
|
||
|
|
||
|
rqlite exposes an HTTP API allowing the database to be modified such that the changes are replicated. Queries are also executed using the HTTP API. Modifications go through the Raft log, ensuring only changes committed by a quorum of rqlite nodes are actually executed against the SQLite database. Queries do not __necessarily__ go through the Raft log, however, since they do not change the state of the database, and therefore do not need to be captured in the log. More on this later.
|
||
|
|
||
|
There are also [client libraries available](https://github.com/rqlite).
|
||
|
|
||
|
## Writing Data
|
||
|
To write data successfully to the database, you must create at least 1 table. To do this perform a HTTP POST, with a `CREATE TABLE` SQL command encapsulated in a JSON array, in the body of the request. An example via [curl](http://curl.haxx.se/):
|
||
|
|
||
|
```bash
|
||
|
curl -XPOST 'localhost:4001/db/execute?pretty&timings' -H "Content-Type: application/json" -d '[
|
||
|
"CREATE TABLE foo (id integer not null primary key, name text)"
|
||
|
]'
|
||
|
```
|
||
|
|
||
|
To insert an entry into the database, execute a second SQL command:
|
||
|
|
||
|
```bash
|
||
|
curl -XPOST 'localhost:4001/db/execute?pretty&timings' -H "Content-Type: application/json" -d '[
|
||
|
"INSERT INTO foo(name) VALUES(\"fiona\")"
|
||
|
]'
|
||
|
```
|
||
|
|
||
|
The response is of the form:
|
||
|
|
||
|
```json
|
||
|
{
|
||
|
"results": [
|
||
|
{
|
||
|
"last_insert_id": 1,
|
||
|
"rows_affected": 1,
|
||
|
"time": 0.00886
|
||
|
}
|
||
|
],
|
||
|
"time": 0.0152
|
||
|
}
|
||
|
```
|
||
|
|
||
|
The use of the URL param `pretty` is optional, and results in pretty-printed JSON responses. Time is measured in seconds. If you do not want timings, do not pass `timings` as a URL parameter.
|
||
|
|
||
|
## Querying Data
|
||
|
Querying data is easy. The most important thing to know is that, by default, queries must go through the leader node. More on this later.
|
||
|
|
||
|
For a single query simply perform a HTTP GET, setting the query statement as the query parameter `q`:
|
||
|
|
||
|
```bash
|
||
|
curl -G 'localhost:4001/db/query?pretty&timings' --data-urlencode 'q=SELECT * FROM foo'
|
||
|
```
|
||
|
|
||
|
The response is of the form:
|
||
|
|
||
|
```json
|
||
|
{
|
||
|
"results": [
|
||
|
{
|
||
|
"columns": [
|
||
|
"id",
|
||
|
"name"
|
||
|
],
|
||
|
"types": [
|
||
|
"integer",
|
||
|
"text"
|
||
|
],
|
||
|
"values": [
|
||
|
[
|
||
|
1,
|
||
|
"fiona"
|
||
|
]
|
||
|
],
|
||
|
"time": 0.0150043
|
||
|
}
|
||
|
],
|
||
|
"time": 0.0220043
|
||
|
}
|
||
|
```
|
||
|
|
||
|
### Read Consistency
|
||
7 years ago
|
You can learn all about the read consistency guarantees supported by rqlite [here](https://github.com/rqlite/rqlite/blob/master/DOC/CONSISTENCY.md).
|
||
8 years ago
|
|
||
|
## Transactions
|
||
|
Transactions are supported. To execute statements within a transaction, add `transaction` to the URL. An example of the above operation executed within a transaction is shown below.
|
||
|
|
||
|
```bash
|
||
|
curl -XPOST 'localhost:4001/db/execute?pretty&transaction' -H "Content-Type: application/json" -d "[
|
||
|
\"INSERT INTO foo(name) VALUES('fiona')\",
|
||
|
\"INSERT INTO foo(name) VALUES('sinead')\"
|
||
|
]"
|
||
|
```
|
||
|
|
||
|
When a transaction takes place either both statements will succeed, or neither. Performance is *much, much* better if multiple SQL INSERTs or UPDATEs are executed via a transaction. Note that processing of the request ceases the moment any single query results in an error.
|
||
|
|
||
|
The behaviour of rqlite when using `BEGIN`, `COMMIT`, `ROLLBACK`, `SAVEPOINT`, and `RELEASE` to control transactions is **not defined**. It is important to control transactions only through the query parameters shown above.
|
||
|
|
||
|
## Handling Errors
|
||
7 years ago
|
If an error occurs while processing a statement, it will be marked as such in the response. For example:
|
||
8 years ago
|
|
||
|
```bash
|
||
|
curl -XPOST 'localhost:4001/db/execute?pretty&timings' -H "Content-Type: application/json" -d "[
|
||
|
\"INSERT INTO nonsense\"
|
||
|
]"
|
||
|
```
|
||
|
```json
|
||
|
{
|
||
|
"results": [
|
||
|
{
|
||
|
"error": "near \"nonsense\": syntax error"
|
||
|
}
|
||
|
],
|
||
|
"time": 2.478862
|
||
|
}
|
||
|
```
|
||
7 years ago
|
|
||
|
## Sending requests to followers
|
||
7 years ago
|
What happens when you send a request to a follower depends on the nature of the request.
|
||
|
|
||
|
You must always send write-requests (requests will change the database) to the leader. If you send a write-request to a follower, the follower will respond with [HTTP 301 Moved Permanently](https://en.wikipedia.org/wiki/HTTP_301) and include the address of the leader as the `Location` header in the response.
|
||
|
|
||
7 years ago
|
The situation for queries -- requests which just read data -- is somewhat different. If you send the request to a node that is not the leader of the cluster, and specify `strong` or `weak` as the [read-consistency level](https://github.com/rqlite/rqlite/blob/master/DOC/CONSISTENCY.md), the node will also respond with [HTTP 301 Moved Permanently](https://en.wikipedia.org/wiki/HTTP_301) and include the address of the leader as the `Location` header in the response.
|
||
7 years ago
|
|
||
7 years ago
|
However, if you specify `none` for read-consistency the node will query its local SQLite database. No redirect will be returned.
|
||
7 years ago
|
|
||
|
## Example of redirect on query
|
||
7 years ago
|
```
|
||
|
$ curl -v -G 'localhost:4003/db/query?pretty&timings' --data-urlencode 'q=SELECT * FROM foo'
|
||
|
* Trying ::1...
|
||
|
* connect to ::1 port 4003 failed: Connection refused
|
||
|
* Trying 127.0.0.1...
|
||
|
* Connected to localhost (127.0.0.1) port 4003 (#0)
|
||
|
> GET /db/query?pretty&timings&q=SELECT%20%2A%20FROM%20foo HTTP/1.1
|
||
|
> Host: localhost:4003
|
||
|
> User-Agent: curl/7.43.0
|
||
|
> Accept: */*
|
||
|
>
|
||
|
< HTTP/1.1 301 Moved Permanently
|
||
|
< Content-Type: application/json; charset=utf-8
|
||
7 years ago
|
< Location: http://localhost:4001/db/query?pretty&timings&q=SELECT%20%2A%20FROM%20foo
|
||
7 years ago
|
< X-Rqlite-Version: 4
|
||
7 years ago
|
< Date: Mon, 07 Aug 2017 21:10:59 GMT
|
||
|
< Content-Length: 116
|
||
7 years ago
|
<
|
||
7 years ago
|
<a href="http://localhost:4001/db/query?pretty&timings&q=SELECT%20%2A%20FROM%20foo">Moved Permanently</a>.
|
||
7 years ago
|
|
||
|
* Connection #0 to host localhost left intact
|
||
|
```
|
||
|
It is up the clients to re-issue the command to the leader.
|
||
7 years ago
|
|
||
7 years ago
|
This choice was made, as it provides maximum visibility to the clients. For example, if a follower transparently forwarded a request to the leader, and one of the nodes then crashed during processing, it may be much harder for the client to determine where in the chain of nodes the processing failed.
|
||
7 years ago
|
|
||
8 years ago
|
## Bulk API
|
||
7 years ago
|
You can learn about the bulk API [here](https://github.com/rqlite/rqlite/blob/master/DOC/BULK.md).
|
||
8 years ago
|
|
||
|
|