From da9a57629e9e24d4cdec61c1468b98c28172a4de Mon Sep 17 00:00:00 2001 From: "tidb-cloud-data-service[bot]" <134662589+tidb-cloud-data-service[bot]@users.noreply.github.com> Date: Wed, 2 Aug 2023 06:28:51 +0000 Subject: [PATCH 1/7] [Redeploy]Initial Data App Setup --- data-service/data_sources/cluster.json | 5 +++++ data-service/dataapp_config.json | 7 +++++++ data-service/http_endpoints/config.json | 1 + 3 files changed, 13 insertions(+) create mode 100644 data-service/data_sources/cluster.json create mode 100644 data-service/dataapp_config.json create mode 100644 data-service/http_endpoints/config.json diff --git a/data-service/data_sources/cluster.json b/data-service/data_sources/cluster.json new file mode 100644 index 0000000..7129013 --- /dev/null +++ b/data-service/data_sources/cluster.json @@ -0,0 +1,5 @@ +[ + { + "cluster_id": 1379661944634374075 + } +] \ No newline at end of file diff --git a/data-service/dataapp_config.json b/data-service/dataapp_config.json new file mode 100644 index 0000000..ae7e5d6 --- /dev/null +++ b/data-service/dataapp_config.json @@ -0,0 +1,7 @@ +{ + "app_id": "dataapp-SdpjBpyj", + "app_name": "bookshop", + "app_type": "dataapp", + "description": "", + "app_version": "" +} \ No newline at end of file diff --git a/data-service/http_endpoints/config.json b/data-service/http_endpoints/config.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/data-service/http_endpoints/config.json @@ -0,0 +1 @@ +[] \ No newline at end of file From ec85ff342695a203174f39928d7674af57a658c0 Mon Sep 17 00:00:00 2001 From: "tidb-cloud-data-service[bot]" <134662589+tidb-cloud-data-service[bot]@users.noreply.github.com> Date: Wed, 2 Aug 2023 08:11:53 +0000 Subject: [PATCH 2/7] Deployment from Data App --- data-service/dataapp_config.json | 2 +- data-service/http_endpoints/config.json | 193 +++++++++++++++++- ...v1-book-rating_dump_pkOZmV_dump_SuCGLU.sql | 10 + .../http_endpoints/sql/GET-v1-book-rating.sql | 21 ++ .../http_endpoints/sql/GET-v1-book.sql | 23 +++ .../http_endpoints/sql/GET-v1-books.sql | 25 +++ .../sql/POST-v1-book-rating.sql | 20 ++ .../http_endpoints/sql/PUT-v1-book.sql | 13 ++ 8 files changed, 305 insertions(+), 2 deletions(-) create mode 100644 data-service/http_endpoints/sql/DELETE-v1-book-rating_dump_pkOZmV_dump_SuCGLU.sql create mode 100644 data-service/http_endpoints/sql/GET-v1-book-rating.sql create mode 100644 data-service/http_endpoints/sql/GET-v1-book.sql create mode 100644 data-service/http_endpoints/sql/GET-v1-books.sql create mode 100644 data-service/http_endpoints/sql/POST-v1-book-rating.sql create mode 100644 data-service/http_endpoints/sql/PUT-v1-book.sql diff --git a/data-service/dataapp_config.json b/data-service/dataapp_config.json index ae7e5d6..94c3eee 100644 --- a/data-service/dataapp_config.json +++ b/data-service/dataapp_config.json @@ -3,5 +3,5 @@ "app_name": "bookshop", "app_type": "dataapp", "description": "", - "app_version": "" + "app_version": "1.0.0" } \ No newline at end of file diff --git a/data-service/http_endpoints/config.json b/data-service/http_endpoints/config.json index 0637a08..01acf6b 100644 --- a/data-service/http_endpoints/config.json +++ b/data-service/http_endpoints/config.json @@ -1 +1,192 @@ -[] \ No newline at end of file +[ + { + "name": "book/rating", + "description": "", + "method": "DELETE", + "endpoint": "/v1/book/rating_dump_pkOZmV_dump_SuCGLU", + "data_source": { + "cluster_id": 1379661944634374075 + }, + "params": [ + { + "name": "user_id", + "type": "number", + "required": 1, + "default": "", + "description": "" + } + ], + "settings": { + "timeout": 5000, + "row_limit": 50 + }, + "tag": "Default", + "batch_operation": 0, + "sql_file": "sql/DELETE-v1-book-rating_dump_pkOZmV_dump_SuCGLU.sql", + "type": "sql_endpoint", + "return_type": "json" + }, + { + "name": "book/rating", + "description": "", + "method": "POST", + "endpoint": "/v1/book/rating", + "data_source": { + "cluster_id": 1379661944634374075 + }, + "params": [ + { + "name": "score", + "type": "number", + "required": 1, + "default": "", + "description": "" + }, + { + "name": "user_id", + "type": "number", + "required": 1, + "default": "", + "description": "" + }, + { + "name": "book_id", + "type": "number", + "required": 1, + "default": "", + "description": "" + } + ], + "settings": { + "timeout": 5000, + "row_limit": 50 + }, + "tag": "Default", + "batch_operation": 0, + "sql_file": "sql/POST-v1-book-rating.sql", + "type": "sql_endpoint", + "return_type": "json" + }, + { + "name": "book/rating", + "description": "", + "method": "GET", + "endpoint": "/v1/book/rating", + "data_source": { + "cluster_id": 1379661944634374075 + }, + "params": [ + { + "name": "book_id", + "type": "number", + "required": 1, + "default": "", + "description": "" + } + ], + "settings": { + "timeout": 5000, + "row_limit": 50 + }, + "tag": "Default", + "batch_operation": 0, + "sql_file": "sql/GET-v1-book-rating.sql", + "type": "sql_endpoint", + "return_type": "json" + }, + { + "name": "book/[id]", + "description": "", + "method": "PUT", + "endpoint": "/v1/book", + "data_source": { + "cluster_id": 1379661944634374075 + }, + "params": [ + { + "name": "stock", + "type": "number", + "required": 1, + "default": "", + "description": "" + }, + { + "name": "book_id", + "type": "number", + "required": 1, + "default": "", + "description": "" + } + ], + "settings": { + "timeout": 5000, + "row_limit": 50 + }, + "tag": "Default", + "batch_operation": 0, + "sql_file": "sql/PUT-v1-book.sql", + "type": "sql_endpoint", + "return_type": "json" + }, + { + "name": "book/[id]", + "description": "", + "method": "GET", + "endpoint": "/v1/book", + "data_source": { + "cluster_id": 1379661944634374075 + }, + "params": [ + { + "name": "book_id", + "type": "string", + "required": 1, + "default": "", + "description": "" + } + ], + "settings": { + "timeout": 5000, + "row_limit": 50 + }, + "tag": "Default", + "batch_operation": 0, + "sql_file": "sql/GET-v1-book.sql", + "type": "sql_endpoint", + "return_type": "json" + }, + { + "name": "books", + "description": "", + "method": "GET", + "endpoint": "/v1/books", + "data_source": { + "cluster_id": 1379661944634374075 + }, + "params": [ + { + "name": "start_id", + "type": "number", + "required": 0, + "default": "0", + "description": "" + }, + { + "name": "size", + "type": "number", + "required": 0, + "default": "8", + "description": "" + } + ], + "settings": { + "timeout": 5000, + "row_limit": 50 + }, + "tag": "Default", + "batch_operation": 0, + "sql_file": "sql/GET-v1-books.sql", + "type": "sql_endpoint", + "return_type": "json" + } +] \ No newline at end of file diff --git a/data-service/http_endpoints/sql/DELETE-v1-book-rating_dump_pkOZmV_dump_SuCGLU.sql b/data-service/http_endpoints/sql/DELETE-v1-book-rating_dump_pkOZmV_dump_SuCGLU.sql new file mode 100644 index 0000000..c29464f --- /dev/null +++ b/data-service/http_endpoints/sql/DELETE-v1-book-rating_dump_pkOZmV_dump_SuCGLU.sql @@ -0,0 +1,10 @@ +/* Getting Started: +Enter "USE {database};" before entering your SQL statements. +Type "--your question" + Enter to try out AI-generated SQL queries +Declare a parameter like "Where id = ${arg}". +*/ +USE bookshop; + +DELETE FROM `ratings` +WHERE + `user_id` = ${user_id}; diff --git a/data-service/http_endpoints/sql/GET-v1-book-rating.sql b/data-service/http_endpoints/sql/GET-v1-book-rating.sql new file mode 100644 index 0000000..50a4258 --- /dev/null +++ b/data-service/http_endpoints/sql/GET-v1-book-rating.sql @@ -0,0 +1,21 @@ +/* Getting Started: +Enter "USE {database};" before entering your SQL statements. +Type "--your question" + Enter to try out AI-generated SQL queries +Declare a parameter like "Where id = ${arg}". +*/ +USE bookshop; + +-- get all ratings by variable book.id, and user details +SELECT + ratings.book_id, + ratings.user_id, + ratings.score, + ratings.rated_at, + users.id, + users.balance, + users.nickname +FROM + ratings + INNER JOIN users ON ratings.user_id = users.id +WHERE + ratings.book_id = ${book_id}; diff --git a/data-service/http_endpoints/sql/GET-v1-book.sql b/data-service/http_endpoints/sql/GET-v1-book.sql new file mode 100644 index 0000000..7413dc8 --- /dev/null +++ b/data-service/http_endpoints/sql/GET-v1-book.sql @@ -0,0 +1,23 @@ +/* Getting Started: +Enter "USE {database};" before entering your SQL statements. +Type "--your question" + Enter to try out AI-generated SQL queries +Declare a parameter like "Where id = ${arg}". +*/ +USE bookshop; + +SELECT + b.id, + b.title, + b.type, + b.published_at, + b.stock, + b.price, + r.score, + a.name +FROM + `books` AS b + JOIN `ratings` AS r ON b.id = r.book_id + JOIN `book_authors` AS ba ON b.id = ba.book_id + JOIN `authors` AS a ON ba.author_id = a.id +WHERE b.id = ${book_id} +LIMIT 1 \ No newline at end of file diff --git a/data-service/http_endpoints/sql/GET-v1-books.sql b/data-service/http_endpoints/sql/GET-v1-books.sql new file mode 100644 index 0000000..2200ad6 --- /dev/null +++ b/data-service/http_endpoints/sql/GET-v1-books.sql @@ -0,0 +1,25 @@ +/* Getting Started: +Enter "USE {database};" before entering your SQL statements. +Type "--your question" + Enter to try out AI-generated SQL queries +Declare a parameter like "Where id = ${arg}". +*/ +USE bookshop; + +SELECT + b.id, + b.title, + b.type, + b.published_at, + b.stock, + b.price, + r.score, + a.name +FROM + `books` AS b + JOIN `ratings` AS r ON b.id = r.book_id + JOIN `book_authors` AS ba ON b.id = ba.book_id + JOIN `authors` AS a ON ba.author_id = a.id +WHERE b.id > ${start_id} +ORDER BY + b.id ASC +LIMIT ${size} diff --git a/data-service/http_endpoints/sql/POST-v1-book-rating.sql b/data-service/http_endpoints/sql/POST-v1-book-rating.sql new file mode 100644 index 0000000..2323200 --- /dev/null +++ b/data-service/http_endpoints/sql/POST-v1-book-rating.sql @@ -0,0 +1,20 @@ +/* Getting Started: +Enter "USE {database};" before entering your SQL statements. +Type "--your question" + Enter to try out AI-generated SQL queries +Declare a parameter like "Where id = ${arg}". +*/ +USE bookshop; + +-- check if user ID in users.id, and insert a score to ratings by variable book.id +INSERT INTO + `ratings` (`book_id`, `user_id`, `score`) +SELECT + `book`.`id`, + `users`.`id`, + ${score} +FROM + `books` AS `book` + CROSS JOIN `users` +WHERE + `users`.`id` = ${user_id} + AND `book`.`id` = ${book_id}; diff --git a/data-service/http_endpoints/sql/PUT-v1-book.sql b/data-service/http_endpoints/sql/PUT-v1-book.sql new file mode 100644 index 0000000..7417330 --- /dev/null +++ b/data-service/http_endpoints/sql/PUT-v1-book.sql @@ -0,0 +1,13 @@ +/* Getting Started: +Enter "USE {database};" before entering your SQL statements. +Type "--your question" + Enter to try out AI-generated SQL queries +Declare a parameter like "Where id = ${arg}". +*/ +USE bookshop; + +-- update stock by b.id +UPDATE `books` +SET + `stock` = ${stock} +WHERE + `id` = ${book_id}; \ No newline at end of file From 5b88d87dddff63fbab2e97b73c3764c436b6c49d Mon Sep 17 00:00:00 2001 From: "tidb-cloud-data-service[bot]" <134662589+tidb-cloud-data-service[bot]@users.noreply.github.com> Date: Wed, 2 Aug 2023 08:12:47 +0000 Subject: [PATCH 3/7] Deployment from Data App --- data-service/http_endpoints/config.json | 4 ++-- ..._dump_pkOZmV_dump_SuCGLU.sql => DELETE-v1-book-rating.sql} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename data-service/http_endpoints/sql/{DELETE-v1-book-rating_dump_pkOZmV_dump_SuCGLU.sql => DELETE-v1-book-rating.sql} (100%) diff --git a/data-service/http_endpoints/config.json b/data-service/http_endpoints/config.json index 01acf6b..6ad97bc 100644 --- a/data-service/http_endpoints/config.json +++ b/data-service/http_endpoints/config.json @@ -3,7 +3,7 @@ "name": "book/rating", "description": "", "method": "DELETE", - "endpoint": "/v1/book/rating_dump_pkOZmV_dump_SuCGLU", + "endpoint": "/v1/book/rating", "data_source": { "cluster_id": 1379661944634374075 }, @@ -22,7 +22,7 @@ }, "tag": "Default", "batch_operation": 0, - "sql_file": "sql/DELETE-v1-book-rating_dump_pkOZmV_dump_SuCGLU.sql", + "sql_file": "sql/DELETE-v1-book-rating.sql", "type": "sql_endpoint", "return_type": "json" }, diff --git a/data-service/http_endpoints/sql/DELETE-v1-book-rating_dump_pkOZmV_dump_SuCGLU.sql b/data-service/http_endpoints/sql/DELETE-v1-book-rating.sql similarity index 100% rename from data-service/http_endpoints/sql/DELETE-v1-book-rating_dump_pkOZmV_dump_SuCGLU.sql rename to data-service/http_endpoints/sql/DELETE-v1-book-rating.sql From de981f3fee92e0fe6188d01dc4973e856ff1aa9b Mon Sep 17 00:00:00 2001 From: "tidb-cloud-data-service[bot]" <134662589+tidb-cloud-data-service[bot]@users.noreply.github.com> Date: Thu, 3 Aug 2023 06:33:15 +0000 Subject: [PATCH 4/7] Deployment from Data App --- data-service/http_endpoints/config.json | 7 +++++++ data-service/http_endpoints/sql/DELETE-v1-book-rating.sql | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/data-service/http_endpoints/config.json b/data-service/http_endpoints/config.json index 6ad97bc..1f2179b 100644 --- a/data-service/http_endpoints/config.json +++ b/data-service/http_endpoints/config.json @@ -14,6 +14,13 @@ "required": 1, "default": "", "description": "" + }, + { + "name": "book_id", + "type": "number", + "required": 0, + "default": "", + "description": "" } ], "settings": { diff --git a/data-service/http_endpoints/sql/DELETE-v1-book-rating.sql b/data-service/http_endpoints/sql/DELETE-v1-book-rating.sql index c29464f..8153150 100644 --- a/data-service/http_endpoints/sql/DELETE-v1-book-rating.sql +++ b/data-service/http_endpoints/sql/DELETE-v1-book-rating.sql @@ -7,4 +7,5 @@ USE bookshop; DELETE FROM `ratings` WHERE - `user_id` = ${user_id}; + `user_id` = ${user_id} + AND `book_id` = ${book_id}; From cebc16037cd2ccdaf9feb6cdb4066c682f06976c Mon Sep 17 00:00:00 2001 From: "tidb-cloud-data-service[bot]" <134662589+tidb-cloud-data-service[bot]@users.noreply.github.com> Date: Thu, 3 Aug 2023 06:38:27 +0000 Subject: [PATCH 5/7] Deploy from Data App --- data-service/http_endpoints/config.json | 50 ++++++++++++------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/data-service/http_endpoints/config.json b/data-service/http_endpoints/config.json index 1f2179b..222e8f0 100644 --- a/data-service/http_endpoints/config.json +++ b/data-service/http_endpoints/config.json @@ -34,23 +34,16 @@ "return_type": "json" }, { - "name": "book/rating", + "name": "book/[id]", "description": "", - "method": "POST", - "endpoint": "/v1/book/rating", + "method": "PUT", + "endpoint": "/v1/book", "data_source": { "cluster_id": 1379661944634374075 }, "params": [ { - "name": "score", - "type": "number", - "required": 1, - "default": "", - "description": "" - }, - { - "name": "user_id", + "name": "stock", "type": "number", "required": 1, "default": "", @@ -70,22 +63,22 @@ }, "tag": "Default", "batch_operation": 0, - "sql_file": "sql/POST-v1-book-rating.sql", + "sql_file": "sql/PUT-v1-book.sql", "type": "sql_endpoint", "return_type": "json" }, { - "name": "book/rating", + "name": "book/[id]", "description": "", "method": "GET", - "endpoint": "/v1/book/rating", + "endpoint": "/v1/book", "data_source": { "cluster_id": 1379661944634374075 }, "params": [ { "name": "book_id", - "type": "number", + "type": "string", "required": 1, "default": "", "description": "" @@ -97,21 +90,28 @@ }, "tag": "Default", "batch_operation": 0, - "sql_file": "sql/GET-v1-book-rating.sql", + "sql_file": "sql/GET-v1-book.sql", "type": "sql_endpoint", "return_type": "json" }, { - "name": "book/[id]", + "name": "book/rating", "description": "", - "method": "PUT", - "endpoint": "/v1/book", + "method": "POST", + "endpoint": "/v1/book/rating", "data_source": { "cluster_id": 1379661944634374075 }, "params": [ { - "name": "stock", + "name": "score", + "type": "number", + "required": 1, + "default": "", + "description": "" + }, + { + "name": "user_id", "type": "number", "required": 1, "default": "", @@ -131,22 +131,22 @@ }, "tag": "Default", "batch_operation": 0, - "sql_file": "sql/PUT-v1-book.sql", + "sql_file": "sql/POST-v1-book-rating.sql", "type": "sql_endpoint", "return_type": "json" }, { - "name": "book/[id]", + "name": "book/rating", "description": "", "method": "GET", - "endpoint": "/v1/book", + "endpoint": "/v1/book/rating", "data_source": { "cluster_id": 1379661944634374075 }, "params": [ { "name": "book_id", - "type": "string", + "type": "number", "required": 1, "default": "", "description": "" @@ -158,7 +158,7 @@ }, "tag": "Default", "batch_operation": 0, - "sql_file": "sql/GET-v1-book.sql", + "sql_file": "sql/GET-v1-book-rating.sql", "type": "sql_endpoint", "return_type": "json" }, From ad1ec6ba6d3e9382d4f3ab8c0f6d5f9e7d353561 Mon Sep 17 00:00:00 2001 From: "tidb-cloud-data-service[bot]" <134662589+tidb-cloud-data-service[bot]@users.noreply.github.com> Date: Thu, 3 Aug 2023 06:39:40 +0000 Subject: [PATCH 6/7] Deployment from Data App --- data-service/http_endpoints/config.json | 52 ++++++++++++------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/data-service/http_endpoints/config.json b/data-service/http_endpoints/config.json index 222e8f0..49849fc 100644 --- a/data-service/http_endpoints/config.json +++ b/data-service/http_endpoints/config.json @@ -11,7 +11,7 @@ { "name": "user_id", "type": "number", - "required": 1, + "required": 0, "default": "", "description": "" }, @@ -34,16 +34,23 @@ "return_type": "json" }, { - "name": "book/[id]", + "name": "book/rating", "description": "", - "method": "PUT", - "endpoint": "/v1/book", + "method": "POST", + "endpoint": "/v1/book/rating", "data_source": { "cluster_id": 1379661944634374075 }, "params": [ { - "name": "stock", + "name": "score", + "type": "number", + "required": 1, + "default": "", + "description": "" + }, + { + "name": "user_id", "type": "number", "required": 1, "default": "", @@ -63,22 +70,22 @@ }, "tag": "Default", "batch_operation": 0, - "sql_file": "sql/PUT-v1-book.sql", + "sql_file": "sql/POST-v1-book-rating.sql", "type": "sql_endpoint", "return_type": "json" }, { - "name": "book/[id]", + "name": "book/rating", "description": "", "method": "GET", - "endpoint": "/v1/book", + "endpoint": "/v1/book/rating", "data_source": { "cluster_id": 1379661944634374075 }, "params": [ { "name": "book_id", - "type": "string", + "type": "number", "required": 1, "default": "", "description": "" @@ -90,28 +97,21 @@ }, "tag": "Default", "batch_operation": 0, - "sql_file": "sql/GET-v1-book.sql", + "sql_file": "sql/GET-v1-book-rating.sql", "type": "sql_endpoint", "return_type": "json" }, { - "name": "book/rating", + "name": "book/[id]", "description": "", - "method": "POST", - "endpoint": "/v1/book/rating", + "method": "PUT", + "endpoint": "/v1/book", "data_source": { "cluster_id": 1379661944634374075 }, "params": [ { - "name": "score", - "type": "number", - "required": 1, - "default": "", - "description": "" - }, - { - "name": "user_id", + "name": "stock", "type": "number", "required": 1, "default": "", @@ -131,22 +131,22 @@ }, "tag": "Default", "batch_operation": 0, - "sql_file": "sql/POST-v1-book-rating.sql", + "sql_file": "sql/PUT-v1-book.sql", "type": "sql_endpoint", "return_type": "json" }, { - "name": "book/rating", + "name": "book/[id]", "description": "", "method": "GET", - "endpoint": "/v1/book/rating", + "endpoint": "/v1/book", "data_source": { "cluster_id": 1379661944634374075 }, "params": [ { "name": "book_id", - "type": "number", + "type": "string", "required": 1, "default": "", "description": "" @@ -158,7 +158,7 @@ }, "tag": "Default", "batch_operation": 0, - "sql_file": "sql/GET-v1-book-rating.sql", + "sql_file": "sql/GET-v1-book.sql", "type": "sql_endpoint", "return_type": "json" }, From 6da97442f994af21403cc52dc929cecf22fc2285 Mon Sep 17 00:00:00 2001 From: czhen <56986964+shczhen@users.noreply.github.com> Date: Thu, 3 Aug 2023 15:34:38 +0800 Subject: [PATCH 7/7] add dataservice examples --- README-DATASERVICE.md | 66 +++++++++++++++++++++++++++ package.json | 3 ++ pages/api/data-service/book/[id].ts | 49 ++++++++++++++++++++ pages/api/data-service/book/rating.ts | 63 +++++++++++++++++++++++++ pages/api/data-service/books.ts | 20 ++++++++ yarn.lock | 59 ++++++++++++++++++++++++ 6 files changed, 260 insertions(+) create mode 100644 README-DATASERVICE.md create mode 100644 pages/api/data-service/book/[id].ts create mode 100644 pages/api/data-service/book/rating.ts create mode 100644 pages/api/data-service/books.ts diff --git a/README-DATASERVICE.md b/README-DATASERVICE.md new file mode 100644 index 0000000..72270f7 --- /dev/null +++ b/README-DATASERVICE.md @@ -0,0 +1,66 @@ +# TiDB Cloud Data Service + +[About TiDB Cloud Data Service (Beta)](https://docs.pingcap.com/tidbcloud/data-service-overview) + +> TiDB Cloud provides a Data Service (beta) feature that enables you to access TiDB Cloud data via an HTTPS request using a custom API endpoint. This feature uses a serverless architecture to handle computing resources and elastic scaling, so you can focus on the query logic in endpoints without worrying about infrastructure or maintenance costs. + +We will introduce how to add some Data Service API examples to the existing Bookshop demo. + +## Prerequisites + +- Create a [TiDB Cloud](https://tidbcloud.com/) account and get your free trial cluster. + +- Deploy a Bookshop demo on Vercel. You can follow the [README](./README.md) to deploy the demo. + +- All the Data Service configurations are under the `data-service` folder. You can follow the official [documentation](https://docs.pingcap.com/tidbcloud/data-service-manage-github-connection#import-configurations-of-an-existing-data-app) to set up the environment. + +## Data Service Examples + +### Before you start + +Setup the environment variables: + +```bash +TIDB_CLOUD_DS_PUB_KEY= # The public key of the Data Service +TIDB_CLOUD_DS_PRI_KEY= # The private key of the Data Service +TIDB_CLOUD_DS_ENDPOINT= # The endpoint of the Data Service +``` + +### Example 1: Query the data of a table + +SQL is defined in [`data-service/http_endpoints/sql/GET-v1-book.sql`](data-service/http_endpoints/sql/GET-v1-book.sql): + +```sql +USE bookshop; + +SELECT + b.id, + b.title, + b.type, + b.published_at, + b.stock, + b.price, + r.score, + a.name +FROM + `books` AS b + JOIN `ratings` AS r ON b.id = r.book_id + JOIN `book_authors` AS ba ON b.id = ba.book_id + JOIN `authors` AS a ON ba.author_id = a.id +WHERE b.id = ${book_id} +LIMIT 1 +``` + +The `book_id` is a parameter in the URL. The Data Service will replace `${book_id}` with the value in the URL. + +API is defined in [`pages/api/data-service/book/[id].ts`](pages/api/data-service/book/[id].ts): + +```typescript +// handle GET request +if (req.method === 'GET') { + const url = process.env?.TIDB_CLOUD_DS_ENDPOINT + `/v1/book?book_id=${id}`; + const data = await client.fetch(url).then((res) => res.json()); + res.status(200).json(data); + return; +} +``` diff --git a/package.json b/package.json index 8845727..45a3082 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,9 @@ "@mui/material": "^5.9.2", "@prisma/client": "^4.5.0", "axios": "^1.1.3", + "digest-fetch": "^3.1.0", "dotenv": "^16.0.3", + "lodash": "^4.17.21", "next": "12.2.2", "notistack": "^2.0.5", "react": "18.2.0", @@ -26,6 +28,7 @@ "recoil": "^0.7.5" }, "devDependencies": { + "@types/lodash": "^4.14.196", "@types/node": "^18.6.3", "@types/react": "^18.0.15", "@types/react-dom": "^18.0.6", diff --git a/pages/api/data-service/book/[id].ts b/pages/api/data-service/book/[id].ts new file mode 100644 index 0000000..5901e95 --- /dev/null +++ b/pages/api/data-service/book/[id].ts @@ -0,0 +1,49 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import DigestClient from 'digest-fetch'; +import _ from 'lodash'; + +const handler = async (req: NextApiRequest, res: NextApiResponse) => { + const client = new DigestClient( + process.env?.TIDB_CLOUD_DS_PUB_KEY, + process.env?.TIDB_CLOUD_DS_PRI_KEY, + { basic: true } + ); + + const { id } = req.query; + + if (!id) { + res.status(400).json({ error: 'Missing book ID' }); + return; + } + + // handle GET request + if (req.method === 'GET') { + const url = process.env?.TIDB_CLOUD_DS_ENDPOINT + `/v1/book?book_id=${id}`; + const data = await client.fetch(url).then((res) => res.json()); + res.status(200).json(data); + return; + } else if (req.method === 'PUT') { + // handle PUT request + const url = process.env?.TIDB_CLOUD_DS_ENDPOINT + `/v1/book?book_id=${id}`; + const { stock } = req.body; + if (_.isNumber(stock)) { + const data = await client + .fetch(url, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ stock, book_id: id }), + }) + .then((res) => res.json()); + res.status(200).json(data); + return; + } + res.status(400).json({ error: 'Missing stock' }); + return; + } + + res.status(400).json({ error: 'Invalid request method' }); +}; + +export default handler; diff --git a/pages/api/data-service/book/rating.ts b/pages/api/data-service/book/rating.ts new file mode 100644 index 0000000..f0072de --- /dev/null +++ b/pages/api/data-service/book/rating.ts @@ -0,0 +1,63 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import DigestClient from 'digest-fetch'; + +const handler = async (req: NextApiRequest, res: NextApiResponse) => { + const client = new DigestClient( + process.env?.TIDB_CLOUD_DS_PUB_KEY, + process.env?.TIDB_CLOUD_DS_PRI_KEY, + { basic: true } + ); + + const url = process.env?.TIDB_CLOUD_DS_ENDPOINT + `/v1/book/rating`; + + if (req.method === 'GET') { + const { book_id } = req.query; + if (!book_id) { + res.status(400).json({ error: 'Missing book ID' }); + return; + } + const data = await client + .fetch(url + `?book_id=${book_id}`) + .then((res) => res.json()); + res.status(200).json(data); + return; + } else if (req.method === 'POST') { + const { book_id, score, user_id } = req.body; + if (!book_id || !score || !user_id) { + res.status(400).json({ error: 'Missing book ID or score or user ID' }); + return; + } + const data = await client + .fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ book_id, score, user_id }), + }) + .then((res) => res.json()); + res.status(200).json(data); + return; + // } else if (req.method === 'DELETE') { + // const { book_id, user_id } = req.body; + // if (!book_id || !user_id) { + // res.status(400).json({ error: 'Missing book ID or user ID' }); + // return; + // } + // const data = await client + // .fetch(url, { + // method: 'DELETE', + // headers: { + // 'Content-Type': 'application/json', + // }, + // body: JSON.stringify({ user_id, book_id }), + // }) + // .then((res) => res.json()); + // res.status(200).json(data); + // return; + } + + res.status(400).json({ error: 'Invalid request method' }); +}; + +export default handler; diff --git a/pages/api/data-service/books.ts b/pages/api/data-service/books.ts new file mode 100644 index 0000000..55a0cf8 --- /dev/null +++ b/pages/api/data-service/books.ts @@ -0,0 +1,20 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import DigestClient from 'digest-fetch'; + +const handler = async (req: NextApiRequest, res: NextApiResponse) => { + const client = new DigestClient( + process.env?.TIDB_CLOUD_DS_PUB_KEY, + process.env?.TIDB_CLOUD_DS_PRI_KEY, + { basic: true } + ); + + const url = process.env?.TIDB_CLOUD_DS_ENDPOINT + `/v1/books`; + + const data = await client.fetch(url).then((res) => res.json()); + + console.log(data); + + res.status(200).json(data); +}; + +export default handler; diff --git a/yarn.lock b/yarn.lock index 1099edf..02f03b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -443,6 +443,11 @@ resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== +"@types/lodash@^4.14.196": + version "4.14.196" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.196.tgz#a7c3d6fc52d8d71328b764e28e080b4169ec7a95" + integrity sha512-22y3o88f4a94mKljsZcanlNWPzO0uBsBdzLAngf2tp533LzZcQzb6+eZPJ+vCTt+bqF2XnvT9gejTLsAcJAJyQ== + "@types/node@^18.6.3": version "18.6.5" resolved "https://registry.npmjs.org/@types/node/-/node-18.6.5.tgz" @@ -668,6 +673,11 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base-64@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/base-64/-/base-64-0.1.0.tgz#780a99c84e7d600260361511c4877613bf24f6bb" + integrity sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" @@ -718,6 +728,11 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +charenc@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + integrity sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA== + clsx@^1.1.0, clsx@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz" @@ -791,6 +806,11 @@ cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" +crypt@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== + csstype@^3.0.2, csstype@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz" @@ -840,6 +860,16 @@ delayed-stream@~1.0.0: resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== +digest-fetch@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/digest-fetch/-/digest-fetch-3.1.0.tgz#d471018c2f688c31d6df53b4999112e4c6dd5c8b" + integrity sha512-FBsj/E0CkZ8cQddUdUBIt3r8fVXZFwnGphQDGUlHkdCVW07+y+PUiYSb1QBVW2n8z7PxXYoCYVMPT1XhvHgDfQ== + dependencies: + base-64 "^0.1.0" + js-sha256 "^0.9.0" + js-sha512 "^0.8.0" + md5 "^2.3.0" + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" @@ -1448,6 +1478,11 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" +is-buffer@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + is-callable@^1.1.4, is-callable@^1.2.4: version "1.2.4" resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz" @@ -1537,6 +1572,16 @@ isexe@^2.0.0: resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +js-sha256@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966" + integrity sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA== + +js-sha512@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha512/-/js-sha512-0.8.0.tgz#dd22db8d02756faccf19f218e3ed61ec8249f7d4" + integrity sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" @@ -1617,6 +1662,11 @@ lodash.merge@^4.6.2: resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" @@ -1631,6 +1681,15 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +md5@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g== + dependencies: + charenc "0.0.2" + crypt "0.0.2" + is-buffer "~1.1.6" + merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"