From f5b94f1d55292b42c6c47753c8f15ee15a3667c5 Mon Sep 17 00:00:00 2001 From: Kevin Deus Date: Wed, 2 Nov 2016 15:56:54 -0700 Subject: [PATCH 1/8] Copied Endpoints Echo sample from /appengine/endpoints --- endpoints/getting-started/README.md | 46 +++++++++ endpoints/getting-started/app.js | 51 ++++++++++ endpoints/getting-started/app.yaml | 21 ++++ endpoints/getting-started/package.json | 22 +++++ endpoints/getting-started/swagger.yaml | 106 +++++++++++++++++++++ endpoints/getting-started/test/app.test.js | 81 ++++++++++++++++ 6 files changed, 327 insertions(+) create mode 100644 endpoints/getting-started/README.md create mode 100644 endpoints/getting-started/app.js create mode 100644 endpoints/getting-started/app.yaml create mode 100644 endpoints/getting-started/package.json create mode 100644 endpoints/getting-started/swagger.yaml create mode 100644 endpoints/getting-started/test/app.test.js diff --git a/endpoints/getting-started/README.md b/endpoints/getting-started/README.md new file mode 100644 index 0000000000..0334812803 --- /dev/null +++ b/endpoints/getting-started/README.md @@ -0,0 +1,46 @@ +# Google Cloud Endpoints sample for Google App Engine Flexible Environment + +This sample demonstrates how to use Google Cloud Endpoints on Google App Engine Flexible Environment using Node.js. + +## Running locally + +Refer to the [appengine/README.md](../README.md) file for instructions on +running locally. + +## Deploying to Google App Engine + +Open the `swagger.yaml` file and in the `host` property, replace +`YOUR-PROJECT-ID` with your project's ID. + +Then, deploy the sample using `gcloud`: + + gcloud beta app deploy + +Once deployed, you can access the application at https://YOUR-PROJECT-ID.appspot.com/. + +## Send an echo request + +Choose your local or production server: + +``` +# If you're running locally, you won't need an API key. +$ export ENDPOINTS_HOST=http://localhost:8080 + +$ export ENDPOINTS_HOST=https://PROJECT-ID.appspot.com +$ export ENDPOINTS_KEY=AIza... +``` + +Send the request: + +``` +$ curl -vv -d '{"message":"foo"}' -H 'Content-Type: application/json' "${ENDPOINTS_HOST}/echo?key=${ENDPOINTS_KEY}" +``` + +If you're running locally, you won't need an API key. + +## Sending authenticated requests + +No Node.js client is written yet, but you can try the Python client found [here][python-client]. +It will send authenticated JWT requests using a Google Cloud service account, or using a three-legged OAuth flow. + +[python-client]: https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/managed_vms/endpoints diff --git a/endpoints/getting-started/app.js b/endpoints/getting-started/app.js new file mode 100644 index 0000000000..e882d6b037 --- /dev/null +++ b/endpoints/getting-started/app.js @@ -0,0 +1,51 @@ +// Copyright 2015-2016, Google, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// [START app] +'use strict'; + +// [START setup] +var express = require('express'); +var bodyParser = require('body-parser'); + +var app = express(); +app.use(bodyParser.json()); +// [END setup] + +app.post('/echo', function (req, res) { + res.status(200).json({ message: req.body.message }); +}); + +function authInfoHandler (req, res) { + var authUser = { id: 'anonymous' }; + var encodedInfo = req.get('X-Endpoint-API-UserInfo'); + if (encodedInfo) { + authUser = JSON.parse(new Buffer(encodedInfo, 'base64')); + } + res.status(200).json(authUser); +} + +app.get('/auth/info/googlejwt', authInfoHandler); +app.get('/auth/info/googleidtoken', authInfoHandler); + +// [START listen] +var PORT = process.env.PORT || 8080; +app.listen(PORT, function () { + console.log('App listening on port %s', PORT); + console.log('Press Ctrl+C to quit.'); +}); +// [END listen] +// [END app] + +module.exports = app; diff --git a/endpoints/getting-started/app.yaml b/endpoints/getting-started/app.yaml new file mode 100644 index 0000000000..6a22da0518 --- /dev/null +++ b/endpoints/getting-started/app.yaml @@ -0,0 +1,21 @@ +# Copyright 2015-2016, Google, Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +runtime: nodejs +vm: true + +beta_settings: + # Enable Google Cloud Endpoints API management. + use_endpoints_api_management: true + # Specify the Swagger API specification. + endpoints_swagger_spec_file: swagger.yaml diff --git a/endpoints/getting-started/package.json b/endpoints/getting-started/package.json new file mode 100644 index 0000000000..8627da51b2 --- /dev/null +++ b/endpoints/getting-started/package.json @@ -0,0 +1,22 @@ +{ + "name": "appengine-endpoints", + "description": "Endpoints Node.js sample for Google App Engine", + "version": "0.0.1", + "private": true, + "license": "Apache Version 2.0", + "author": "Google Inc.", + "engines": { + "node": "~4.2" + }, + "scripts": { + "start": "node app.js", + "test": "mocha -R spec -t 120000 --require intelli-espower-loader ../../test/_setup.js test/*.test.js" + }, + "dependencies": { + "express": "^4.13.4", + "body-parser": "^1.15.0" + }, + "devDependencies": { + "mocha": "^2.5.3" + } +} diff --git a/endpoints/getting-started/swagger.yaml b/endpoints/getting-started/swagger.yaml new file mode 100644 index 0000000000..71bac9ce62 --- /dev/null +++ b/endpoints/getting-started/swagger.yaml @@ -0,0 +1,106 @@ +swagger: "2.0" +info: + description: "A simple Google Cloud Endpoints API example." + title: "Endpoints Example" + version: "1.0.0" +host: "YOUR-PROJECT-ID.appspot.com" +basePath: "/" +consumes: +- "application/json" +produces: +- "application/json" +schemes: +- "https" +paths: + "/echo": + post: + description: "Echo back a given message." + operationId: "echo" + produces: + - "application/json" + responses: + 200: + description: "Echo" + schema: + $ref: "#/definitions/echoMessage" + parameters: + - description: "Message to echo" + in: body + name: message + required: true + schema: + $ref: "#/definitions/echoMessage" + "/auth/info/googlejwt": + get: + description: "Returns the requests' authentication information." + operationId: "auth_info_google_jwt" + produces: + - "application/json" + responses: + 200: + description: "Authenication info." + schema: + $ref: "#/definitions/authInfoResponse" + x-security: + - google_jwt: + audiences: + # This must match the "aud" field in the JWT. You can add multiple + # audiences to accept JWTs from multiple clients. + - "echo.endpoints.sample.google.com" + "/auth/info/googleidtoken": + get: + description: "Returns the requests' authentication information." + operationId: "authInfoGoogleIdToken" + produces: + - "application/json" + responses: + 200: + description: "Authenication info." + schema: + $ref: "#/definitions/authInfoResponse" + x-security: + - google_id_token: + audiences: + # Your OAuth2 client's Client ID must be added here. You can add + # multiple client IDs to accept tokens from multiple clients. + - "YOUR-CLIENT-ID" +definitions: + echoMessage: + properties: + message: + type: "string" + authInfoResponse: + properties: + id: + type: "string" + email: + type: "string" +# This section requires all requests to any path to require an API key. +security: +- api_key: [] +securityDefinitions: + # This section configures basic authentication with an API key. + api_key: + type: "apiKey" + name: "key" + in: "query" + # This section configures authentication using Google API Service Accounts + # to sign a json web token. This is mostly used for server-to-server + # communication. + google_jwt: + authorizationUrl: "" + flow: "implicit" + type: "oauth2" + # This must match the 'iss' field in the JWT. + x-issuer: "jwt-client.endpoints.sample.google.com" + # Update this with your service account's email address. + x-jwks_uri: "https://www.googleapis.com/service_accounts/v1/jwk/YOUR-SERVICE-ACCOUNT-EMAIL" + # This section configures authentication using Google OAuth2 ID Tokens. + # ID Tokens can be obtained using OAuth2 clients, and can be used to access + # your API on behalf of a particular user. + google_id_token: + authorizationUrl: "" + flow: "implicit" + type: "oauth2" + x-issuer: "accounts.google.com" + x-jwks_uri: "https://www.googleapis.com/oauth2/v1/certs" diff --git a/endpoints/getting-started/test/app.test.js b/endpoints/getting-started/test/app.test.js new file mode 100644 index 0000000000..1d88c55917 --- /dev/null +++ b/endpoints/getting-started/test/app.test.js @@ -0,0 +1,81 @@ +// Copyright 2016, Google, Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +var express = require('express'); +var path = require('path'); +var proxyquire = require('proxyquire').noPreserveCache(); +var request = require('supertest'); + +var SAMPLE_PATH = path.join(__dirname, '../app.js'); + +function getSample () { + var testApp = express(); + sinon.stub(testApp, 'listen').callsArg(1); + var expressMock = sinon.stub().returns(testApp); + + var app = proxyquire(SAMPLE_PATH, { + express: expressMock + }); + return { + app: app, + mocks: { + express: expressMock + } + }; +} + +describe('appengine/endpoints/app.js', function () { + var sample; + + beforeEach(function () { + sample = getSample(); + + assert(sample.mocks.express.calledOnce); + assert(sample.app.listen.calledOnce); + assert.equal(sample.app.listen.firstCall.args[0], process.env.PORT || 8080); + }); + + it('should echo a message', function (done) { + request(sample.app) + .post('/echo') + .send({ message: 'foo' }) + .expect(200) + .expect(function (response) { + assert.equal(response.body.message, 'foo'); + }) + .end(done); + }); + + it('should try to parse encoded info', function (done) { + request(sample.app) + .get('/auth/info/googlejwt') + .expect(200) + .expect(function (response) { + assert.deepEqual(response.body, { id: 'anonymous' }); + }) + .end(done); + }); + + it('should successfully parse encoded info', function (done) { + request(sample.app) + .get('/auth/info/googlejwt') + .set('X-Endpoint-API-UserInfo', new Buffer(JSON.stringify({ id: 'foo' })).toString('base64')) + .expect(200) + .expect(function (response) { + assert.deepEqual(response.body, { id: 'foo' }); + }) + .end(done); + }); +}); From db294c3c2f1556e852290603102ee74e427b495f Mon Sep 17 00:00:00 2001 From: Kevin Deus Date: Wed, 2 Nov 2016 16:45:32 -0700 Subject: [PATCH 2/8] Added gke.yaml --- endpoints/getting-started/gke.yaml | 68 ++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 endpoints/getting-started/gke.yaml diff --git a/endpoints/getting-started/gke.yaml b/endpoints/getting-started/gke.yaml new file mode 100644 index 0000000000..a8f37a1df2 --- /dev/null +++ b/endpoints/getting-started/gke.yaml @@ -0,0 +1,68 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +apiVersion: v1 +kind: Service +metadata: + name: esp-echo +spec: + ports: + - port: 80 + targetPort: 8080 + protocol: TCP + name: http + - port: 443 + protocol: TCP + name: https + selector: + app: esp-echo + type: LoadBalancer +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: esp-echo +spec: + replicas: 1 + template: + metadata: + labels: + app: esp-echo + spec: + volumes: + - name: nginx-ssl + secret: + secretName: nginx-ssl + containers: + - name: esp + image: b.gcr.io/endpoints/endpoints-runtime:0.3 + args: [ + "-p", "8080", + "-S", "443", + "-a", "127.0.0.1:8081", + "-s", "SERVICE_NAME", + "-v", "SERVICE_VERSION", + ] + ports: + - containerPort: 8080 + - containerPort: 443 + volumeMounts: + - mountPath: /etc/nginx/ssl + name: nginx-ssl + readOnly: true + - name: echo + image: b.gcr.io/endpoints/echo:latest + ports: + - containerPort: 8081 From 70da871ccff7775c335c253229caa4b7f04ddf00 Mon Sep 17 00:00:00 2001 From: Kevin Deus Date: Thu, 3 Nov 2016 11:01:48 -0700 Subject: [PATCH 3/8] Renamed gke.yaml to container-engine.yaml --- endpoints/getting-started/{gke.yaml => container-engine.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename endpoints/getting-started/{gke.yaml => container-engine.yaml} (100%) diff --git a/endpoints/getting-started/gke.yaml b/endpoints/getting-started/container-engine.yaml similarity index 100% rename from endpoints/getting-started/gke.yaml rename to endpoints/getting-started/container-engine.yaml From 5a936ff8a5fa3502b6d5fa412840c9f5eaf3ee4d Mon Sep 17 00:00:00 2001 From: Kevin Deus Date: Thu, 3 Nov 2016 12:12:44 -0700 Subject: [PATCH 4/8] Cleaned up readme, added Dockerfile --- endpoints/getting-started/Dockerfile.custom | 8 +++++++ endpoints/getting-started/README.md | 25 ++++++++------------- 2 files changed, 17 insertions(+), 16 deletions(-) create mode 100644 endpoints/getting-started/Dockerfile.custom diff --git a/endpoints/getting-started/Dockerfile.custom b/endpoints/getting-started/Dockerfile.custom new file mode 100644 index 0000000000..c9ad24c465 --- /dev/null +++ b/endpoints/getting-started/Dockerfile.custom @@ -0,0 +1,8 @@ +FROM gcr.io/google_appengine/nodejs + +ADD . /app +WORKDIR /app + +RUN npm install +ENV PORT=8081 +ENTRYPOINT ["npm", "start"] \ No newline at end of file diff --git a/endpoints/getting-started/README.md b/endpoints/getting-started/README.md index 0334812803..67898f8007 100644 --- a/endpoints/getting-started/README.md +++ b/endpoints/getting-started/README.md @@ -1,22 +1,15 @@ -# Google Cloud Endpoints sample for Google App Engine Flexible Environment +# Google Cloud Endpoints sample for Node.js -This sample demonstrates how to use Google Cloud Endpoints on Google App Engine Flexible Environment using Node.js. +This sample demonstrates how to use Google Cloud Endpoints using Node.js. -## Running locally - -Refer to the [appengine/README.md](../README.md) file for instructions on -running locally. - -## Deploying to Google App Engine +For a complete walkthrough showing how to run this sample in different +environments, see the +[Google Cloud Endpoints Quickstarts](https://cloud.google.com/endpoints/docs/quickstarts). -Open the `swagger.yaml` file and in the `host` property, replace -`YOUR-PROJECT-ID` with your project's ID. - -Then, deploy the sample using `gcloud`: - - gcloud beta app deploy +## Running locally -Once deployed, you can access the application at https://YOUR-PROJECT-ID.appspot.com/. +Refer to the [appengine/README.md](../../appengine/README.md) file for +instructions on running locally. ## Send an echo request @@ -43,4 +36,4 @@ If you're running locally, you won't need an API key. No Node.js client is written yet, but you can try the Python client found [here][python-client]. It will send authenticated JWT requests using a Google Cloud service account, or using a three-legged OAuth flow. -[python-client]: https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/managed_vms/endpoints +[python-client]: https://github.com/GoogleCloudPlatform/python-docs-samples/tree/master/endpoints/getting-started From e82013251ba9c3b558e760b7ea71493b1d74dacf Mon Sep 17 00:00:00 2001 From: Kevin Deus Date: Thu, 3 Nov 2016 12:16:22 -0700 Subject: [PATCH 5/8] Added region tags for docs --- endpoints/getting-started/container-engine.yaml | 2 ++ endpoints/getting-started/swagger.yaml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/endpoints/getting-started/container-engine.yaml b/endpoints/getting-started/container-engine.yaml index a8f37a1df2..ec9e897836 100644 --- a/endpoints/getting-started/container-engine.yaml +++ b/endpoints/getting-started/container-engine.yaml @@ -46,6 +46,7 @@ spec: secret: secretName: nginx-ssl containers: + # [START esp] - name: esp image: b.gcr.io/endpoints/endpoints-runtime:0.3 args: [ @@ -55,6 +56,7 @@ spec: "-s", "SERVICE_NAME", "-v", "SERVICE_VERSION", ] + # [END esp] ports: - containerPort: 8080 - containerPort: 443 diff --git a/endpoints/getting-started/swagger.yaml b/endpoints/getting-started/swagger.yaml index 71bac9ce62..b446aa06d2 100644 --- a/endpoints/getting-started/swagger.yaml +++ b/endpoints/getting-started/swagger.yaml @@ -1,9 +1,11 @@ +# [START swagger] swagger: "2.0" info: description: "A simple Google Cloud Endpoints API example." title: "Endpoints Example" version: "1.0.0" host: "YOUR-PROJECT-ID.appspot.com" +# [END swagger] basePath: "/" consumes: - "application/json" From db691e552d4093c7de32775e263e3c447d68b7b9 Mon Sep 17 00:00:00 2001 From: Kevin Deus Date: Thu, 3 Nov 2016 13:19:45 -0700 Subject: [PATCH 6/8] Switch to http container-engine.yaml --- endpoints/getting-started/container-engine.yaml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/endpoints/getting-started/container-engine.yaml b/endpoints/getting-started/container-engine.yaml index ec9e897836..f939ed40dc 100644 --- a/endpoints/getting-started/container-engine.yaml +++ b/endpoints/getting-started/container-engine.yaml @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. - apiVersion: v1 kind: Service metadata: @@ -23,9 +22,6 @@ spec: targetPort: 8080 protocol: TCP name: http - - port: 443 - protocol: TCP - name: https selector: app: esp-echo type: LoadBalancer @@ -41,17 +37,12 @@ spec: labels: app: esp-echo spec: - volumes: - - name: nginx-ssl - secret: - secretName: nginx-ssl containers: # [START esp] - name: esp image: b.gcr.io/endpoints/endpoints-runtime:0.3 args: [ "-p", "8080", - "-S", "443", "-a", "127.0.0.1:8081", "-s", "SERVICE_NAME", "-v", "SERVICE_VERSION", @@ -59,11 +50,6 @@ spec: # [END esp] ports: - containerPort: 8080 - - containerPort: 443 - volumeMounts: - - mountPath: /etc/nginx/ssl - name: nginx-ssl - readOnly: true - name: echo image: b.gcr.io/endpoints/echo:latest ports: From 804239724c5ead3aba73e43ab270a004802339f3 Mon Sep 17 00:00:00 2001 From: Kevin Deus Date: Thu, 3 Nov 2016 13:39:03 -0700 Subject: [PATCH 7/8] Added trailing newline --- endpoints/getting-started/Dockerfile.custom | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/endpoints/getting-started/Dockerfile.custom b/endpoints/getting-started/Dockerfile.custom index c9ad24c465..3c9f9fe70c 100644 --- a/endpoints/getting-started/Dockerfile.custom +++ b/endpoints/getting-started/Dockerfile.custom @@ -5,4 +5,4 @@ WORKDIR /app RUN npm install ENV PORT=8081 -ENTRYPOINT ["npm", "start"] \ No newline at end of file +ENTRYPOINT ["npm", "start"] From 926d9fa942f03486149c3233d1d770fc92d4c98e Mon Sep 17 00:00:00 2001 From: Kevin Deus Date: Thu, 3 Nov 2016 13:39:19 -0700 Subject: [PATCH 8/8] Changed to point at Node.js-specific image --- endpoints/getting-started/container-engine.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/endpoints/getting-started/container-engine.yaml b/endpoints/getting-started/container-engine.yaml index f939ed40dc..6d07c37013 100644 --- a/endpoints/getting-started/container-engine.yaml +++ b/endpoints/getting-started/container-engine.yaml @@ -51,6 +51,6 @@ spec: ports: - containerPort: 8080 - name: echo - image: b.gcr.io/endpoints/echo:latest + image: gcr.io/google-samples/node-echo:1.0 ports: - containerPort: 8081