diff --git a/README.md b/README.md index f7752a59..672eb42c 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ custom: request: # request mapping template name response: # response mapping template name - ${file({fileLocation}.yml)} # link to a file with arrays of mapping templates - schema: # defaults schema.graphql + schema: # schema file or array of files to merge, defaults to schema.graphql dataSources: - type: AMAZON_DYNAMODB name: # data source name diff --git a/__snapshots__/get-config.test.js.snap b/__snapshots__/get-config.test.js.snap index ce0337fd..ff6e5b14 100644 --- a/__snapshots__/get-config.test.js.snap +++ b/__snapshots__/get-config.test.js.snap @@ -1,5 +1,199 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Schema as array 1`] = ` +Object { + "apiId": undefined, + "apiKey": undefined, + "authenticationType": "AWS_IAM", + "dataSources": Array [], + "functionConfigurations": Array [], + "functionConfigurationsLocation": "mapping-templates", + "isSingleConfig": true, + "logConfig": undefined, + "mappingTemplates": Array [], + "mappingTemplatesLocation": "mapping-templates", + "name": "api", + "openIdConnectConfig": undefined, + "region": "us-east-1", + "schema": "schema { + query: Query + mutation: Mutation + subscription: Subscription +} + +type Query { + # search functionality is available in elasticsearch integration + searchAllTweetsByKeyword(keyword: String!): TweetConnection + getUserInfo(handle: String!, consumer_key: String, consumer_secret: String): User! + meInfo(consumer_key: String, consumer_secret: String): User! +} + +type Mutation { + # Create a tweet for a user + # consumer keys and tokens are not required for dynamo integration + createTweet(tweet: String!, consumer_key: String, consumer_secret: String, access_token_key: String, access_token_secret: String, created_at: String!): Tweet! + # Delete User Tweet + deleteTweet(tweet_id: String!, consumer_key: String, consumer_secret: String, access_token_key: String, access_token_secret: String): Tweet! + # Retweet existing Tweet + reTweet(tweet_id: String!, consumer_key: String, consumer_secret: String, access_token_key: String, access_token_secret: String): Tweet! + # Update existing Tweet + updateTweet(tweet_id: String!, tweet: String!): Tweet! + # Create user info is available in dynamo integration + updateUserInfo(location: String!, description: String!, name: String!, followers_count: Int!, friends_count: Int!, favourites_count: Int!, followers: [String!]!): User! +} + +type Subscription { + addTweet: Tweet @aws_subscribe(mutations: [\\"createTweet\\"]) +} + +type Tweet { + tweet_id: String! + tweet: String! + retweeted: Boolean + retweet_count: Int + favorited: Boolean + created_at: String! +} + +type TweetConnection { + items: [Tweet!]! + nextToken: String +} + +type User { + name: String! + handle: String! + location: String! + description: String! + followers_count: Int! + friends_count: Int! + favourites_count: Int! + followers: [String!]! + topTweet: Tweet + tweets(limit: Int!, nextToken: String): TweetConnection + # search functionality is available in elasticsearch integration + searchTweetsByKeyword(keyword: String!): TweetConnection +} +", + "substitutions": Object {}, + "userPoolConfig": undefined, +} +`; + +exports[`Schema as string 1`] = ` +Object { + "apiId": undefined, + "apiKey": undefined, + "authenticationType": "AWS_IAM", + "dataSources": Array [], + "functionConfigurations": Array [], + "functionConfigurationsLocation": "mapping-templates", + "isSingleConfig": true, + "logConfig": undefined, + "mappingTemplates": Array [], + "mappingTemplatesLocation": "mapping-templates", + "name": "api", + "openIdConnectConfig": undefined, + "region": "us-east-1", + "schema": "type Mutation { + # Create a tweet for a user + # consumer keys and tokens are not required for dynamo integration + createTweet( + tweet: String!, + consumer_key: String, + consumer_secret: String, + access_token_key: String, + access_token_secret: String, + created_at: String! + ): Tweet! + + # Delete User Tweet + deleteTweet( + tweet_id: String!, + consumer_key: String, + consumer_secret: String, + access_token_key: String, + access_token_secret: String + ): Tweet! + + # Retweet existing Tweet + reTweet( + tweet_id: String!, + consumer_key: String, + consumer_secret: String, + access_token_key: String, + access_token_secret: String + ): Tweet! + + # Update existing Tweet + updateTweet(tweet_id: String!, tweet: String!): Tweet! + + # Create user info is available in dynamo integration + updateUserInfo( + location: String!, + description: String!, + name: String!, + followers_count: Int!, + friends_count: Int!, + favourites_count: Int!, + followers: [String!]! + ): User! +} + +type Query { + meInfo(consumer_key: String, consumer_secret: String): User! + getUserInfo(handle: String!, consumer_key: String, consumer_secret: String): User! + + # search functionality is available in elasticsearch integration + searchAllTweetsByKeyword(keyword: String!): TweetConnection +} + +type Subscription { + addTweet: Tweet + @aws_subscribe(mutations: [\\"createTweet\\"]) +} + +type Tweet { + tweet_id: String! + tweet: String! + retweeted: Boolean + retweet_count: Int + favorited: Boolean + created_at: String! +} + +type TweetConnection { + items: [Tweet!]! + nextToken: String +} + +type User { + name: String! + handle: String! + location: String! + description: String! + followers_count: Int! + friends_count: Int! + favourites_count: Int! + followers: [String!]! + topTweet: Tweet + tweets(limit: Int!, nextToken: String): TweetConnection + + # search functionality is available in elasticsearch integration + searchTweetsByKeyword(keyword: String!): TweetConnection +} + +schema { + query: Query + mutation: Mutation + subscription: Subscription +} +", + "substitutions": Object {}, + "userPoolConfig": undefined, +} +`; + exports[`authenticationType is missing 1`] = `"appSync property \`authenticationType\` is missing or invalid."`; exports[`authenticationType is missing 2`] = `"appSync property \`authenticationType\` is missing or invalid."`; diff --git a/example/_type_tweet.graphql b/example/_type_tweet.graphql new file mode 100644 index 00000000..8250a026 --- /dev/null +++ b/example/_type_tweet.graphql @@ -0,0 +1,63 @@ +type Mutation { + # Create a tweet for a user + # consumer keys and tokens are not required for dynamo integration + createTweet( + tweet: String!, + consumer_key: String, + consumer_secret: String, + access_token_key: String, + access_token_secret: String, + created_at: String! + ): Tweet! + + # Delete User Tweet + deleteTweet( + tweet_id: String!, + consumer_key: String, + consumer_secret: String, + access_token_key: String, + access_token_secret: String + ): Tweet! + + # Retweet existing Tweet + reTweet( + tweet_id: String!, + consumer_key: String, + consumer_secret: String, + access_token_key: String, + access_token_secret: String + ): Tweet! + + # Update existing Tweet + updateTweet(tweet_id: String!, tweet: String!): Tweet! + +} + +type Query { + # search functionality is available in elasticsearch integration + searchAllTweetsByKeyword(keyword: String!): TweetConnection +} + +type Subscription { + addTweet: Tweet @aws_subscribe(mutations: ["createTweet"]) +} + +type Tweet { + tweet_id: String! + tweet: String! + retweeted: Boolean + retweet_count: Int + favorited: Boolean + created_at: String! +} + +type TweetConnection { + items: [Tweet!]! + nextToken: String +} + +schema { + query: Query + mutation: Mutation + subscription: Subscription +} diff --git a/example/_type_user.graphql b/example/_type_user.graphql new file mode 100644 index 00000000..2fa50e7b --- /dev/null +++ b/example/_type_user.graphql @@ -0,0 +1,34 @@ +type Mutation { + # Create user info is available in dynamo integration + updateUserInfo( + location: String!, + description: String!, + name: String!, + followers_count: Int!, + friends_count: Int!, + favourites_count: Int!, + followers: [String!]! + ): User! +} + +type Query { + getUserInfo(handle: String!, consumer_key: String, consumer_secret: String): User! + meInfo(consumer_key: String, consumer_secret: String): User! +} + +type User { + name: String! + handle: String! + location: String! + description: String! + followers_count: Int! + friends_count: Int! + favourites_count: Int! + followers: [String!]! + topTweet: Tweet + tweets(limit: Int!, nextToken: String): TweetConnection + + # search functionality is available in elasticsearch integration + searchTweetsByKeyword(keyword: String!): TweetConnection +} + diff --git a/get-config.js b/get-config.js index 50263e8f..b45aab14 100644 --- a/get-config.js +++ b/get-config.js @@ -1,5 +1,6 @@ const fs = require('fs'); const path = require('path'); +const { mergeTypes } = require('merge-graphql-schemas'); const { mapObjIndexed, pipe, values, merge, } = require('ramda'); @@ -39,15 +40,14 @@ const getConfig = (config, provider, servicePath) => { const functionConfigurations = config.functionConfigurations || []; const mappingTemplates = config.mappingTemplates || []; - const schemaPath = path.join( - servicePath, - config.schema || 'schema.graphql', - ); + const readSchemaFile = + (schemaRelPath) => fs.readFileSync(path.join(servicePath, schemaRelPath), {encoding: 'utf8'}); + + const schemaContent = + Array.isArray(config.schema) ? + mergeTypes(config.schema.map(readSchemaFile)) : + readSchemaFile(config.schema || 'schema.graphql'); - const schemaContent = fs.readFileSync(schemaPath, { - encoding: 'utf8', - }); - let dataSources = []; if (Array.isArray(config.dataSources)) { dataSources = config.dataSources.reduce( diff --git a/get-config.test.js b/get-config.test.js index 31cb14d2..838f5625 100644 --- a/get-config.test.js +++ b/get-config.test.js @@ -86,4 +86,28 @@ test('datasources as array form different files (array of arrays or objects)', ( { region: 'us-east-1' }, servicePath )[0]).toMatchSnapshot(); -}); \ No newline at end of file +}); + +test('Schema as string', () => { + + expect(getConfig( + { + authenticationType: 'AWS_IAM', + schema: 'schema.graphql' + }, + { region: 'us-east-1' }, + servicePath + )[0]).toMatchSnapshot(); +}); + +test('Schema as array', () => { + + expect(getConfig( + { + authenticationType: 'AWS_IAM', + schema: ['_type_tweet.graphql', '_type_user.graphql'] + }, + { region: 'us-east-1' }, + servicePath + )[0]).toMatchSnapshot(); +}); diff --git a/package.json b/package.json index 4ca9e93e..30f603d1 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "graphql": "^0.13.2", "graphql-playground-middleware-koa": "^1.6.4", "koa": "^2.5.2", + "merge-graphql-schemas": "^1.5.8", "ramda": "^0.25.0" }, "peerDependencies": {}, diff --git a/yarn.lock b/yarn.lock index ce153fea..6ce2b126 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1140,6 +1140,11 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +deepmerge@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170" + integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA== + default-require-extensions@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" @@ -2445,6 +2450,11 @@ is-extglob@^1.0.0: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" integrity sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA= +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + is-finite@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" @@ -2481,6 +2491,13 @@ is-glob@^2.0.0, is-glob@^2.0.1: dependencies: is-extglob "^1.0.0" +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + integrity sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A= + dependencies: + is-extglob "^2.1.1" + is-installed-globally@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" @@ -3414,6 +3431,15 @@ mem@^1.1.0: dependencies: mimic-fn "^1.0.0" +merge-graphql-schemas@^1.5.8: + version "1.5.8" + resolved "https://registry.yarnpkg.com/merge-graphql-schemas/-/merge-graphql-schemas-1.5.8.tgz#89457b60312aabead44d5b2b7625643f8ab9e369" + integrity sha512-0TGOKebltvmWR9h9dPYS2vAqMPThXwJ6gVz7O5MtpBp2sunAg/M25iMSNI7YhU6PDJVtGtldTfqV9a+55YhB+A== + dependencies: + deepmerge "^2.2.1" + glob "^7.1.3" + is-glob "^4.0.0" + merge-stream@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1"