From f45e61891add0a350227aa2f721c54d884969408 Mon Sep 17 00:00:00 2001 From: asararatnakar Date: Wed, 29 Jan 2025 14:40:02 -0500 Subject: [PATCH 1/7] chore: example for setters argument for @rest directive Signed-off-by: asararatnakar --- transforms/README.md | 1 + transforms/jsonobjectToJsonarray/api.graphql | 10 ------ transforms/setters/api.graphql | 34 ++++++++++++++++++++ transforms/setters/index.graphql | 3 ++ transforms/setters/stepzen.config.json | 3 ++ transforms/setters/tests/Test.js | 12 +++++++ 6 files changed, 53 insertions(+), 10 deletions(-) create mode 100644 transforms/setters/api.graphql create mode 100644 transforms/setters/index.graphql create mode 100644 transforms/setters/stepzen.config.json create mode 100644 transforms/setters/tests/Test.js diff --git a/transforms/README.md b/transforms/README.md index 527c673..0ad010e 100644 --- a/transforms/README.md +++ b/transforms/README.md @@ -10,3 +10,4 @@ For more on what `transforms` is and how it operates within the custom `@rest` d - [combineintostring](combineintostring) shows how a new field in the return type can be created by concatenating some other fields (like address parts into one address) - [jsonarrayToJsonobject](jsonarrayToJsonobject) shows how an array of data (say coords) can be converted into an object, `{"lat":, "lon",..}` so that it can be fed into some other system that requires data to be expressed that way - [jsonobjectToJsonarray](jsonobjectToJsonarray) shows how an object (typically where each key is an id of a record) can be converted into an array (e.g., `{"1":{"name": "john"}, "2": "jane"}` can be converted to `[{"id":"1", "name": "john"}, {"id":"2", name: "jane"}]`), so that it can then behave well for GraphQL processing. +- [setters](setters) shows how to map a JSON response values to the fields of the GraphQL type. \ No newline at end of file diff --git a/transforms/jsonobjectToJsonarray/api.graphql b/transforms/jsonobjectToJsonarray/api.graphql index 7e71d44..f896745 100644 --- a/transforms/jsonobjectToJsonarray/api.graphql +++ b/transforms/jsonobjectToJsonarray/api.graphql @@ -58,20 +58,10 @@ type Query { # StepZen takes care of calling jq for each element. transforms: [ { pathpattern: ["<>*"], editor: "objectToArray" } - # you could comment this out if you want to try setters instead { pathpattern: ["[]*"] editor: "jq:.[]|{id:.name,fullName:.value.fullName,age:.value.age}" } ] - - # for the second transformation, you can use setters. Uncomment the next line and comment the second pathpattern line above to see how it operates. - # In order to make this to work, change the return type from JSON to [Customer]. - - # setters: [ - # { field: "id", path: "name" } - # { field: "fullName", path: "value.fullName" } - # { field: "age", path: "value.age" } - # ] ) } diff --git a/transforms/setters/api.graphql b/transforms/setters/api.graphql new file mode 100644 index 0000000..ce48c73 --- /dev/null +++ b/transforms/setters/api.graphql @@ -0,0 +1,34 @@ +# We first transform the JSON result object from REST API the Graphql structure +# and then map the JSON response to the fields corresponding to the GraphQL type. + +type Customer { + cId: ID + cName: String + cAddress: Address +} +type Address { + city: String + countryRegion: String + stateProvince: String + street: String + postalCode: String +} + +type Query { + customer(id: ID): [Customer] + @rest( + endpoint: "https://json2api-customers-zlwadjbovq-uc.a.run.app/customers?q=id+eq+$id;" + # The jq expression transform each element of the array. + # StepZen takes care of calling jq for each element. + transforms: [ + { + pathpattern: [] + editor: """ + jq:.[]|{id,name,cAddress:{street, city, stateProvince, countryRegion}} + """ + } + ] + # mapping from JSON response values to the fields of the GraphQL result. + setters: [{ field: "cId", path: "id" }, { field: "cName", path: "name" }] + ) +} diff --git a/transforms/setters/index.graphql b/transforms/setters/index.graphql new file mode 100644 index 0000000..956ed98 --- /dev/null +++ b/transforms/setters/index.graphql @@ -0,0 +1,3 @@ +schema @sdl(files: ["api.graphql"]) { + query: Query +} diff --git a/transforms/setters/stepzen.config.json b/transforms/setters/stepzen.config.json new file mode 100644 index 0000000..abe76e9 --- /dev/null +++ b/transforms/setters/stepzen.config.json @@ -0,0 +1,3 @@ +{ + "endpoint": "api/miscellaneous" +} \ No newline at end of file diff --git a/transforms/setters/tests/Test.js b/transforms/setters/tests/Test.js new file mode 100644 index 0000000..53b0db0 --- /dev/null +++ b/transforms/setters/tests/Test.js @@ -0,0 +1,12 @@ +const { + deployAndRun, + getTestDescription, +} = require("../../../tests/gqltest.js"); + +testDescription = getTestDescription("snippets", __dirname); + +describe(testDescription, function () { + const tests = [ + ] + return deployAndRun(__dirname, tests); +}); \ No newline at end of file From c3552b24db96e980d86454873028420c37256c86 Mon Sep 17 00:00:00 2001 From: asararatnakar Date: Wed, 29 Jan 2025 14:44:29 -0500 Subject: [PATCH 2/7] prettify Signed-off-by: asararatnakar --- transforms/setters/api.graphql | 2 +- transforms/setters/stepzen.config.json | 2 +- transforms/setters/tests/Test.js | 5 ++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/transforms/setters/api.graphql b/transforms/setters/api.graphql index ce48c73..d304f9c 100644 --- a/transforms/setters/api.graphql +++ b/transforms/setters/api.graphql @@ -1,4 +1,4 @@ -# We first transform the JSON result object from REST API the Graphql structure +# We first transform the JSON result object from REST API the Graphql structure # and then map the JSON response to the fields corresponding to the GraphQL type. type Customer { diff --git a/transforms/setters/stepzen.config.json b/transforms/setters/stepzen.config.json index abe76e9..af1c0ea 100644 --- a/transforms/setters/stepzen.config.json +++ b/transforms/setters/stepzen.config.json @@ -1,3 +1,3 @@ { "endpoint": "api/miscellaneous" -} \ No newline at end of file +} diff --git a/transforms/setters/tests/Test.js b/transforms/setters/tests/Test.js index 53b0db0..1596c11 100644 --- a/transforms/setters/tests/Test.js +++ b/transforms/setters/tests/Test.js @@ -6,7 +6,6 @@ const { testDescription = getTestDescription("snippets", __dirname); describe(testDescription, function () { - const tests = [ - ] + const tests = []; return deployAndRun(__dirname, tests); -}); \ No newline at end of file +}); From 10e1c207de401c8db2b24213b89acadd97998e73 Mon Sep 17 00:00:00 2001 From: asararatnakar Date: Thu, 30 Jan 2025 18:39:53 -0500 Subject: [PATCH 3/7] removed the rest call and simulated JSON response as suggested Signed-off-by: asararatnakar --- transforms/setters/api.graphql | 41 +++++++++++++---------- transforms/setters/requests.graphql | 14 ++++++++ transforms/setters/tests/Test.js | 51 +++++++++++++++++++++++++++-- 3 files changed, 87 insertions(+), 19 deletions(-) create mode 100644 transforms/setters/requests.graphql diff --git a/transforms/setters/api.graphql b/transforms/setters/api.graphql index d304f9c..8daa945 100644 --- a/transforms/setters/api.graphql +++ b/transforms/setters/api.graphql @@ -1,34 +1,41 @@ -# We first transform the JSON result object from REST API the Graphql structure -# and then map the JSON response to the fields corresponding to the GraphQL type. +# This example demonstartes mapping a JSON response to the fields of the GraphQL. type Customer { cId: ID cName: String cAddress: Address } + type Address { city: String - countryRegion: String - stateProvince: String + country: String + state: String street: String postalCode: String } type Query { - customer(id: ID): [Customer] + # ecmascript generates customer data to simulate a REST api with a JSON response. + # To verify with a real data source (API or a database) it is required to change the `endpoint` argument on the `@rest` directive. + # https://stepzen.com/docs/connecting-backends/how-to-connect-a-rest-service + customerByID(id: ID!): Customer @rest( - endpoint: "https://json2api-customers-zlwadjbovq-uc.a.run.app/customers?q=id+eq+$id;" - # The jq expression transform each element of the array. - # StepZen takes care of calling jq for each element. - transforms: [ - { - pathpattern: [] - editor: """ - jq:.[]|{id,name,cAddress:{street, city, stateProvince, countryRegion}} - """ - } - ] + endpoint: "stepzen:empty" + ecmascript: """ + function transformREST() { + var id = get('id') + if (id==1) + return ({"address":{"city":"Raleigh","country":"USA","postalCode":"54321","state":"NC","street":"101 Main St"},"id":"12345","name":"John Doe"}) + else + return ({"address":{"city":"Hyderabad","country":"India","postalCode":"654231","state":"TS","street":"J.N.T.U Colony"},"id":"21345","name":"Siddarth A"}) + } + """ + # mapping from JSON response values to the fields of the GraphQL result. - setters: [{ field: "cId", path: "id" }, { field: "cName", path: "name" }] + setters: [ + { field: "cId", path: "id" } # cId mapped to 'id' + { field: "cName", path: "name" } # cName mapped to 'name' + { field: "cAddress", path: "address" } # cAddress mapped to 'address' + ] ) } diff --git a/transforms/setters/requests.graphql b/transforms/setters/requests.graphql new file mode 100644 index 0000000..0a158a7 --- /dev/null +++ b/transforms/setters/requests.graphql @@ -0,0 +1,14 @@ +# maps some of JSON response values to the fields of the GraphQL result. +query CustomerByID($id: ID!) { + customerByID(id: $id) { + cAddress { + city + country + state + street + postalCode + } + cId + cName + } +} diff --git a/transforms/setters/tests/Test.js b/transforms/setters/tests/Test.js index 1596c11..4451d48 100644 --- a/transforms/setters/tests/Test.js +++ b/transforms/setters/tests/Test.js @@ -1,11 +1,58 @@ +const fs = require('fs'); +const path = require("node:path"); const { deployAndRun, + stepzen, getTestDescription, } = require("../../../tests/gqltest.js"); testDescription = getTestDescription("snippets", __dirname); +const requestsFile = path.join(path.dirname(__dirname), 'requests.graphql'); +const requests = fs.readFileSync(requestsFile, 'utf8').toString(); + describe(testDescription, function () { - const tests = []; - return deployAndRun(__dirname, tests); + const tests = [ + { + label: "customer-by-id-1", + query: requests, + operationName: 'CustomerByID', + variables: { id: 1 }, + expected: { + customerByID: { + cAddress: { + city: "Raleigh", + country: "USA", + state: "NC", + street: "101 Main St", + postalCode: "54321" + }, + cId: "12345", + cName: "John Doe" + + } + } + }, + { + label: "customer-by-id-100", + query: requests, + operationName: 'CustomerByID', + variables: { id: 100 }, + expected: { + customerByID: { + cAddress: { + city: "Hyderabad", + country: "India", + state: "TS", + street: "J.N.T.U Colony", + postalCode: "654231" + }, + cId: "21345", + cName: "Siddarth A" + + } + } + } + ] + return deployAndRun(__dirname, tests, stepzen.admin); }); From a2911a42f756111bf1bfa0f49389c5d48d46e680 Mon Sep 17 00:00:00 2001 From: asararatnakar Date: Thu, 30 Jan 2025 18:43:43 -0500 Subject: [PATCH 4/7] update comments Signed-off-by: asararatnakar --- transforms/setters/api.graphql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/transforms/setters/api.graphql b/transforms/setters/api.graphql index 8daa945..866a677 100644 --- a/transforms/setters/api.graphql +++ b/transforms/setters/api.graphql @@ -33,9 +33,9 @@ type Query { # mapping from JSON response values to the fields of the GraphQL result. setters: [ - { field: "cId", path: "id" } # cId mapped to 'id' - { field: "cName", path: "name" } # cName mapped to 'name' - { field: "cAddress", path: "address" } # cAddress mapped to 'address' + { field: "cId", path: "id" } # JSON response field 'id' is mapped to GraphQL 'cId' + { field: "cName", path: "name" } # JSON response field 'name' is mapped to GraphQL 'cName' + { field: "cAddress", path: "address" } # JSON response field 'address' mapped to GraphQL 'cAddress' ] ) } From 72a127854d6b75c6e0d376d50d6a035d9555cc9b Mon Sep 17 00:00:00 2001 From: asararatnakar Date: Thu, 30 Jan 2025 18:54:12 -0500 Subject: [PATCH 5/7] minor edits: Signed-off-by: asararatnakar --- transforms/setters/requests.graphql | 4 +--- transforms/setters/tests/Test.js | 32 ++++++++++++----------------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/transforms/setters/requests.graphql b/transforms/setters/requests.graphql index 0a158a7..3b3672d 100644 --- a/transforms/setters/requests.graphql +++ b/transforms/setters/requests.graphql @@ -3,10 +3,8 @@ query CustomerByID($id: ID!) { customerByID(id: $id) { cAddress { city - country state - street - postalCode + country } cId cName diff --git a/transforms/setters/tests/Test.js b/transforms/setters/tests/Test.js index 4451d48..27db899 100644 --- a/transforms/setters/tests/Test.js +++ b/transforms/setters/tests/Test.js @@ -1,4 +1,4 @@ -const fs = require('fs'); +const fs = require("fs"); const path = require("node:path"); const { deployAndRun, @@ -8,15 +8,15 @@ const { testDescription = getTestDescription("snippets", __dirname); -const requestsFile = path.join(path.dirname(__dirname), 'requests.graphql'); -const requests = fs.readFileSync(requestsFile, 'utf8').toString(); +const requestsFile = path.join(path.dirname(__dirname), "requests.graphql"); +const requests = fs.readFileSync(requestsFile, "utf8").toString(); describe(testDescription, function () { const tests = [ { label: "customer-by-id-1", query: requests, - operationName: 'CustomerByID', + operationName: "CustomerByID", variables: { id: 1 }, expected: { customerByID: { @@ -24,19 +24,16 @@ describe(testDescription, function () { city: "Raleigh", country: "USA", state: "NC", - street: "101 Main St", - postalCode: "54321" }, cId: "12345", - cName: "John Doe" - - } - } + cName: "John Doe", + }, + }, }, { label: "customer-by-id-100", query: requests, - operationName: 'CustomerByID', + operationName: "CustomerByID", variables: { id: 100 }, expected: { customerByID: { @@ -44,15 +41,12 @@ describe(testDescription, function () { city: "Hyderabad", country: "India", state: "TS", - street: "J.N.T.U Colony", - postalCode: "654231" }, cId: "21345", - cName: "Siddarth A" - - } - } - } - ] + cName: "Siddarth A", + }, + }, + }, + ]; return deployAndRun(__dirname, tests, stepzen.admin); }); From 12ed847d5a7e54f588d3ac9acfdd43c92a9aeab9 Mon Sep 17 00:00:00 2001 From: asararatnakar Date: Fri, 31 Jan 2025 11:08:54 -0500 Subject: [PATCH 6/7] address comments Signed-off-by: asararatnakar --- transforms/setters/api.graphql | 18 +++++++++--------- transforms/setters/requests.graphql | 6 +++--- transforms/setters/tests/Test.js | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/transforms/setters/api.graphql b/transforms/setters/api.graphql index 866a677..4303cad 100644 --- a/transforms/setters/api.graphql +++ b/transforms/setters/api.graphql @@ -1,9 +1,9 @@ -# This example demonstartes mapping a JSON response to the fields of the GraphQL. +# This example illustrates how to map a JSON response to the fields of a GraphQL object. type Customer { - cId: ID - cName: String - cAddress: Address + id: ID + name: String + address: Address } type Address { @@ -25,17 +25,17 @@ type Query { function transformREST() { var id = get('id') if (id==1) - return ({"address":{"city":"Raleigh","country":"USA","postalCode":"54321","state":"NC","street":"101 Main St"},"id":"12345","name":"John Doe"}) + return ({"location":{"address":{"city":"Raleigh","country":"USA","postalCode":"54321","state":"NC","street":"101 Main St"}},"customerId":"12345","customerName":"John Doe"}) else - return ({"address":{"city":"Hyderabad","country":"India","postalCode":"654231","state":"TS","street":"J.N.T.U Colony"},"id":"21345","name":"Siddarth A"}) + return ({"location":{"address":{"city":"Hyderabad","country":"India","postalCode":"654231","state":"TS","street":"J.N.T.U Colony"}},"customerId":"21345","customerName":"Siddarth A"}) } """ # mapping from JSON response values to the fields of the GraphQL result. setters: [ - { field: "cId", path: "id" } # JSON response field 'id' is mapped to GraphQL 'cId' - { field: "cName", path: "name" } # JSON response field 'name' is mapped to GraphQL 'cName' - { field: "cAddress", path: "address" } # JSON response field 'address' mapped to GraphQL 'cAddress' + { field: "id", path: "customerId" } # JSON response field 'customerId' is mapped to GraphQL 'id' + { field: "name", path: "customerName" } # JSON response field 'customerName' is mapped to GraphQL 'name' + { field: "address", path: "location.address" } # JSON response nested field 'location.address' mapped to GraphQL 'address' ] ) } diff --git a/transforms/setters/requests.graphql b/transforms/setters/requests.graphql index 3b3672d..bdcf6d9 100644 --- a/transforms/setters/requests.graphql +++ b/transforms/setters/requests.graphql @@ -1,12 +1,12 @@ # maps some of JSON response values to the fields of the GraphQL result. query CustomerByID($id: ID!) { customerByID(id: $id) { - cAddress { + address { city state country } - cId - cName + id + name } } diff --git a/transforms/setters/tests/Test.js b/transforms/setters/tests/Test.js index 27db899..b70ea01 100644 --- a/transforms/setters/tests/Test.js +++ b/transforms/setters/tests/Test.js @@ -20,13 +20,13 @@ describe(testDescription, function () { variables: { id: 1 }, expected: { customerByID: { - cAddress: { + address: { city: "Raleigh", country: "USA", state: "NC", }, - cId: "12345", - cName: "John Doe", + id: "12345", + name: "John Doe", }, }, }, @@ -37,13 +37,13 @@ describe(testDescription, function () { variables: { id: 100 }, expected: { customerByID: { - cAddress: { + address: { city: "Hyderabad", country: "India", state: "TS", }, - cId: "21345", - cName: "Siddarth A", + id: "21345", + name: "Siddarth A", }, }, }, From fe75e1abe9121215144ae7d29e6162e97bdf6d28 Mon Sep 17 00:00:00 2001 From: asararatnakar Date: Fri, 31 Jan 2025 11:13:13 -0500 Subject: [PATCH 7/7] change names to look better Signed-off-by: asararatnakar --- transforms/setters/api.graphql | 2 +- transforms/setters/requests.graphql | 2 +- transforms/setters/tests/Test.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/transforms/setters/api.graphql b/transforms/setters/api.graphql index 4303cad..53458a6 100644 --- a/transforms/setters/api.graphql +++ b/transforms/setters/api.graphql @@ -18,7 +18,7 @@ type Query { # ecmascript generates customer data to simulate a REST api with a JSON response. # To verify with a real data source (API or a database) it is required to change the `endpoint` argument on the `@rest` directive. # https://stepzen.com/docs/connecting-backends/how-to-connect-a-rest-service - customerByID(id: ID!): Customer + customer(id: ID!): Customer @rest( endpoint: "stepzen:empty" ecmascript: """ diff --git a/transforms/setters/requests.graphql b/transforms/setters/requests.graphql index bdcf6d9..108e087 100644 --- a/transforms/setters/requests.graphql +++ b/transforms/setters/requests.graphql @@ -1,6 +1,6 @@ # maps some of JSON response values to the fields of the GraphQL result. query CustomerByID($id: ID!) { - customerByID(id: $id) { + customer(id: $id) { address { city state diff --git a/transforms/setters/tests/Test.js b/transforms/setters/tests/Test.js index b70ea01..2bfb9ed 100644 --- a/transforms/setters/tests/Test.js +++ b/transforms/setters/tests/Test.js @@ -19,7 +19,7 @@ describe(testDescription, function () { operationName: "CustomerByID", variables: { id: 1 }, expected: { - customerByID: { + customer: { address: { city: "Raleigh", country: "USA", @@ -36,7 +36,7 @@ describe(testDescription, function () { operationName: "CustomerByID", variables: { id: 100 }, expected: { - customerByID: { + customer: { address: { city: "Hyderabad", country: "India",