Skip to content

Commit 17e7edf

Browse files
committed
Updated README
1 parent 0be3439 commit 17e7edf

File tree

4 files changed

+187
-11
lines changed

4 files changed

+187
-11
lines changed

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ go 1.17
44

55
require (
66
github.com/djthorpe/go-errors v1.0.2
7-
github.com/djthorpe/go-marshaler v0.0.14
8-
github.com/djthorpe/go-server v1.0.8
7+
github.com/djthorpe/go-marshaler v0.0.15
8+
github.com/djthorpe/go-server v1.0.10
99
github.com/hashicorp/go-multierror v1.1.1
1010
github.com/mattn/go-sqlite3 v1.14.8
1111
github.com/rjeczalik/notify v0.9.2

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
66
github.com/djthorpe/go-errors v1.0.2 h1:kZuNLhb6Yo1iNHaenGa9s5CpRbOG6KxbUtrME4LrAkk=
77
github.com/djthorpe/go-errors v1.0.2/go.mod h1:HtfrZnMd6HsX75Mtbv9Qcnn0BqOrrFArvCaj3RMnZhY=
88
github.com/djthorpe/go-marshaler v0.0.4/go.mod h1:xCXhTzj52UL3YStRsqUSfrKses7ofmfTXYQfVedn8Lw=
9-
github.com/djthorpe/go-marshaler v0.0.14 h1:L3qHWvEgqPGZI8ZQr4qAxOpKfSKAaF6EUPcGyWulIcQ=
10-
github.com/djthorpe/go-marshaler v0.0.14/go.mod h1:xCXhTzj52UL3YStRsqUSfrKses7ofmfTXYQfVedn8Lw=
11-
github.com/djthorpe/go-server v1.0.8 h1:Ml1SkYPiDmMVpSDMmVNjSMLFW7MLttZwkOnJYC5NgA4=
12-
github.com/djthorpe/go-server v1.0.8/go.mod h1:FShgU8xZdpIiNDhBD/SGytAEW1t3O4+eJdcBRU1vQwQ=
9+
github.com/djthorpe/go-marshaler v0.0.15 h1:ZXq5YHCsbREbbYJtc0ie9hz7HJ7vIeeDlMbe7cGh0C0=
10+
github.com/djthorpe/go-marshaler v0.0.15/go.mod h1:xCXhTzj52UL3YStRsqUSfrKses7ofmfTXYQfVedn8Lw=
11+
github.com/djthorpe/go-server v1.0.10 h1:9XSNwkP7Y7GnSWKmJgoKhB+47G+YkYoYAtGJrSgsy6E=
12+
github.com/djthorpe/go-server v1.0.10/go.mod h1:UiBRW6dbmRCVDUfzT5IZ0CCdnGChL3RpTTLjcmPICWI=
1313
github.com/djthorpe/go-sqlite v1.0.28/go.mod h1:TiGX+dIFea54xxIBVmFemTI/8KUjVUlEoDN2A5HKaMs=
1414
github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
1515
github.com/go-ldap/ldap/v3 v3.4.1/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=

plugin/sqlite3/README.md

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,117 @@
1-
# sqlite3 REST API
1+
# sqlite3 API plugin
22

3-
TODO
3+
The API plugin provides an interface into the database through HTTP calls. It is a plugin to
4+
the monolithic server [`github.com/djthorpe/go-server`](github.com/djthorpe/go-server)
5+
and as such the server needs to be installed in addition to the plugin. Instructions on how
6+
to install the server and necessary plugins is described below.
47

58
This package is part of a wider project, `github.com/djthorpe/go-sqlite`.
69
Please see the [module documentation](https://github.com/djthorpe/go-sqlite/blob/master/README.md)
710
for more information.
811

12+
## Running the API backend
13+
14+
The simplest way to install the backend is to run the following commands:
15+
16+
```bash
17+
[bash] git clone github.com/djthorpe/go-sqlite.git
18+
[bash] cd go-sqlite
19+
[bash] make server plugins
20+
```
21+
22+
This will put the following binaries in the `build` directory:
23+
24+
* `server` is the basic monolith server binary;
25+
* `httpserver.plugin` is the HTTP server plugin;
26+
* `log.plugin` provides logging for HTTP requests;
27+
* `static.plugin` provides static file serving. This is not necessary for the
28+
backend, but can be used to serve a frontend (see [here](../../npm/sqlite3) for more
29+
information on the frontend).
30+
31+
To run the server, there is an example configuration file in the `etc` folder:
32+
33+
```bash
34+
[bash] ./build/server etc/server.yaml
35+
```
36+
37+
On Macintosh, you may need to use the `DYLD_LIBRARY_PATH` environment variable to
38+
locate the correct sqlite3 library. For example,
39+
40+
```bash
41+
[bash] brew install sqlite3
42+
[bash] DYLD_LIBRARY_PATH="/usr/local/opt/sqlite/lib" \
43+
./build/server etc/server.yaml
44+
```
45+
46+
You can override the port by passing the `-addr` flag:
47+
48+
```bash
49+
[bash] ./build/server -addr :9001 etc/server.yaml
50+
```
51+
52+
Press CTRL+C to stop the server.
53+
54+
## REST API calls
55+
56+
Requests can generally be `application/json` or `application/x-www-form-urlencoded`, which
57+
needs to be indicated in the `Content-Type` header. Responses are always in `application/json`.
58+
59+
| Endpoint Path | Method | Name | Description |
60+
|--------------------|-----------|----------|-------------|
61+
| / | GET | Ping | Return version, schema, connection pool and module information
62+
| /`schema` | GET | Schema | Return information about a schema: tables, indexes, tiggers and views
63+
| /`schema`/`table` | GET | Table | Return rows of the table or view
64+
| /-/q | POST | Query | Execute a query
65+
| /-/tokenizer | POST | Tokenize | Tokenize a query for syntax colouring
66+
67+
## Error Responses
68+
69+
Errors are returned when the status code is not `200 OK`. A typical error response will look like this:
70+
71+
```json
72+
{
73+
"reason" : "1 error occurred:\n\t* SQL logic error\n\n",
74+
"code" : 400
75+
}
76+
```
77+
78+
79+
## Ping Request and Response
80+
81+
There are no query arguments for this call. Typically a response will look like this:
82+
83+
```json
84+
{
85+
"version": "3.36.0",
86+
"modules": [
87+
"json_tree",
88+
"json_each",
89+
"fts3",
90+
"fts4",
91+
"fts3tokenize",
92+
"fts5vocab",
93+
"fts5",
94+
"rtree",
95+
"rtree_i32",
96+
"fts4aux",
97+
"geopoly"
98+
],
99+
"schemas": [
100+
"main",
101+
"test"
102+
],
103+
"pool": {
104+
"cur": 1,
105+
"max": 50
106+
}
107+
}
108+
```
109+
110+
## Schema Request and Response
111+
112+
There are no query arguments for this call. Typically a response will provide you with information
113+
in the schemas. For example, a typical response may look like this:
114+
115+
TODO
116+
117+
## Table Request and Response

plugin/sqlite3/handlers.go

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ type SqlRequest struct {
7676
}
7777

7878
type SqlResultResponse struct {
79+
Schema string `json:"schema,omitempty"`
80+
Table string `json:"table,omitempty"`
7981
Sql string `json:"sql"`
8082
LastInsertId int64 `json:"last_insert_id,omitempty"`
8183
RowsAffected int `json:"rows_affected,omitempty"`
@@ -93,6 +95,7 @@ type TokenizerResponse struct {
9395
var (
9496
reRoutePing = regexp.MustCompile(`^/?$`)
9597
reRouteSchema = regexp.MustCompile(`^/([a-zA-Z][a-zA-Z0-9_-]+)/?$`)
98+
reRouteTable = regexp.MustCompile(`^/([a-zA-Z][a-zA-Z0-9_-]+)/([^/]+)/?$`)
9699
reRouteTokenizer = regexp.MustCompile(`^/-/tokenize/?$`)
97100
reRouteQuery = regexp.MustCompile(`^/-/q/?$`)
98101
)
@@ -118,6 +121,11 @@ func (p *plugin) AddHandlers(ctx context.Context, provider Provider) error {
118121
return err
119122
}
120123

124+
// Add handler for table
125+
if err := provider.AddHandlerFuncEx(ctx, reRouteTable, p.ServeTable); err != nil {
126+
return err
127+
}
128+
121129
// Add handler for SQL tokenizer
122130
if err := provider.AddHandlerFuncEx(ctx, reRouteTokenizer, p.ServeTokenizer, http.MethodPost); err != nil {
123131
return err
@@ -223,6 +231,65 @@ func (p *plugin) ServeSchema(w http.ResponseWriter, req *http.Request) {
223231
router.ServeJSON(w, response, http.StatusOK, 2)
224232
}
225233

234+
func (p *plugin) ServeTable(w http.ResponseWriter, req *http.Request) {
235+
// Query parameters
236+
var q struct {
237+
Offset uint `json:"offset"`
238+
Limit uint `json:"limit"`
239+
}
240+
241+
// Decode params, params[0] is the schema name and params[1] is the table name
242+
params := router.RequestParams(req)
243+
244+
// Decode query
245+
if err := router.RequestQuery(req, &q); err != nil {
246+
router.ServeError(w, http.StatusBadRequest, err.Error())
247+
return
248+
}
249+
250+
// Get a connection
251+
conn := p.Get(req.Context())
252+
if conn == nil {
253+
router.ServeError(w, http.StatusBadGateway, "No connection")
254+
return
255+
}
256+
defer p.Put(conn)
257+
258+
// Check for schema
259+
if !stringSliceContainsElement(conn.Schemas(), params[0]) {
260+
router.ServeError(w, http.StatusNotFound, "Schema not found", strconv.Quote(params[0]))
261+
return
262+
}
263+
if !stringSliceContainsElement(conn.Tables(params[0]), params[1]) {
264+
router.ServeError(w, http.StatusNotFound, "Table not found", strconv.Quote(params[1]))
265+
return
266+
}
267+
268+
// Populate response
269+
var response SqlResultResponse
270+
if err := conn.Do(req.Context(), SQLITE_TXN_DEFAULT, func(txn SQTransaction) error {
271+
r, err := txn.Query(S(N(params[1]).WithSchema(params[0])).WithLimitOffset(q.Limit, q.Offset))
272+
if err != nil {
273+
return err
274+
}
275+
if r, err := results(r); err != nil {
276+
return err
277+
} else {
278+
response = r
279+
response.Schema = params[0]
280+
response.Table = params[1]
281+
}
282+
// Return success
283+
return nil
284+
}); err != nil {
285+
router.ServeError(w, http.StatusBadRequest, err.Error())
286+
return
287+
}
288+
289+
// Serve response
290+
router.ServeJSON(w, response, http.StatusOK, 2)
291+
}
292+
226293
func (p *plugin) ServeTokenizer(w http.ResponseWriter, req *http.Request) {
227294
// Decode request
228295
query := SqlRequest{}
@@ -302,6 +369,9 @@ func (p *plugin) ServeQuery(w http.ResponseWriter, req *http.Request) {
302369
router.ServeJSON(w, response, http.StatusOK, 2)
303370
}
304371

372+
///////////////////////////////////////////////////////////////////////////////
373+
// PRIVATE METHODS
374+
305375
func results(r SQResults) (SqlResultResponse, error) {
306376
result := SqlResultResponse{
307377
Sql: r.ExpandedSQL(),
@@ -327,9 +397,6 @@ func results(r SQResults) (SqlResultResponse, error) {
327397
return result, nil
328398
}
329399

330-
///////////////////////////////////////////////////////////////////////////////
331-
// PRIVATE METHODS
332-
333400
func stringSliceContainsElement(v []string, elem string) bool {
334401
for _, v := range v {
335402
if v == elem {

0 commit comments

Comments
 (0)