diff --git a/graphql/.env b/graphql/.env new file mode 100644 index 00000000..6009b480 --- /dev/null +++ b/graphql/.env @@ -0,0 +1 @@ +PORT = 4007 diff --git a/graphql/db/data/sap.capire.graphql-Chapters.csv b/graphql/db/data/sap.capire.graphql-Chapters.csv new file mode 100644 index 00000000..cfca7414 --- /dev/null +++ b/graphql/db/data/sap.capire.graphql-Chapters.csv @@ -0,0 +1,4 @@ +book_ID;number;title +201;1;Chapter 1 +201;2;Chapter 2 +201;3;Chapter 3 diff --git a/graphql/db/schema.cds b/graphql/db/schema.cds new file mode 100644 index 00000000..dd65c2bf --- /dev/null +++ b/graphql/db/schema.cds @@ -0,0 +1,15 @@ +using {managed} from '@sap/cds/common'; +using {sap.capire.bookshop} from '@capire/bookshop'; + +namespace sap.capire.graphql; + +extend bookshop.Books with { + chapters : Composition of many Chapters + on chapters.book = $self; +} + +entity Chapters : managed { + key book : Association to bookshop.Books; + key number : Integer; + title : String; +} diff --git a/graphql/examples.http b/graphql/examples.http new file mode 100644 index 00000000..4d479624 --- /dev/null +++ b/graphql/examples.http @@ -0,0 +1 @@ +GET http://localhost:4007/graphql?query={AdminService{Books{title,chapters{number,title}}}} diff --git a/graphql/examples.md b/graphql/examples.md new file mode 100644 index 00000000..ad806297 --- /dev/null +++ b/graphql/examples.md @@ -0,0 +1,16 @@ +1. open `http://localhost:4007/graphql` +2. paste into left field: + ```graphql + { + AdminService { + Books { + title + chapters { + number + title + } + } + } + } + ``` +3. press play button diff --git a/graphql/package.json b/graphql/package.json new file mode 100644 index 00000000..1e91c08d --- /dev/null +++ b/graphql/package.json @@ -0,0 +1,16 @@ +{ + "name": "@capire/graphql", + "version": "1.0.0", + "dependencies": { + "@capire/bookshop": "*", + "@graphql-tools/schema": "^8.3.1", + "@sap/cds": "^5.6", + "express-graphql": "^0.12.0", + "graphql": "^16.0.1" + }, + "cds": { + "features": { + "graphql": true + } + } +} diff --git a/graphql/srv/admin-service.cds b/graphql/srv/admin-service.cds new file mode 100644 index 00000000..7fea54bc --- /dev/null +++ b/graphql/srv/admin-service.cds @@ -0,0 +1,5 @@ +using {sap.capire.graphql} from '../db/schema'; + +extend service AdminService with { + entity Chapters as projection on graphql.Chapters; +} diff --git a/package-lock.json b/package-lock.json index 96c4af28..75e04bd1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,16 @@ "passport": "^0.4.1" } }, + "@capire/graphql": { + "version": "file:graphql", + "requires": { + "@capire/bookshop": "*", + "@graphql-tools/schema": "^8.3.1", + "@sap/cds": "^5.6", + "express-graphql": "^0.12.0", + "graphql": "^16.0.1" + } + }, "@capire/hello": { "version": "file:hello" }, @@ -71,6 +81,34 @@ "kuler": "^2.0.0" } }, + "@graphql-tools/merge": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.2.1.tgz", + "integrity": "sha512-Q240kcUszhXiAYudjuJgNuLgy9CryDP3wp83NOZQezfA6h3ByYKU7xI6DiKrdjyVaGpYN3ppUmdj0uf5GaXzMA==", + "requires": { + "@graphql-tools/utils": "^8.5.1", + "tslib": "~2.3.0" + } + }, + "@graphql-tools/schema": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-8.3.1.tgz", + "integrity": "sha512-3R0AJFe715p4GwF067G5i0KCr/XIdvSfDLvTLEiTDQ8V/hwbOHEKHKWlEBHGRQwkG5lwFQlW1aOn7VnlPERnWQ==", + "requires": { + "@graphql-tools/merge": "^8.2.1", + "@graphql-tools/utils": "^8.5.1", + "tslib": "~2.3.0", + "value-or-promise": "1.0.11" + } + }, + "@graphql-tools/utils": { + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.5.2.tgz", + "integrity": "sha512-wxA51td/759nQziPYh+HxE0WbURRufrp1lwfOYMgfK4e8Aa6gCa1P1p6ERogUIm423NrIfOVau19Q/BBpHdolw==", + "requires": { + "tslib": "~2.3.0" + } + }, "@sap-cloud-sdk/analytics": { "version": "1.51.0", "resolved": "https://registry.npmjs.org/@sap-cloud-sdk/analytics/-/analytics-1.51.0.tgz", @@ -970,6 +1008,66 @@ } } }, + "express-graphql": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/express-graphql/-/express-graphql-0.12.0.tgz", + "integrity": "sha512-DwYaJQy0amdy3pgNtiTDuGGM2BLdj+YO2SgbKoLliCfuHv3VVTt7vNG/ZqK2hRYjtYHE2t2KB705EU94mE64zg==", + "requires": { + "accepts": "^1.3.7", + "content-type": "^1.0.4", + "http-errors": "1.8.0", + "raw-body": "^2.4.1" + }, + "dependencies": { + "http-errors": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.0.tgz", + "integrity": "sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "raw-body": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", + "integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.3", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + } + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + } + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -1176,6 +1274,11 @@ "dev": true, "optional": true }, + "graphql": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.0.1.tgz", + "integrity": "sha512-oPvCuu6dlLdiz8gZupJ47o1clgb72r1u8NDBcQYjcV6G/iEdmE11B1bBlkhXRvV0LisP/SXRFP7tT6AgaTjpzg==" + }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -2428,6 +2531,11 @@ "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" }, + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -2506,6 +2614,11 @@ "resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz", "integrity": "sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA=" }, + "value-or-promise": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.11.tgz", + "integrity": "sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index fbf16378..0370bcd0 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,12 @@ "@capire/bookshop": "./bookshop", "@capire/common": "./common", "@capire/fiori": "./fiori", + "@capire/graphql": "./graphql", "@capire/hello": "./hello", "@capire/media": "./media", "@capire/orders": "./orders", "@capire/reviews": "./reviews", - "@sap/cds": "^5.5.3" + "@sap/cds": "^5.6" }, "devDependencies": { "chai": "^4.3.4",