Repository: tablelandnetwork/go-tableland
Pull request #612 (2024-02-21 16:38:30)

implements POST /query
# Summary

Implements the `POST /query` spec defined at https://github.com/tablelandnetwork/docs/pull/188

Working example on `staging`

```bash
curl -v --json '{"statement": "SELECT * FROM system_txn_receipts LIMIT 1"}' https://staging.tableland.network/api/v1/query
```

cc @dtbuchholz 

# Context

We're adding support for `POST /query` so queries can be sent via body request without the need of encoding the URL.

# Implementation overview

Generates the code based on a new spec and implements the controller in a similar way to `GET /query`. 




Patch:
diff --git a/internal/router/controllers/apiv1/api_health.go b/internal/router/controllers/apiv1/api_health.go
index c1a4e46..c060b02 100644
--- a/internal/router/controllers/apiv1/api_health.go
+++ b/internal/router/controllers/apiv1/api_health.go
@@ -1,9 +1,9 @@
 /*
  * Tableland Validator - OpenAPI 3.0
  *
- * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+ * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.  The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information.
  *
- * API version: 1.0.0
+ * API version: 1.1.0
  * Contact: carson@textile.io
  * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
  */
diff --git a/internal/router/controllers/apiv1/api_query.go b/internal/router/controllers/apiv1/api_query.go
index 0d2ccd8..3fd7d41 100644
--- a/internal/router/controllers/apiv1/api_query.go
+++ b/internal/router/controllers/apiv1/api_query.go
@@ -1,9 +1,9 @@
 /*
  * Tableland Validator - OpenAPI 3.0
  *
- * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+ * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.  The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information.
  *
- * API version: 1.0.0
+ * API version: 1.1.0
  * Contact: carson@textile.io
  * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
  */
@@ -17,3 +17,8 @@ func QueryByStatement(w http.ResponseWriter, r *http.Request) {
 	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
 	w.WriteHeader(http.StatusOK)
 }
+
+func QueryByStatementPost(w http.ResponseWriter, r *http.Request) {
+	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
+	w.WriteHeader(http.StatusOK)
+}
diff --git a/internal/router/controllers/apiv1/api_receipt.go b/internal/router/controllers/apiv1/api_receipt.go
index 81177b3..9baf8b2 100644
--- a/internal/router/controllers/apiv1/api_receipt.go
+++ b/internal/router/controllers/apiv1/api_receipt.go
@@ -1,9 +1,9 @@
 /*
  * Tableland Validator - OpenAPI 3.0
  *
- * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+ * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.  The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information.
  *
- * API version: 1.0.0
+ * API version: 1.1.0
  * Contact: carson@textile.io
  * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
  */
diff --git a/internal/router/controllers/apiv1/api_tables.go b/internal/router/controllers/apiv1/api_tables.go
index fced67c..855adf0 100644
--- a/internal/router/controllers/apiv1/api_tables.go
+++ b/internal/router/controllers/apiv1/api_tables.go
@@ -1,9 +1,9 @@
 /*
  * Tableland Validator - OpenAPI 3.0
  *
- * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+ * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.  The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information.
  *
- * API version: 1.0.0
+ * API version: 1.1.0
  * Contact: carson@textile.io
  * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
  */
diff --git a/internal/router/controllers/apiv1/api_version.go b/internal/router/controllers/apiv1/api_version.go
index 3f4aa47..8bb58d9 100644
--- a/internal/router/controllers/apiv1/api_version.go
+++ b/internal/router/controllers/apiv1/api_version.go
@@ -1,9 +1,9 @@
 /*
  * Tableland Validator - OpenAPI 3.0
  *
- * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+ * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.  The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information.
  *
- * API version: 1.0.0
+ * API version: 1.1.0
  * Contact: carson@textile.io
  * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
  */
diff --git a/internal/router/controllers/apiv1/logger.go b/internal/router/controllers/apiv1/logger.go
index ed473ba..d404d51 100644
--- a/internal/router/controllers/apiv1/logger.go
+++ b/internal/router/controllers/apiv1/logger.go
@@ -1,9 +1,9 @@
 /*
  * Tableland Validator - OpenAPI 3.0
  *
- * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+ * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.  The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information.
  *
- * API version: 1.0.0
+ * API version: 1.1.0
  * Contact: carson@textile.io
  * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
  */
diff --git a/internal/router/controllers/apiv1/model_column.go b/internal/router/controllers/apiv1/model_column.go
index 56b9e07..f105c6a 100644
--- a/internal/router/controllers/apiv1/model_column.go
+++ b/internal/router/controllers/apiv1/model_column.go
@@ -1,9 +1,9 @@
 /*
  * Tableland Validator - OpenAPI 3.0
  *
- * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+ * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.  The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information.
  *
- * API version: 1.0.0
+ * API version: 1.1.0
  * Contact: carson@textile.io
  * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
  */
diff --git a/internal/router/controllers/apiv1/model_one_of_table_attributes_value.go b/internal/router/controllers/apiv1/model_one_of_table_attributes_value.go
index b0bf2f6..477f613 100644
--- a/internal/router/controllers/apiv1/model_one_of_table_attributes_value.go
+++ b/internal/router/controllers/apiv1/model_one_of_table_attributes_value.go
@@ -1,9 +1,9 @@
 /*
  * Tableland Validator - OpenAPI 3.0
  *
- * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+ * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.  The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information.
  *
- * API version: 1.0.0
+ * API version: 1.1.0
  * Contact: carson@textile.io
  * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
  */
diff --git a/internal/router/controllers/apiv1/model_query.go b/internal/router/controllers/apiv1/model_query.go
new file mode 100644
index 0000000..339834e
--- /dev/null
+++ b/internal/router/controllers/apiv1/model_query.go
@@ -0,0 +1,21 @@
+/*
+ * Tableland Validator - OpenAPI 3.0
+ *
+ * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.  The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information.
+ *
+ * API version: 1.1.0
+ * Contact: carson@textile.io
+ * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
+ */
+package apiv1
+
+type Query struct {
+	// The SQL read query statement
+	Statement string `json:"statement,omitempty"`
+	// The requested response format: * `objects` - Returns the query results as a JSON array of JSON objects. * `table` - Return the query results as a JSON object with columns and rows properties. 
+	Format string `json:"format,omitempty"`
+	// Whether to extract the JSON object from the single property of the surrounding JSON object.
+	Extract bool `json:"extract,omitempty"`
+	// Whether to unwrap the returned JSON objects from their surrounding array.
+	Unwrap bool `json:"unwrap,omitempty"`
+}
diff --git a/internal/router/controllers/apiv1/model_schema.go b/internal/router/controllers/apiv1/model_schema.go
index 83060b0..6f3fe07 100644
--- a/internal/router/controllers/apiv1/model_schema.go
+++ b/internal/router/controllers/apiv1/model_schema.go
@@ -1,9 +1,9 @@
 /*
  * Tableland Validator - OpenAPI 3.0
  *
- * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+ * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.  The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information.
  *
- * API version: 1.0.0
+ * API version: 1.1.0
  * Contact: carson@textile.io
  * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
  */
diff --git a/internal/router/controllers/apiv1/model_table.go b/internal/router/controllers/apiv1/model_table.go
index 08a21d5..6dcd7f7 100644
--- a/internal/router/controllers/apiv1/model_table.go
+++ b/internal/router/controllers/apiv1/model_table.go
@@ -1,9 +1,9 @@
 /*
  * Tableland Validator - OpenAPI 3.0
  *
- * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+ * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.  The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information.
  *
- * API version: 1.0.0
+ * API version: 1.1.0
  * Contact: carson@textile.io
  * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
  */
diff --git a/internal/router/controllers/apiv1/model_table_attributes.go b/internal/router/controllers/apiv1/model_table_attributes.go
index e519d6b..f079b75 100644
--- a/internal/router/controllers/apiv1/model_table_attributes.go
+++ b/internal/router/controllers/apiv1/model_table_attributes.go
@@ -1,9 +1,9 @@
 /*
  * Tableland Validator - OpenAPI 3.0
  *
- * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+ * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.  The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information.
  *
- * API version: 1.0.0
+ * API version: 1.1.0
  * Contact: carson@textile.io
  * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
  */
diff --git a/internal/router/controllers/apiv1/model_transaction_receipt.go b/internal/router/controllers/apiv1/model_transaction_receipt.go
index 6b3c7e8..b79011f 100644
--- a/internal/router/controllers/apiv1/model_transaction_receipt.go
+++ b/internal/router/controllers/apiv1/model_transaction_receipt.go
@@ -1,16 +1,16 @@
 /*
  * Tableland Validator - OpenAPI 3.0
  *
- * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+ * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.  The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information.
  *
- * API version: 1.0.0
+ * API version: 1.1.0
  * Contact: carson@textile.io
  * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
  */
 package apiv1
 
 type TransactionReceipt struct {
-
+	// This field is deprecated
 	TableId string `json:"table_id,omitempty"`
 
 	TableIds []string `json:"table_ids,omitempty"`
diff --git a/internal/router/controllers/apiv1/model_version_info.go b/internal/router/controllers/apiv1/model_version_info.go
index d460bc9..fbd9dee 100644
--- a/internal/router/controllers/apiv1/model_version_info.go
+++ b/internal/router/controllers/apiv1/model_version_info.go
@@ -1,16 +1,15 @@
 /*
  * Tableland Validator - OpenAPI 3.0
  *
- * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+ * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.  The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information.
  *
- * API version: 1.0.0
+ * API version: 1.1.0
  * Contact: carson@textile.io
  * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
  */
 package apiv1
 
 type VersionInfo struct {
-
 	Version int32 `json:"version,omitempty"`
 
 	GitCommit string `json:"git_commit,omitempty"`
diff --git a/internal/router/controllers/apiv1/routers.go b/internal/router/controllers/apiv1/routers.go
index f61e689..598aefd 100644
--- a/internal/router/controllers/apiv1/routers.go
+++ b/internal/router/controllers/apiv1/routers.go
@@ -1,9 +1,9 @@
 /*
  * Tableland Validator - OpenAPI 3.0
  *
- * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to on-chain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g: SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g. list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.
+ * In Tableland, Validators are the execution unit/actors of the protocol. They have the following responsibilities: - Listen to onchain events to materialize Tableland-compliant SQL queries in a database engine (currently, SQLite by default). - Serve read-queries (e.g., SELECT * FROM foo_69_1) to the external world. - Serve state queries (e.g., list tables, get receipts, etc) to the external world.  In the 1.0.0 release of the Tableland Validator API, we've switched to a design first approach! You can now help us improve the API whether it's by making changes to the definition itself or to the code. That way, with time, we can improve the API in general, and expose some of the new features in OAS3.  The API includes the following endpoints: - `/health`: Returns OK if the validator considers itself healthy. - `/version`: Returns version information about the validator daemon. - `/query`: Returns the results of a SQL read query against the Tableland network. - `/receipt/{chainId}/{transactionHash}`: Returns the status of a given transaction receipt by hash. - `/tables/{chainId}/{tableId}`: Returns information about a single table, including schema information.
  *
- * API version: 1.0.0
+ * API version: 1.1.0
  * Contact: carson@textile.io
  * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git)
  */
@@ -69,6 +69,13 @@ var routes = Routes{
 		QueryByStatement,
 	},
 
+	Route{
+		"QueryByStatementPost",
+		strings.ToUpper("Post"),
+		"/api/v1/query",
+		QueryByStatementPost,
+	},
+
 	Route{
 		"ReceiptByTransactionHash",
 		strings.ToUpper("Get"),
diff --git a/internal/router/controllers/controller.go b/internal/router/controllers/controller.go
index 073d256..699befd 100644
--- a/internal/router/controllers/controller.go
+++ b/internal/router/controllers/controller.go
@@ -150,7 +150,7 @@ func (c *Controller) GetReceiptByTransactionHash(rw http.ResponseWriter, r *http
 	_ = json.NewEncoder(rw).Encode(receiptResponse)
 }
 
-// GetTable handles the GET /chain/{chainID}/tables/{tableId} call.
+// GetTable handles the GET /tables/{chainID}/{tableId} call.
 func (c *Controller) GetTable(rw http.ResponseWriter, r *http.Request) {
 	ctx := r.Context()
 	vars := mux.Vars(r)
@@ -256,6 +256,11 @@ func (c *Controller) GetTableQuery(rw http.ResponseWriter, r *http.Request) {
 		return
 	}
 
+	if len(formatted) == 0 {
+		rw.WriteHeader(http.StatusNotFound)
+		return
+	}
+
 	collectReadQueryMetric(r.Context(), stm, config, took)
 
 	rw.WriteHeader(http.StatusOK)
@@ -265,6 +270,65 @@ func (c *Controller) GetTableQuery(rw http.ResponseWriter, r *http.Request) {
 	_, _ = rw.Write(formatted)
 }
 
+// PostTableQuery handles the POST /query call.
+func (c *Controller) PostTableQuery(rw http.ResponseWriter, r *http.Request) {
+	rw.Header().Set("Content-Type", "application/json")
+
+	// setting a default body because these options could be missing from JSON
+	body := &apiv1.Query{
+		Format:  string(formatter.Objects),
+		Extract: false,
+		Unwrap:  false,
+	}
+	if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+		rw.WriteHeader(http.StatusBadRequest)
+		msg := fmt.Sprintf("Error parsing the body request: %v", err)
+		log.Ctx(r.Context()).Error().Err(err).Msg(msg)
+		_ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: msg})
+		return
+	}
+	_ = r.Body.Close()
+
+	start := time.Now()
+	res, ok := c.runReadRequest(r.Context(), body.Statement, rw)
+	if !ok {
+		return
+	}
+	took := time.Since(start)
+
+	var opts []formatter.FormatOption
+	output, ok := formatter.OutputFromString(body.Format)
+	if !ok {
+		log.Ctx(r.Context()).Error().Msg("bad output query parameter")
+		_ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: "bad output query parameter"})
+	}
+	opts = append(opts, formatter.WithOutput(output))
+	opts = append(opts, formatter.WithExtract(body.Extract))
+	opts = append(opts, formatter.WithUnwrap(body.Unwrap))
+
+	formatted, config, err := formatter.Format(res, opts...)
+	if err != nil {
+		rw.WriteHeader(http.StatusInternalServerError)
+		msg := fmt.Sprintf("Error formatting data: %v", err)
+		_ = json.NewEncoder(rw).Encode(errors.ServiceError{Message: msg})
+		log.Ctx(r.Context()).Error().Err(err).Msg(msg)
+		return
+	}
+
+	if len(formatted) == 0 {
+		rw.WriteHeader(http.StatusNotFound)
+		return
+	}
+
+	collectReadQueryMetric(r.Context(), body.Statement, config, took)
+
+	rw.WriteHeader(http.StatusOK)
+	if config.Unwrap && len(res.Rows) > 1 {
+		rw.Header().Set("Content-Type", "application/jsonl+json")
+	}
+	_, _ = rw.Write(formatted)
+}
+
 func (c *Controller) runReadRequest(
 	ctx context.Context,
 	stm string,
diff --git a/internal/router/router.go b/internal/router/router.go
index 17546c2..13cd109 100644
--- a/internal/router/router.go
+++ b/internal/router/router.go
@@ -61,6 +61,10 @@ func configureAPIV1Routes(
 			userCtrl.GetTableQuery,
 			[]mux.MiddlewareFunc{middlewares.WithLogging, rateLim},
 		},
+		"QueryByStatementPost": {
+			userCtrl.PostTableQuery,
+			[]mux.MiddlewareFunc{middlewares.WithLogging, rateLim},
+		},
 		"ReceiptByTransactionHash": {
 			userCtrl.GetReceiptByTransactionHash,
 			[]mux.MiddlewareFunc{middlewares.WithLogging, middlewares.RESTChainID(supportedChainIDs), rateLim},
@@ -97,11 +101,30 @@ func configureAPIV1Routes(
 			return fmt.Errorf("get path template: %s", err)
 		}
 
-		router.get(
-			pathTemplate,
-			endpoint.handler,
-			append([]mux.MiddlewareFunc{middlewares.OtelHTTP(routeName)}, endpoint.middlewares...)...,
-		)
+		methods, err := route.GetMethods()
+		if err != nil {
+			return fmt.Errorf("get method: %s", err)
+		}
+
+		for _, method := range methods {
+			switch method {
+			case "GET":
+				router.get(
+					pathTemplate,
+					endpoint.handler,
+					append([]mux.MiddlewareFunc{middlewares.OtelHTTP(routeName)}, endpoint.middlewares...)...,
+				)
+			case "POST":
+				router.post(
+					pathTemplate,
+					endpoint.handler,
+					append([]mux.MiddlewareFunc{middlewares.OtelHTTP(routeName)}, endpoint.middlewares...)...,
+				)
+			default:
+				return fmt.Errorf("unknown method")
+			}
+		}
+
 		return nil
 	}); err != nil {
 		return fmt.Errorf("configuring api v1 router: %s", err)
@@ -132,6 +155,13 @@ func (r *Router) get(uri string, f http.HandlerFunc, mid ...mux.MiddlewareFunc)
 	sub.Use(mid...)
 }
 
+// post creates a subroute on the specified URI that only accepts POST. You can provide specific middlewares.
+func (r *Router) post(uri string, f http.HandlerFunc, mid ...mux.MiddlewareFunc) {
+	sub := r.r.Path(uri).Subrouter()
+	sub.HandleFunc("", f).Methods(http.MethodPost)
+	sub.Use(mid...)
+}
+
 // use adds middlewares to all routes. Should be used when a middleware should be execute all all routes (e.g. CORS).
 func (r *Router) use(mid ...mux.MiddlewareFunc) {
 	r.r.Use(mid...)


Test patch:
diff --git a/internal/router/controllers/controller_test.go b/internal/router/controllers/controller_test.go
index 1a2cce6..5cd20b7 100644
--- a/internal/router/controllers/controller_test.go
+++ b/internal/router/controllers/controller_test.go
@@ -1,7 +1,9 @@
 package controllers
 
 import (
+	"bytes"
 	"context"
+	"encoding/json"
 	"errors"
 	"fmt"
 	"math/big"
@@ -90,6 +92,105 @@ func TestQuery(t *testing.T) {
 	}
 }
 
+func TestPostQuery(t *testing.T) {
+	r := mocks.NewGateway(t)
+	r.EXPECT().RunReadQuery(mock.Anything, mock.AnythingOfType("string")).Return(
+		&gateway.TableData{
+			Columns: []gateway.Column{
+				{Name: "id"},
+				{Name: "eyes"},
+				{Name: "mouth"},
+			},
+			Rows: [][]*gateway.ColumnValue{
+				{
+					gateway.OtherColValue(1),
+					gateway.OtherColValue("Big"),
+					gateway.OtherColValue("Surprised"),
+				},
+				{
+					gateway.OtherColValue(2),
+					gateway.OtherColValue("Medium"),
+					gateway.OtherColValue("Sad"),
+				},
+				{
+					gateway.OtherColValue(3),
+					gateway.OtherColValue("Small"),
+					gateway.OtherColValue("Happy"),
+				},
+			},
+		},
+		nil,
+	)
+
+	ctrl := NewController(r)
+
+	router := mux.NewRouter()
+	router.HandleFunc("/query", ctrl.PostTableQuery)
+
+	ctx := context.WithValue(context.Background(), middlewares.ContextIPAddress, strconv.Itoa(1))
+
+	// Table format
+	body, err := json.Marshal(struct {
+		Statement string
+		Format    string
+	}{
+		Statement: "select * from foo",
+		Format:    "table",
+	})
+	require.NoError(t, err)
+
+	req, err := http.NewRequestWithContext(ctx, "POST", "/query", bytes.NewReader(body))
+	require.NoError(t, err)
+	rr := httptest.NewRecorder()
+	router.ServeHTTP(rr, req)
+	require.Equal(t, http.StatusOK, rr.Code)
+	exp := `{"columns":[{"name":"id"},{"name":"eyes"},{"name":"mouth"}],"rows":[[1,"Big","Surprised"],[2,"Medium","Sad"],[3,"Small","Happy"]]}` // nolint
+	require.JSONEq(t, exp, rr.Body.String())
+
+	// Object format
+	body, err = json.Marshal(struct {
+		Statement string
+		Format    string
+	}{
+		Statement: "select * from foo",
+		Format:    "objects",
+	})
+	require.NoError(t, err)
+
+	req, err = http.NewRequestWithContext(ctx, "POST", "/query", bytes.NewReader(body))
+	require.NoError(t, err)
+	rr = httptest.NewRecorder()
+	router.ServeHTTP(rr, req)
+	require.Equal(t, http.StatusOK, rr.Code)
+	exp = `[{"eyes":"Big","id":1,"mouth":"Surprised"},{"eyes":"Medium","id":2,"mouth":"Sad"},{"eyes":"Small","id":3,"mouth":"Happy"}]` // nolint
+	require.JSONEq(t, exp, rr.Body.String())
+
+	// Unwrapped object format
+	body, err = json.Marshal(struct {
+		Statement string
+		Format    string
+		Unwrap    bool
+	}{
+		Statement: "select * from foo",
+		Format:    "objects",
+		Unwrap:    true,
+	})
+	require.NoError(t, err)
+
+	req, err = http.NewRequestWithContext(ctx, "POST", "/query", bytes.NewReader(body))
+	require.NoError(t, err)
+	rr = httptest.NewRecorder()
+	router.ServeHTTP(rr, req)
+	require.Equal(t, http.StatusOK, rr.Code)
+	exp = "{\"eyes\":\"Big\",\"id\":1,\"mouth\":\"Surprised\"}\n{\"eyes\":\"Medium\",\"id\":2,\"mouth\":\"Sad\"}\n{\"eyes\":\"Small\",\"id\":3,\"mouth\":\"Happy\"}\n" // nolint
+	wantStrings := parseJSONLString(exp)
+	gotStrings := parseJSONLString(rr.Body.String())
+	require.Equal(t, len(wantStrings), len(gotStrings))
+	for i, wantString := range wantStrings {
+		require.JSONEq(t, wantString, gotStrings[i])
+	}
+}
+
 func TestQueryEmptyTable(t *testing.T) {
 	r := mocks.NewGateway(t)
 	r.EXPECT().RunReadQuery(mock.Anything, mock.AnythingOfType("string")).Return(
@@ -123,11 +224,7 @@ func TestQueryEmptyTable(t *testing.T) {
 	require.NoError(t, err)
 	rr = httptest.NewRecorder()
 	router.ServeHTTP(rr, req)
-	require.Equal(t, http.StatusOK, rr.Code)
-	exp = ""
-	wantString := parseJSONLString(exp)
-	gotString := parseJSONLString(rr.Body.String())
-	require.Equal(t, wantString, gotString)
+	require.Equal(t, http.StatusNotFound, rr.Code)
 }
 
 func TestQueryExtracted(t *testing.T) {
@@ -177,6 +274,73 @@ func TestQueryExtracted(t *testing.T) {
 	}
 }
 
+func TestPostQueryExtracted(t *testing.T) {
+	r := mocks.NewGateway(t)
+	r.EXPECT().RunReadQuery(mock.Anything, mock.AnythingOfType("string")).Return(
+		&gateway.TableData{
+			Columns: []gateway.Column{{Name: "name"}},
+			Rows: [][]*gateway.ColumnValue{
+				{gateway.OtherColValue("bob")},
+				{gateway.OtherColValue("jane")},
+				{gateway.OtherColValue("alex")},
+			},
+		},
+		nil,
+	)
+
+	ctrl := NewController(r)
+
+	router := mux.NewRouter()
+	router.HandleFunc("/query", ctrl.PostTableQuery)
+
+	// Extracted object format
+	body, err := json.Marshal(struct {
+		Statement string
+		Format    string
+		Extract   bool
+	}{
+		Statement: "select * from foo",
+		Format:    "objects",
+		Extract:   true,
+	})
+	require.NoError(t, err)
+
+	req, err := http.NewRequestWithContext(context.Background(), "POST", "/query", bytes.NewReader(body))
+	require.NoError(t, err)
+	rr := httptest.NewRecorder()
+	router.ServeHTTP(rr, req)
+	require.Equal(t, http.StatusOK, rr.Code)
+	exp := `["bob","jane","alex"]`
+	require.JSONEq(t, exp, rr.Body.String())
+
+	// Extracted unwrapped object format
+	body, err = json.Marshal(struct {
+		Statement string
+		Format    string
+		Extract   bool
+		Unwrap    bool
+	}{
+		Statement: "select * from foo",
+		Format:    "objects",
+		Extract:   true,
+		Unwrap:    true,
+	})
+	require.NoError(t, err)
+
+	req, err = http.NewRequestWithContext(context.Background(), "POST", "/query", bytes.NewReader(body))
+	require.NoError(t, err)
+	rr = httptest.NewRecorder()
+	router.ServeHTTP(rr, req)
+	require.Equal(t, http.StatusOK, rr.Code)
+	exp = "\"bob\"\n\"jane\"\n\"alex\"\n"
+	wantStrings := parseJSONLString(exp)
+	gotStrings := parseJSONLString(rr.Body.String())
+	require.Equal(t, len(wantStrings), len(gotStrings))
+	for i, wantString := range wantStrings {
+		require.JSONEq(t, wantString, gotStrings[i])
+	}
+}
+
 func TestGetTablesByMocked(t *testing.T) {
 	t.Parallel()