├── .gitignore ├── LICENSE ├── arango └── setup_database.sh ├── deploy_stack.sh ├── docker-compose.yml └── openfaas ├── build └── openfaas-graphql-blog │ ├── Dockerfile │ ├── build.sh │ ├── function │ ├── .dockerignore │ ├── handler.js │ ├── lib │ │ ├── db.js │ │ ├── index.js │ │ └── schema.js │ ├── package.json │ └── yarn.lock │ ├── index.js │ └── package.json ├── master.zip ├── openfaas-graphql-blog.yml ├── openfaas-graphql-blog ├── .dockerignore ├── handler.js ├── lib │ ├── db.js │ ├── index.js │ └── schema.js ├── package.json └── yarn.lock └── template └── node ├── Dockerfile ├── build.sh ├── function ├── handler.js └── package.json ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/node,macos 3 | 4 | ### macOS ### 5 | *.DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | # Thumbnails 13 | ._* 14 | 15 | # Files that might appear in the root of a volume 16 | .DocumentRevisions-V100 17 | .fseventsd 18 | .Spotlight-V100 19 | .TemporaryItems 20 | .Trashes 21 | .VolumeIcon.icns 22 | .com.apple.timemachine.donotpresent 23 | 24 | # Directories potentially created on remote AFP share 25 | .AppleDB 26 | .AppleDesktop 27 | Network Trash Folder 28 | Temporary Items 29 | .apdisk 30 | 31 | ### Node ### 32 | # Logs 33 | logs 34 | *.log 35 | npm-debug.log* 36 | yarn-debug.log* 37 | yarn-error.log* 38 | 39 | # Runtime data 40 | pids 41 | *.pid 42 | *.seed 43 | *.pid.lock 44 | 45 | # Directory for instrumented libs generated by jscoverage/JSCover 46 | lib-cov 47 | 48 | # Coverage directory used by tools like istanbul 49 | coverage 50 | 51 | # nyc test coverage 52 | .nyc_output 53 | 54 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 55 | .grunt 56 | 57 | # Bower dependency directory (https://bower.io/) 58 | bower_components 59 | 60 | # node-waf configuration 61 | .lock-wscript 62 | 63 | # Compiled binary addons (http://nodejs.org/api/addons.html) 64 | build/Release 65 | 66 | # Dependency directories 67 | node_modules/ 68 | jspm_packages/ 69 | 70 | # Typescript v1 declaration files 71 | typings/ 72 | 73 | # Optional npm cache directory 74 | .npm 75 | 76 | # Optional eslint cache 77 | .eslintcache 78 | 79 | # Optional REPL history 80 | .node_repl_history 81 | 82 | # Output of 'npm pack' 83 | *.tgz 84 | 85 | # Yarn Integrity file 86 | .yarn-integrity 87 | 88 | # dotenv environment variables file 89 | .env 90 | 91 | 92 | # End of https://www.gitignore.io/api/node,macos -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 kenev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /arango/setup_database.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | ARANGODB_DB=graphql-blog 5 | ARANGODB_USERNAME=root 6 | ARANGODB_PASSWORD=openfaasgraphqlblog 7 | ENDPOINT=http://$ARANGODB_USERNAME:$ARANGODB_PASSWORD@localhost:8529 8 | 9 | # create 'graphql-blog' database 10 | curl -X POST --data-binary @- --dump - $ENDPOINT/_api/database <&2 5 | exit 1 6 | fi 7 | 8 | export ARANGODB_DB=graphql-blog 9 | export ARANGODB_USERNAME=root 10 | export ARANGODB_PASSWORD=openfaasgraphqlblog 11 | 12 | echo "Deploying stack" 13 | docker stack deploy func --compose-file docker-compose.yml 14 | 15 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: "3.2" 2 | services: 3 | gateway: 4 | volumes: 5 | - "/var/run/docker.sock:/var/run/docker.sock" 6 | ports: 7 | - 8080:8080 8 | image: functions/gateway:0.6.6-beta 9 | networks: 10 | - functions 11 | environment: 12 | dnsrr: "true" # Temporarily use dnsrr in place of VIP while issue persists on PWD 13 | deploy: 14 | placement: 15 | constraints: 16 | - 'node.role == manager' 17 | - 'node.platform.os == linux' 18 | prometheus: 19 | image: functions/prometheus:latest # autobuild from Dockerfile in repo. 20 | command: "-config.file=/etc/prometheus/prometheus.yml -storage.local.path=/prometheus -storage.local.memory-chunks=10000 --alertmanager.url=http://alertmanager:9093" 21 | ports: 22 | - 9090:9090 23 | depends_on: 24 | - gateway 25 | - alertmanager 26 | environment: 27 | no_proxy: "gateway" 28 | networks: 29 | - functions 30 | deploy: 31 | placement: 32 | constraints: 33 | - 'node.role == manager' 34 | - 'node.platform.os == linux' 35 | 36 | alertmanager: 37 | image: functions/alertmanager:latest # autobuild from Dockerfile in repo. 38 | environment: 39 | no_proxy: "gateway" 40 | # volumes: 41 | # - ./prometheus/alertmanager.yml:/alertmanager.yml 42 | command: 43 | - '-config.file=/alertmanager.yml' 44 | networks: 45 | - functions 46 | ports: 47 | - 9093:9093 48 | deploy: 49 | placement: 50 | constraints: 51 | - 'node.role == manager' 52 | - 'node.platform.os == linux' 53 | 54 | db: 55 | image: arangodb/arangodb:3.2.3 56 | networks: 57 | - functions 58 | ports: 59 | - 8529:8529 60 | environment: 61 | no_proxy: "gateway" 62 | https_proxy: $https_proxy 63 | ARANGO_ROOT_PASSWORD: openfaasgraphqlblog 64 | deploy: 65 | placement: 66 | constraints: 67 | - 'node.platform.os == linux' 68 | 69 | # Service label of "function" allows functions to show up in UI on http://gateway:8080/ 70 | graphqlblog: 71 | image: kenfdev/openfaas-graphql-blog 72 | labels: 73 | function: "true" 74 | depends_on: 75 | - gateway 76 | networks: 77 | - functions 78 | environment: 79 | no_proxy: "gateway" 80 | https_proxy: $https_proxy 81 | ARANGODB_HOST: "db" 82 | ARANGODB_PORT: "8529" 83 | ARANGODB_DB: "${ARANGODB_DB}" 84 | ARANGODB_USERNAME: "${ARANGODB_USERNAME}" 85 | ARANGODB_PASSWORD: "${ARANGODB_PASSWORD}" 86 | deploy: 87 | placement: 88 | constraints: 89 | - 'node.platform.os == linux' 90 | 91 | networks: 92 | functions: 93 | driver: overlay 94 | # Docker does not support this option yet - maybe create outside of the stack and reference as "external"? 95 | #attachable: true 96 | -------------------------------------------------------------------------------- /openfaas/build/openfaas-graphql-blog/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:6.11.2-alpine 2 | 3 | # Alternatively use ADD https:// (which will not be cached by Docker builder) 4 | RUN apk --no-cache add curl \ 5 | && echo "Pulling watchdog binary from Github." \ 6 | && curl -sSL https://github.com/alexellis/faas/releases/download/0.6.1/fwatchdog > /usr/bin/fwatchdog \ 7 | && chmod +x /usr/bin/fwatchdog \ 8 | && apk del curl --no-cache 9 | 10 | WORKDIR /root/ 11 | 12 | # Turn down the verbosity to default level. 13 | ENV NPM_CONFIG_LOGLEVEL warn 14 | 15 | # Wrapper/boot-strapper 16 | COPY package.json . 17 | RUN npm i 18 | 19 | # Function 20 | COPY index.js . 21 | RUN mkdir -p ./root/function 22 | 23 | COPY function/*.json ./function/ 24 | WORKDIR /root/function 25 | RUN npm i || : 26 | WORKDIR /root/ 27 | COPY function function 28 | WORKDIR /root/function 29 | 30 | WORKDIR /root/ 31 | 32 | ENV cgi_headers="true" 33 | 34 | ENV fprocess="node index.js" 35 | 36 | HEALTHCHECK --interval=1s CMD [ -e /tmp/.lock ] || exit 1 37 | 38 | CMD ["fwatchdog"] -------------------------------------------------------------------------------- /openfaas/build/openfaas-graphql-blog/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Building functions/base:node-6.9.1-alpine" 4 | docker build -t functions/base:node-6.9.1-alpine . 5 | 6 | -------------------------------------------------------------------------------- /openfaas/build/openfaas-graphql-blog/function/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /openfaas/build/openfaas-graphql-blog/function/handler.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | // Require Logic 4 | var lib = require('./lib'); 5 | 6 | module.exports = (context, callback) => { 7 | const event = JSON.parse(context); 8 | 9 | lib.runGraphQL(event, (err, response) => { 10 | callback(err, response); 11 | }) 12 | 13 | } -------------------------------------------------------------------------------- /openfaas/build/openfaas-graphql-blog/function/lib/db.js: -------------------------------------------------------------------------------- 1 | const { 2 | Database, 3 | aql 4 | } = require('arangojs'); 5 | const Promise = require('bluebird'); 6 | 7 | // Using a complex connection string with authentication 8 | const host = process.env.ARANGODB_HOST; 9 | const port = process.env.ARANGODB_PORT; 10 | const database = process.env.ARANGODB_DB; 11 | const username = process.env.ARANGODB_USERNAME; 12 | const password = process.env.ARANGODB_PASSWORD; 13 | 14 | const db = new Database({ 15 | url: `http://${username}:${password}@${host}:${port}`, 16 | databaseName: database 17 | }); 18 | 19 | const postsTable = 'posts' 20 | const authorsTable = 'authors' 21 | const commentsTable = 'comments' 22 | 23 | function createAuthor(author) { 24 | return new Promise(function (resolve, reject) { 25 | const collection = db.collection(authorsTable); 26 | collection.save(author, { 27 | returnNew: true 28 | }) 29 | .then(result => resolve(Object.assign(result.new, { 30 | id: result._key 31 | }))) 32 | .catch(err => reject(err)); 33 | 34 | }); 35 | } 36 | 37 | function createPost(post) { 38 | return new Promise(function (resolve, reject) { 39 | const collection = db.collection(postsTable); 40 | collection.save(post, { 41 | returnNew: true 42 | }) 43 | .then(result => resolve(Object.assign(result.new, { 44 | id: result._key 45 | }))) 46 | .catch(err => reject(err)); 47 | 48 | }); 49 | } 50 | 51 | function createComment(comment) { 52 | return new Promise(function (resolve, reject) { 53 | const collection = db.collection(commentsTable); 54 | collection.save(comment, { 55 | returnNew: true 56 | }) 57 | .then(result => resolve(Object.assign(result.new, { 58 | id: result._key 59 | }))) 60 | .catch(err => reject(err)); 61 | 62 | }); 63 | } 64 | 65 | function getPosts(authorId) { 66 | return new Promise(function (resolve, reject) { 67 | const collection = db.collection(postsTable); 68 | 69 | collection.byExample({ 70 | "author": authorId 71 | }) 72 | .then(c => c.all()) 73 | .then(results => { 74 | const formatted = results.map(result => Object.assign(result, { 75 | id: result._key 76 | })) 77 | resolve(formatted); 78 | }) 79 | .catch(err => reject(err)); 80 | 81 | }); 82 | } 83 | 84 | function getAuthor(id) { 85 | return new Promise(function (resolve, reject) { 86 | const collection = db.collection(authorsTable); 87 | collection.firstExample({ 88 | _key: id 89 | }) 90 | .then(result => resolve(Object.assign(result, { 91 | id: id 92 | }))) 93 | .catch(err => reject(err)); 94 | 95 | }); 96 | } 97 | 98 | function getAuthors() { 99 | return new Promise(function (resolve, reject) { 100 | const collection = db.collection(authorsTable); 101 | collection.all() 102 | .then(c => c.all()) 103 | .then(results => { 104 | const formatted = results.map(result => Object.assign(result, { 105 | id: result._key 106 | })) 107 | resolve(formatted); 108 | }) 109 | .catch(err => reject(err)); 110 | }); 111 | } 112 | 113 | function getComments(postId) { 114 | return new Promise(function (resolve, reject) { 115 | const collection = db.collection(commentsTable); 116 | collection.byExample({ 117 | "post": postId 118 | }) 119 | .then(c => c.all()) 120 | .then(results => { 121 | const formatted = results.map(result => Object.assign(result, { 122 | id: result._key 123 | })) 124 | resolve(formatted); 125 | }) 126 | .catch(err => reject(err)); 127 | }); 128 | } 129 | 130 | module.exports = { 131 | createPost, 132 | createComment, 133 | createAuthor, 134 | getPosts, 135 | getAuthor, 136 | getAuthors, 137 | getComments, 138 | } -------------------------------------------------------------------------------- /openfaas/build/openfaas-graphql-blog/function/lib/index.js: -------------------------------------------------------------------------------- 1 | const { 2 | graphql 3 | } = require('graphql'); 4 | const { 5 | Schema 6 | } = require('./schema'); 7 | 8 | function runGraphQL(event, cb) { 9 | 10 | let query = event.query; 11 | 12 | graphql(Schema, query).then(function (result) { 13 | return cb(null, result); 14 | }).catch(error => { 15 | const e = { 16 | errors: [{ 17 | message: error.message, 18 | state: error.originalError && error.originalError.state, 19 | locations: error.locations, 20 | path: error.path, 21 | }] 22 | } 23 | return cb(JSON.stringify(e), null); 24 | }); 25 | 26 | } 27 | 28 | module.exports = { 29 | runGraphQL, 30 | } -------------------------------------------------------------------------------- /openfaas/build/openfaas-graphql-blog/function/lib/schema.js: -------------------------------------------------------------------------------- 1 | const { 2 | GraphQLObjectType, 3 | GraphQLSchema, 4 | GraphQLList, 5 | GraphQLString, 6 | GraphQLNonNull 7 | } = require('graphql'); 8 | 9 | const { 10 | GraphQLLimitedString 11 | } = require('graphql-custom-types'); 12 | 13 | const { 14 | getPosts, 15 | getAuthor, 16 | getAuthors, 17 | getComments, 18 | createPost, 19 | createComment, 20 | createAuthor, 21 | } = require('./db'); 22 | 23 | const Author = new GraphQLObjectType({ 24 | name: "Author", 25 | description: "Author of the blog post", 26 | fields: () => ({ 27 | id: { 28 | type: GraphQLString 29 | }, 30 | name: { 31 | type: GraphQLString 32 | } 33 | }) 34 | }); 35 | 36 | const Comment = new GraphQLObjectType({ 37 | name: "Comment", 38 | description: "Comment on the blog post", 39 | fields: () => ({ 40 | id: { 41 | type: GraphQLString 42 | }, 43 | content: { 44 | type: GraphQLString 45 | }, 46 | author: { 47 | type: Author, 48 | resolve: function ({ 49 | author 50 | }) { 51 | return getAuthor(author); 52 | } 53 | } 54 | }) 55 | }); 56 | 57 | const Post = new GraphQLObjectType({ 58 | name: "Post", 59 | description: "Blog post content", 60 | fields: () => ({ 61 | id: { 62 | type: GraphQLString 63 | }, 64 | title: { 65 | type: GraphQLString 66 | }, 67 | bodyContent: { 68 | type: GraphQLString 69 | }, 70 | author: { 71 | type: Author, 72 | resolve: function ({ 73 | author 74 | }) { 75 | return getAuthor(author); 76 | } 77 | }, 78 | comments: { 79 | type: new GraphQLList(Comment), 80 | resolve: function (post) { 81 | return getComments(post.id); 82 | } 83 | } 84 | }) 85 | }); 86 | 87 | const Query = new GraphQLObjectType({ 88 | name: 'BlogSchema', 89 | description: "Root of the Blog Schema", 90 | fields: () => ({ 91 | posts: { 92 | type: new GraphQLList(Post), 93 | description: "List of posts in the blog", 94 | args: { 95 | authorId: { 96 | type: new GraphQLNonNull(GraphQLString) 97 | }, 98 | }, 99 | resolve: function (source, { 100 | authorId 101 | }) { 102 | return getPosts(authorId); 103 | } 104 | }, 105 | authors: { 106 | type: new GraphQLList(Author), 107 | description: "List of Authors", 108 | resolve: function () { 109 | return getAuthors(); 110 | } 111 | }, 112 | author: { 113 | type: Author, 114 | description: "Get Author by id", 115 | args: { 116 | id: { 117 | type: new GraphQLNonNull(GraphQLString) 118 | } 119 | }, 120 | resolve: function (source, { 121 | id 122 | }) { 123 | return getAuthor(id); 124 | } 125 | } 126 | }) 127 | }); 128 | 129 | const Mutuation = new GraphQLObjectType({ 130 | name: 'BlogMutations', 131 | fields: { 132 | createPost: { 133 | type: Post, 134 | description: "Create blog post", 135 | args: { 136 | title: { 137 | type: new GraphQLLimitedString(10, 30) 138 | }, 139 | bodyContent: { 140 | type: new GraphQLNonNull(GraphQLString) 141 | }, 142 | author: { 143 | type: new GraphQLNonNull(GraphQLString), 144 | description: "Id of the author" 145 | } 146 | }, 147 | resolve: function (source, args) { 148 | return createPost(args); 149 | } 150 | }, 151 | createComment: { 152 | type: Comment, 153 | description: "Add comment to blog post", 154 | args: { 155 | content: { 156 | type: new GraphQLNonNull(GraphQLString) 157 | }, 158 | author: { 159 | type: new GraphQLNonNull(GraphQLString), 160 | description: "Id of the comment author" 161 | }, 162 | post: { 163 | type: new GraphQLNonNull(GraphQLString), 164 | description: "Id of the post" 165 | } 166 | }, 167 | resolve: function (source, args, ctx) { 168 | return createComment(args); 169 | } 170 | }, 171 | createAuthor: { 172 | type: Author, 173 | description: "Add an author", 174 | args: { 175 | name: { 176 | type: new GraphQLNonNull(GraphQLString) 177 | }, 178 | }, 179 | resolve: function (source, args, ctx) { 180 | return createAuthor(args); 181 | } 182 | } 183 | } 184 | }); 185 | 186 | const Schema = new GraphQLSchema({ 187 | query: Query, 188 | mutation: Mutuation 189 | }); 190 | 191 | module.exports = { 192 | Schema, 193 | }; -------------------------------------------------------------------------------- /openfaas/build/openfaas-graphql-blog/function/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "function", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "handler.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "arangojs": "^5.7.0", 14 | "bluebird": "^3.5.0", 15 | "graphql": "^0.11.3", 16 | "graphql-custom-types": "^1.1.0", 17 | "graphql-tools": "^1.2.2" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /openfaas/build/openfaas-graphql-blog/function/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/graphql@^0.9.0": 6 | version "0.9.4" 7 | resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.9.4.tgz#cdeb6bcbef9b6c584374b81aa7f48ecf3da404fa" 8 | 9 | arangojs@^5.7.0: 10 | version "5.7.0" 11 | resolved "https://registry.yarnpkg.com/arangojs/-/arangojs-5.7.0.tgz#e51651853d9379f3a867cbac390087d5395dd2b4" 12 | dependencies: 13 | es6-error "^4.0.1" 14 | http-errors "^1.6.1" 15 | linkedlist "^1.0.1" 16 | multi-part "^2.0.0" 17 | retry "^0.10.0" 18 | utf8-length "^0.0.1" 19 | xhr "^2.3.1" 20 | 21 | bluebird@^3.5.0: 22 | version "3.5.0" 23 | resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" 24 | 25 | depd@1.1.1: 26 | version "1.1.1" 27 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" 28 | 29 | deprecated-decorator@^0.1.6: 30 | version "0.1.6" 31 | resolved "https://registry.yarnpkg.com/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz#00966317b7a12fe92f3cc831f7583af329b86c37" 32 | 33 | dom-walk@^0.1.0: 34 | version "0.1.1" 35 | resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" 36 | 37 | es6-error@^4.0.1: 38 | version "4.0.2" 39 | resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.0.2.tgz#eec5c726eacef51b7f6b73c20db6e1b13b069c98" 40 | 41 | file-type@^4.3.0: 42 | version "4.4.0" 43 | resolved "https://registry.yarnpkg.com/file-type/-/file-type-4.4.0.tgz#1b600e5fca1fbdc6e80c0a70c71c8dba5f7906c5" 44 | 45 | for-each@^0.3.2: 46 | version "0.3.2" 47 | resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.2.tgz#2c40450b9348e97f281322593ba96704b9abd4d4" 48 | dependencies: 49 | is-function "~1.0.0" 50 | 51 | global@~4.3.0: 52 | version "4.3.2" 53 | resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" 54 | dependencies: 55 | min-document "^2.19.0" 56 | process "~0.5.1" 57 | 58 | graphql-custom-types@^1.1.0: 59 | version "1.1.0" 60 | resolved "https://registry.yarnpkg.com/graphql-custom-types/-/graphql-custom-types-1.1.0.tgz#9412ad84e1057cb25a40ca496b5aff267ce33c26" 61 | 62 | graphql-tools@^1.2.2: 63 | version "1.2.2" 64 | resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-1.2.2.tgz#ff791e91b78e05eec18a32716a7732bc7bf5cb4d" 65 | dependencies: 66 | deprecated-decorator "^0.1.6" 67 | uuid "^3.0.1" 68 | optionalDependencies: 69 | "@types/graphql" "^0.9.0" 70 | 71 | graphql@^0.11.3: 72 | version "0.11.3" 73 | resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.11.3.tgz#9934e2df28f17d397a85f83cb39d1d179bffef47" 74 | dependencies: 75 | iterall "^1.1.0" 76 | 77 | http-errors@^1.6.1: 78 | version "1.6.2" 79 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" 80 | dependencies: 81 | depd "1.1.1" 82 | inherits "2.0.3" 83 | setprototypeof "1.0.3" 84 | statuses ">= 1.3.1 < 2" 85 | 86 | inherits@2.0.3: 87 | version "2.0.3" 88 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 89 | 90 | is-function@^1.0.1, is-function@~1.0.0: 91 | version "1.0.1" 92 | resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" 93 | 94 | iterall@^1.1.0: 95 | version "1.1.1" 96 | resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.1.1.tgz#f7f0af11e9a04ec6426260f5019d9fcca4d50214" 97 | 98 | linkedlist@^1.0.1: 99 | version "1.0.1" 100 | resolved "https://registry.yarnpkg.com/linkedlist/-/linkedlist-1.0.1.tgz#7b74189bfad6e76367fb5a10f3c36913128b782b" 101 | 102 | mime-db@~1.30.0: 103 | version "1.30.0" 104 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" 105 | 106 | mime-kind@^2.0.1: 107 | version "2.0.2" 108 | resolved "https://registry.yarnpkg.com/mime-kind/-/mime-kind-2.0.2.tgz#5a43d5bebdeb082182224d9d263206329e57cdf8" 109 | dependencies: 110 | file-type "^4.3.0" 111 | mime-types "^2.1.15" 112 | 113 | mime-types@^2.1.15: 114 | version "2.1.17" 115 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" 116 | dependencies: 117 | mime-db "~1.30.0" 118 | 119 | min-document@^2.19.0: 120 | version "2.19.0" 121 | resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" 122 | dependencies: 123 | dom-walk "^0.1.0" 124 | 125 | multi-part@^2.0.0: 126 | version "2.0.0" 127 | resolved "https://registry.yarnpkg.com/multi-part/-/multi-part-2.0.0.tgz#674f53b432f850cf8cc02d30d21f2064e309563c" 128 | dependencies: 129 | mime-kind "^2.0.1" 130 | 131 | parse-headers@^2.0.0: 132 | version "2.0.1" 133 | resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.1.tgz#6ae83a7aa25a9d9b700acc28698cd1f1ed7e9536" 134 | dependencies: 135 | for-each "^0.3.2" 136 | trim "0.0.1" 137 | 138 | process@~0.5.1: 139 | version "0.5.2" 140 | resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" 141 | 142 | retry@^0.10.0: 143 | version "0.10.1" 144 | resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" 145 | 146 | setprototypeof@1.0.3: 147 | version "1.0.3" 148 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" 149 | 150 | "statuses@>= 1.3.1 < 2": 151 | version "1.3.1" 152 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" 153 | 154 | trim@0.0.1: 155 | version "0.0.1" 156 | resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" 157 | 158 | utf8-length@^0.0.1: 159 | version "0.0.1" 160 | resolved "https://registry.yarnpkg.com/utf8-length/-/utf8-length-0.0.1.tgz#d315c4bed529c977f18dd35c73d72628327d9ada" 161 | 162 | uuid@^3.0.1: 163 | version "3.1.0" 164 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" 165 | 166 | xhr@^2.3.1: 167 | version "2.4.0" 168 | resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.4.0.tgz#e16e66a45f869861eeefab416d5eff722dc40993" 169 | dependencies: 170 | global "~4.3.0" 171 | is-function "^1.0.1" 172 | parse-headers "^2.0.0" 173 | xtend "^4.0.0" 174 | 175 | xtend@^4.0.0: 176 | version "4.0.1" 177 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" 178 | -------------------------------------------------------------------------------- /openfaas/build/openfaas-graphql-blog/index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Alex Ellis 2017. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | "use strict" 5 | 6 | let getStdin = require('get-stdin'); 7 | 8 | let handler = require('./function/handler'); 9 | 10 | getStdin().then(val => { 11 | handler(val, (err, res) => { 12 | if (err) { 13 | return console.error(err); 14 | } 15 | if(isArray(res) || isObject(res)) { 16 | console.log(JSON.stringify(res)); 17 | } else { 18 | console.log(res); 19 | } 20 | }); 21 | }).catch(e => { 22 | console.error(e.stack); 23 | }); 24 | 25 | let isArray = (a) => { 26 | return (!!a) && (a.constructor === Array); 27 | }; 28 | 29 | let isObject = (a) => { 30 | return (!!a) && (a.constructor === Object); 31 | }; 32 | -------------------------------------------------------------------------------- /openfaas/build/openfaas-graphql-blog/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NodejsBase", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "faas_index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "get-stdin": "^5.0.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /openfaas/master.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kenfdev/openfaas-graphql-blog/d816e0a67d8f5bdc8cc2a57d09a3ce7b346f2424/openfaas/master.zip -------------------------------------------------------------------------------- /openfaas/openfaas-graphql-blog.yml: -------------------------------------------------------------------------------- 1 | provider: 2 | name: faas 3 | gateway: http://localhost:8080 4 | 5 | functions: 6 | openfaas-graphql-blog: 7 | lang: node 8 | handler: ./openfaas-graphql-blog 9 | image: kenfdev/openfaas-graphql-blog 10 | -------------------------------------------------------------------------------- /openfaas/openfaas-graphql-blog/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /openfaas/openfaas-graphql-blog/handler.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | // Require Logic 4 | var lib = require('./lib'); 5 | 6 | module.exports = (context, callback) => { 7 | const event = JSON.parse(context); 8 | 9 | lib.runGraphQL(event, (err, response) => { 10 | callback(err, response); 11 | }) 12 | 13 | } -------------------------------------------------------------------------------- /openfaas/openfaas-graphql-blog/lib/db.js: -------------------------------------------------------------------------------- 1 | const { 2 | Database, 3 | aql 4 | } = require('arangojs'); 5 | const Promise = require('bluebird'); 6 | 7 | // Using a complex connection string with authentication 8 | const host = process.env.ARANGODB_HOST; 9 | const port = process.env.ARANGODB_PORT; 10 | const database = process.env.ARANGODB_DB; 11 | const username = process.env.ARANGODB_USERNAME; 12 | const password = process.env.ARANGODB_PASSWORD; 13 | 14 | const db = new Database({ 15 | url: `http://${username}:${password}@${host}:${port}`, 16 | databaseName: database 17 | }); 18 | 19 | const postsTable = 'posts' 20 | const authorsTable = 'authors' 21 | const commentsTable = 'comments' 22 | 23 | function createAuthor(author) { 24 | return new Promise(function (resolve, reject) { 25 | const collection = db.collection(authorsTable); 26 | collection.save(author, { 27 | returnNew: true 28 | }) 29 | .then(result => resolve(Object.assign(result.new, { 30 | id: result._key 31 | }))) 32 | .catch(err => reject(err)); 33 | 34 | }); 35 | } 36 | 37 | function createPost(post) { 38 | return new Promise(function (resolve, reject) { 39 | const collection = db.collection(postsTable); 40 | collection.save(post, { 41 | returnNew: true 42 | }) 43 | .then(result => resolve(Object.assign(result.new, { 44 | id: result._key 45 | }))) 46 | .catch(err => reject(err)); 47 | 48 | }); 49 | } 50 | 51 | function createComment(comment) { 52 | return new Promise(function (resolve, reject) { 53 | const collection = db.collection(commentsTable); 54 | collection.save(comment, { 55 | returnNew: true 56 | }) 57 | .then(result => resolve(Object.assign(result.new, { 58 | id: result._key 59 | }))) 60 | .catch(err => reject(err)); 61 | 62 | }); 63 | } 64 | 65 | function getPosts(authorId) { 66 | return new Promise(function (resolve, reject) { 67 | const collection = db.collection(postsTable); 68 | 69 | collection.byExample({ 70 | "author": authorId 71 | }) 72 | .then(c => c.all()) 73 | .then(results => { 74 | const formatted = results.map(result => Object.assign(result, { 75 | id: result._key 76 | })) 77 | resolve(formatted); 78 | }) 79 | .catch(err => reject(err)); 80 | 81 | }); 82 | } 83 | 84 | function getAuthor(id) { 85 | return new Promise(function (resolve, reject) { 86 | const collection = db.collection(authorsTable); 87 | collection.firstExample({ 88 | _key: id 89 | }) 90 | .then(result => resolve(Object.assign(result, { 91 | id: id 92 | }))) 93 | .catch(err => reject(err)); 94 | 95 | }); 96 | } 97 | 98 | function getAuthors() { 99 | return new Promise(function (resolve, reject) { 100 | const collection = db.collection(authorsTable); 101 | collection.all() 102 | .then(c => c.all()) 103 | .then(results => { 104 | const formatted = results.map(result => Object.assign(result, { 105 | id: result._key 106 | })) 107 | resolve(formatted); 108 | }) 109 | .catch(err => reject(err)); 110 | }); 111 | } 112 | 113 | function getComments(postId) { 114 | return new Promise(function (resolve, reject) { 115 | const collection = db.collection(commentsTable); 116 | collection.byExample({ 117 | "post": postId 118 | }) 119 | .then(c => c.all()) 120 | .then(results => { 121 | const formatted = results.map(result => Object.assign(result, { 122 | id: result._key 123 | })) 124 | resolve(formatted); 125 | }) 126 | .catch(err => reject(err)); 127 | }); 128 | } 129 | 130 | module.exports = { 131 | createPost, 132 | createComment, 133 | createAuthor, 134 | getPosts, 135 | getAuthor, 136 | getAuthors, 137 | getComments, 138 | } -------------------------------------------------------------------------------- /openfaas/openfaas-graphql-blog/lib/index.js: -------------------------------------------------------------------------------- 1 | const { 2 | graphql 3 | } = require('graphql'); 4 | const { 5 | Schema 6 | } = require('./schema'); 7 | 8 | function runGraphQL(event, cb) { 9 | 10 | let query = event.query; 11 | 12 | graphql(Schema, query).then(function (result) { 13 | return cb(null, result); 14 | }).catch(error => { 15 | const e = { 16 | errors: [{ 17 | message: error.message, 18 | state: error.originalError && error.originalError.state, 19 | locations: error.locations, 20 | path: error.path, 21 | }] 22 | } 23 | return cb(JSON.stringify(e), null); 24 | }); 25 | 26 | } 27 | 28 | module.exports = { 29 | runGraphQL, 30 | } -------------------------------------------------------------------------------- /openfaas/openfaas-graphql-blog/lib/schema.js: -------------------------------------------------------------------------------- 1 | const { 2 | GraphQLObjectType, 3 | GraphQLSchema, 4 | GraphQLList, 5 | GraphQLString, 6 | GraphQLNonNull 7 | } = require('graphql'); 8 | 9 | const { 10 | GraphQLLimitedString 11 | } = require('graphql-custom-types'); 12 | 13 | const { 14 | getPosts, 15 | getAuthor, 16 | getAuthors, 17 | getComments, 18 | createPost, 19 | createComment, 20 | createAuthor, 21 | } = require('./db'); 22 | 23 | const Author = new GraphQLObjectType({ 24 | name: "Author", 25 | description: "Author of the blog post", 26 | fields: () => ({ 27 | id: { 28 | type: GraphQLString 29 | }, 30 | name: { 31 | type: GraphQLString 32 | } 33 | }) 34 | }); 35 | 36 | const Comment = new GraphQLObjectType({ 37 | name: "Comment", 38 | description: "Comment on the blog post", 39 | fields: () => ({ 40 | id: { 41 | type: GraphQLString 42 | }, 43 | content: { 44 | type: GraphQLString 45 | }, 46 | author: { 47 | type: Author, 48 | resolve: function ({ 49 | author 50 | }) { 51 | return getAuthor(author); 52 | } 53 | } 54 | }) 55 | }); 56 | 57 | const Post = new GraphQLObjectType({ 58 | name: "Post", 59 | description: "Blog post content", 60 | fields: () => ({ 61 | id: { 62 | type: GraphQLString 63 | }, 64 | title: { 65 | type: GraphQLString 66 | }, 67 | bodyContent: { 68 | type: GraphQLString 69 | }, 70 | author: { 71 | type: Author, 72 | resolve: function ({ 73 | author 74 | }) { 75 | return getAuthor(author); 76 | } 77 | }, 78 | comments: { 79 | type: new GraphQLList(Comment), 80 | resolve: function (post) { 81 | return getComments(post.id); 82 | } 83 | } 84 | }) 85 | }); 86 | 87 | const Query = new GraphQLObjectType({ 88 | name: 'BlogSchema', 89 | description: "Root of the Blog Schema", 90 | fields: () => ({ 91 | posts: { 92 | type: new GraphQLList(Post), 93 | description: "List of posts in the blog", 94 | args: { 95 | authorId: { 96 | type: new GraphQLNonNull(GraphQLString) 97 | }, 98 | }, 99 | resolve: function (source, { 100 | authorId 101 | }) { 102 | return getPosts(authorId); 103 | } 104 | }, 105 | authors: { 106 | type: new GraphQLList(Author), 107 | description: "List of Authors", 108 | resolve: function () { 109 | return getAuthors(); 110 | } 111 | }, 112 | author: { 113 | type: Author, 114 | description: "Get Author by id", 115 | args: { 116 | id: { 117 | type: new GraphQLNonNull(GraphQLString) 118 | } 119 | }, 120 | resolve: function (source, { 121 | id 122 | }) { 123 | return getAuthor(id); 124 | } 125 | } 126 | }) 127 | }); 128 | 129 | const Mutuation = new GraphQLObjectType({ 130 | name: 'BlogMutations', 131 | fields: { 132 | createPost: { 133 | type: Post, 134 | description: "Create blog post", 135 | args: { 136 | title: { 137 | type: new GraphQLLimitedString(10, 30) 138 | }, 139 | bodyContent: { 140 | type: new GraphQLNonNull(GraphQLString) 141 | }, 142 | author: { 143 | type: new GraphQLNonNull(GraphQLString), 144 | description: "Id of the author" 145 | } 146 | }, 147 | resolve: function (source, args) { 148 | return createPost(args); 149 | } 150 | }, 151 | createComment: { 152 | type: Comment, 153 | description: "Add comment to blog post", 154 | args: { 155 | content: { 156 | type: new GraphQLNonNull(GraphQLString) 157 | }, 158 | author: { 159 | type: new GraphQLNonNull(GraphQLString), 160 | description: "Id of the comment author" 161 | }, 162 | post: { 163 | type: new GraphQLNonNull(GraphQLString), 164 | description: "Id of the post" 165 | } 166 | }, 167 | resolve: function (source, args, ctx) { 168 | return createComment(args); 169 | } 170 | }, 171 | createAuthor: { 172 | type: Author, 173 | description: "Add an author", 174 | args: { 175 | name: { 176 | type: new GraphQLNonNull(GraphQLString) 177 | }, 178 | }, 179 | resolve: function (source, args, ctx) { 180 | return createAuthor(args); 181 | } 182 | } 183 | } 184 | }); 185 | 186 | const Schema = new GraphQLSchema({ 187 | query: Query, 188 | mutation: Mutuation 189 | }); 190 | 191 | module.exports = { 192 | Schema, 193 | }; -------------------------------------------------------------------------------- /openfaas/openfaas-graphql-blog/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "function", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "handler.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "arangojs": "^5.7.0", 14 | "bluebird": "^3.5.0", 15 | "graphql": "^0.11.3", 16 | "graphql-custom-types": "^1.1.0", 17 | "graphql-tools": "^1.2.2" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /openfaas/openfaas-graphql-blog/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/graphql@^0.9.0": 6 | version "0.9.4" 7 | resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.9.4.tgz#cdeb6bcbef9b6c584374b81aa7f48ecf3da404fa" 8 | 9 | arangojs@^5.7.0: 10 | version "5.7.0" 11 | resolved "https://registry.yarnpkg.com/arangojs/-/arangojs-5.7.0.tgz#e51651853d9379f3a867cbac390087d5395dd2b4" 12 | dependencies: 13 | es6-error "^4.0.1" 14 | http-errors "^1.6.1" 15 | linkedlist "^1.0.1" 16 | multi-part "^2.0.0" 17 | retry "^0.10.0" 18 | utf8-length "^0.0.1" 19 | xhr "^2.3.1" 20 | 21 | bluebird@^3.5.0: 22 | version "3.5.0" 23 | resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" 24 | 25 | depd@1.1.1: 26 | version "1.1.1" 27 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" 28 | 29 | deprecated-decorator@^0.1.6: 30 | version "0.1.6" 31 | resolved "https://registry.yarnpkg.com/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz#00966317b7a12fe92f3cc831f7583af329b86c37" 32 | 33 | dom-walk@^0.1.0: 34 | version "0.1.1" 35 | resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" 36 | 37 | es6-error@^4.0.1: 38 | version "4.0.2" 39 | resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.0.2.tgz#eec5c726eacef51b7f6b73c20db6e1b13b069c98" 40 | 41 | file-type@^4.3.0: 42 | version "4.4.0" 43 | resolved "https://registry.yarnpkg.com/file-type/-/file-type-4.4.0.tgz#1b600e5fca1fbdc6e80c0a70c71c8dba5f7906c5" 44 | 45 | for-each@^0.3.2: 46 | version "0.3.2" 47 | resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.2.tgz#2c40450b9348e97f281322593ba96704b9abd4d4" 48 | dependencies: 49 | is-function "~1.0.0" 50 | 51 | global@~4.3.0: 52 | version "4.3.2" 53 | resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" 54 | dependencies: 55 | min-document "^2.19.0" 56 | process "~0.5.1" 57 | 58 | graphql-custom-types@^1.1.0: 59 | version "1.1.0" 60 | resolved "https://registry.yarnpkg.com/graphql-custom-types/-/graphql-custom-types-1.1.0.tgz#9412ad84e1057cb25a40ca496b5aff267ce33c26" 61 | 62 | graphql-tools@^1.2.2: 63 | version "1.2.2" 64 | resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-1.2.2.tgz#ff791e91b78e05eec18a32716a7732bc7bf5cb4d" 65 | dependencies: 66 | deprecated-decorator "^0.1.6" 67 | uuid "^3.0.1" 68 | optionalDependencies: 69 | "@types/graphql" "^0.9.0" 70 | 71 | graphql@^0.11.3: 72 | version "0.11.3" 73 | resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.11.3.tgz#9934e2df28f17d397a85f83cb39d1d179bffef47" 74 | dependencies: 75 | iterall "^1.1.0" 76 | 77 | http-errors@^1.6.1: 78 | version "1.6.2" 79 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" 80 | dependencies: 81 | depd "1.1.1" 82 | inherits "2.0.3" 83 | setprototypeof "1.0.3" 84 | statuses ">= 1.3.1 < 2" 85 | 86 | inherits@2.0.3: 87 | version "2.0.3" 88 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 89 | 90 | is-function@^1.0.1, is-function@~1.0.0: 91 | version "1.0.1" 92 | resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" 93 | 94 | iterall@^1.1.0: 95 | version "1.1.1" 96 | resolved "https://registry.yarnpkg.com/iterall/-/iterall-1.1.1.tgz#f7f0af11e9a04ec6426260f5019d9fcca4d50214" 97 | 98 | linkedlist@^1.0.1: 99 | version "1.0.1" 100 | resolved "https://registry.yarnpkg.com/linkedlist/-/linkedlist-1.0.1.tgz#7b74189bfad6e76367fb5a10f3c36913128b782b" 101 | 102 | mime-db@~1.30.0: 103 | version "1.30.0" 104 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" 105 | 106 | mime-kind@^2.0.1: 107 | version "2.0.2" 108 | resolved "https://registry.yarnpkg.com/mime-kind/-/mime-kind-2.0.2.tgz#5a43d5bebdeb082182224d9d263206329e57cdf8" 109 | dependencies: 110 | file-type "^4.3.0" 111 | mime-types "^2.1.15" 112 | 113 | mime-types@^2.1.15: 114 | version "2.1.17" 115 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.17.tgz#09d7a393f03e995a79f8af857b70a9e0ab16557a" 116 | dependencies: 117 | mime-db "~1.30.0" 118 | 119 | min-document@^2.19.0: 120 | version "2.19.0" 121 | resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" 122 | dependencies: 123 | dom-walk "^0.1.0" 124 | 125 | multi-part@^2.0.0: 126 | version "2.0.0" 127 | resolved "https://registry.yarnpkg.com/multi-part/-/multi-part-2.0.0.tgz#674f53b432f850cf8cc02d30d21f2064e309563c" 128 | dependencies: 129 | mime-kind "^2.0.1" 130 | 131 | parse-headers@^2.0.0: 132 | version "2.0.1" 133 | resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.1.tgz#6ae83a7aa25a9d9b700acc28698cd1f1ed7e9536" 134 | dependencies: 135 | for-each "^0.3.2" 136 | trim "0.0.1" 137 | 138 | process@~0.5.1: 139 | version "0.5.2" 140 | resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" 141 | 142 | retry@^0.10.0: 143 | version "0.10.1" 144 | resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" 145 | 146 | setprototypeof@1.0.3: 147 | version "1.0.3" 148 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" 149 | 150 | "statuses@>= 1.3.1 < 2": 151 | version "1.3.1" 152 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" 153 | 154 | trim@0.0.1: 155 | version "0.0.1" 156 | resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" 157 | 158 | utf8-length@^0.0.1: 159 | version "0.0.1" 160 | resolved "https://registry.yarnpkg.com/utf8-length/-/utf8-length-0.0.1.tgz#d315c4bed529c977f18dd35c73d72628327d9ada" 161 | 162 | uuid@^3.0.1: 163 | version "3.1.0" 164 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" 165 | 166 | xhr@^2.3.1: 167 | version "2.4.0" 168 | resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.4.0.tgz#e16e66a45f869861eeefab416d5eff722dc40993" 169 | dependencies: 170 | global "~4.3.0" 171 | is-function "^1.0.1" 172 | parse-headers "^2.0.0" 173 | xtend "^4.0.0" 174 | 175 | xtend@^4.0.0: 176 | version "4.0.1" 177 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" 178 | -------------------------------------------------------------------------------- /openfaas/template/node/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:6.11.2-alpine 2 | 3 | # Alternatively use ADD https:// (which will not be cached by Docker builder) 4 | RUN apk --no-cache add curl \ 5 | && echo "Pulling watchdog binary from Github." \ 6 | && curl -sSL https://github.com/alexellis/faas/releases/download/0.6.1/fwatchdog > /usr/bin/fwatchdog \ 7 | && chmod +x /usr/bin/fwatchdog \ 8 | && apk del curl --no-cache 9 | 10 | WORKDIR /root/ 11 | 12 | # Turn down the verbosity to default level. 13 | ENV NPM_CONFIG_LOGLEVEL warn 14 | 15 | # Wrapper/boot-strapper 16 | COPY package.json . 17 | RUN npm i 18 | 19 | # Function 20 | COPY index.js . 21 | RUN mkdir -p ./root/function 22 | 23 | COPY function/*.json ./function/ 24 | WORKDIR /root/function 25 | RUN npm i || : 26 | WORKDIR /root/ 27 | COPY function function 28 | WORKDIR /root/function 29 | 30 | WORKDIR /root/ 31 | 32 | ENV cgi_headers="true" 33 | 34 | ENV fprocess="node index.js" 35 | 36 | HEALTHCHECK --interval=1s CMD [ -e /tmp/.lock ] || exit 1 37 | 38 | CMD ["fwatchdog"] -------------------------------------------------------------------------------- /openfaas/template/node/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Building functions/base:node-6.9.1-alpine" 4 | docker build -t functions/base:node-6.9.1-alpine . 5 | 6 | -------------------------------------------------------------------------------- /openfaas/template/node/function/handler.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | module.exports = (context, callback) => { 4 | callback(undefined, {status: "done"}); 5 | } 6 | -------------------------------------------------------------------------------- /openfaas/template/node/function/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "function", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "handler.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC" 12 | } 13 | -------------------------------------------------------------------------------- /openfaas/template/node/index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Alex Ellis 2017. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | "use strict" 5 | 6 | let getStdin = require('get-stdin'); 7 | 8 | let handler = require('./function/handler'); 9 | 10 | getStdin().then(val => { 11 | handler(val, (err, res) => { 12 | if (err) { 13 | return console.error(err); 14 | } 15 | if(isArray(res) || isObject(res)) { 16 | console.log(JSON.stringify(res)); 17 | } else { 18 | console.log(res); 19 | } 20 | }); 21 | }).catch(e => { 22 | console.error(e.stack); 23 | }); 24 | 25 | let isArray = (a) => { 26 | return (!!a) && (a.constructor === Array); 27 | }; 28 | 29 | let isObject = (a) => { 30 | return (!!a) && (a.constructor === Object); 31 | }; 32 | -------------------------------------------------------------------------------- /openfaas/template/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NodejsBase", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "faas_index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "get-stdin": "^5.0.1" 14 | } 15 | } 16 | --------------------------------------------------------------------------------