Add v2 interface support for nodes env (#836)
This commit is contained in:
@@ -0,0 +1,11 @@
|
|||||||
|
ARG BUILDER_IMAGE=fission/builder
|
||||||
|
FROM ${BUILDER_IMAGE}
|
||||||
|
# default variant is the official alpine node image (much smaller than the standard image)
|
||||||
|
FROM node:8-alpine
|
||||||
|
|
||||||
|
ARG NODE_ENV
|
||||||
|
ENV NODE_ENV $NODE_ENV
|
||||||
|
|
||||||
|
COPY --from=0 /builder /builder
|
||||||
|
ADD build.sh /usr/local/bin/build
|
||||||
|
RUN chmod +x /usr/local/bin/build
|
||||||
Executable
+3
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
cd ${SRC_PKG}
|
||||||
|
npm install && cp -r ${SRC_PKG} ${DEPLOY_PKG}
|
||||||
@@ -6,6 +6,10 @@
|
|||||||
{
|
{
|
||||||
"name": "Soam Vasani",
|
"name": "Soam Vasani",
|
||||||
"email": "soamvasani@platform9.com"
|
"email": "soamvasani@platform9.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Gary Yeap",
|
||||||
|
"email": "contact@garyyeap.com"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "NodeJS run container for the fission framework",
|
"description": "NodeJS run container for the fission framework",
|
||||||
@@ -20,7 +24,7 @@
|
|||||||
"morgan": "*",
|
"morgan": "*",
|
||||||
"mz": "~2.7.0",
|
"mz": "~2.7.0",
|
||||||
"request": "^2.81.0",
|
"request": "^2.81.0",
|
||||||
"request-promise-native": "^1.0.3",
|
"underscore": ">=1.8.3",
|
||||||
"underscore": ">=1.8.3"
|
"request-promise-native": "^1.0.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,56 +7,86 @@ const express = require('express');
|
|||||||
const app = express();
|
const app = express();
|
||||||
const bodyParser = require('body-parser');
|
const bodyParser = require('body-parser');
|
||||||
const morgan = require('morgan');
|
const morgan = require('morgan');
|
||||||
|
const argv = require('minimist')(process.argv.slice(1));// Command line opts
|
||||||
|
|
||||||
// Command line opts
|
|
||||||
const argv = require('minimist')(process.argv.slice(1));
|
|
||||||
if (!argv.codepath) {
|
|
||||||
argv.codepath = "/userfunc/user";
|
|
||||||
console.log("Codepath defaulting to ", argv.codepath);
|
|
||||||
}
|
|
||||||
if (!argv.port) {
|
if (!argv.port) {
|
||||||
console.log("Port defaulting to 8888");
|
|
||||||
argv.port = 8888;
|
argv.port = 8888;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Node resolves module paths according to a file's location. We load
|
|
||||||
// the file from argv.codepath, but tell users to put dependencies in
|
|
||||||
// the server's package.json; this means the function's dependencies
|
|
||||||
// are in /usr/src/app/node_modules. We could be smarter and have the
|
|
||||||
// function deps in the right place in argv.codepath; but for now we
|
|
||||||
// just symlink the function's node_modules to the server's
|
|
||||||
// node_modules.
|
|
||||||
fs.symlinkSync('/usr/src/app/node_modules', `${path.dirname(argv.codepath)}/node_modules`);
|
|
||||||
|
|
||||||
// User function. Starts out undefined.
|
// User function. Starts out undefined.
|
||||||
let userFunction;
|
let userFunction;
|
||||||
|
|
||||||
//
|
function loadFunction(modulepath, funcname) {
|
||||||
// Specialize this server to a given user function. The user function
|
|
||||||
// is read from argv.codepath; it's expected to be placed there by the
|
|
||||||
// fission runtime.
|
|
||||||
//
|
|
||||||
function specialize(req, res) {
|
|
||||||
// Make sure we're a generic container. (No reuse of containers.
|
|
||||||
// Once specialized, the container remains specialized.)
|
|
||||||
if (userFunction) {
|
|
||||||
res.status(400).send("Not a generic container");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read and load the code. It's placed there securely by the fission runtime.
|
// Read and load the code. It's placed there securely by the fission runtime.
|
||||||
try {
|
try {
|
||||||
var startTime = process.hrtime();
|
let startTime = process.hrtime();
|
||||||
userFunction = require(argv.codepath);
|
// support v1 codepath and v2 entrypoint like 'foo', '', 'index.hello'
|
||||||
var elapsed = process.hrtime(startTime);
|
let userFunction = funcname ? require(modulepath)[funcname] : require(modulepath);
|
||||||
|
let elapsed = process.hrtime(startTime);
|
||||||
console.log(`user code loaded in ${elapsed[0]}sec ${elapsed[1]/1000000}ms`);
|
console.log(`user code loaded in ${elapsed[0]}sec ${elapsed[1]/1000000}ms`);
|
||||||
|
return userFunction;
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error(`user code load error: ${e}`);
|
console.error(`user code load error: ${e}`);
|
||||||
res.status(500).send(JSON.stringify(e));
|
return e;
|
||||||
return;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function withEnsureGeneric(func) {
|
||||||
|
return function(req, res) {
|
||||||
|
// Make sure we're a generic container. (No reuse of containers.
|
||||||
|
// Once specialized, the container remains specialized.)
|
||||||
|
if (userFunction) {
|
||||||
|
res.status(400).send("Not a generic container");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
func(req, res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFunction(func) {
|
||||||
|
return func && func.constructor && func.call && func.apply;
|
||||||
|
}
|
||||||
|
|
||||||
|
function specializeV2(req, res) {
|
||||||
|
// for V2 entrypoint, 'filename.funcname' => ['filename', 'funcname']
|
||||||
|
const entrypoint = req.body.functionName ? req.body.functionName.split('.') : [];
|
||||||
|
// for V2, filepath is dynamic path
|
||||||
|
const modulepath = path.join(req.body.filepath, entrypoint[0] || '');
|
||||||
|
const result = loadFunction(modulepath, entrypoint[1]);
|
||||||
|
|
||||||
|
if(isFunction(result)){
|
||||||
|
userFunction = result;
|
||||||
|
res.status(202).send();
|
||||||
|
} else {
|
||||||
|
res.status(500).send(JSON.stringify(result));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function specialize(req, res) {
|
||||||
|
// Specialize this server to a given user function. The user function
|
||||||
|
// is read from argv.codepath; it's expected to be placed there by the
|
||||||
|
// fission runtime.
|
||||||
|
//
|
||||||
|
const modulepath = argv.codepath || '/userfunc/user';
|
||||||
|
|
||||||
|
// Node resolves module paths according to a file's location. We load
|
||||||
|
// the file from argv.codepath, but tell users to put dependencies in
|
||||||
|
// the server's package.json; this means the function's dependencies
|
||||||
|
// are in /usr/src/app/node_modules. We could be smarter and have the
|
||||||
|
// function deps in the right place in argv.codepath; b ut for now we
|
||||||
|
// just symlink the function's node_modules to the server's
|
||||||
|
// node_modules.
|
||||||
|
fs.symlinkSync('/usr/src/app/node_modules', `${path.dirname(modulepath)}/node_modules`);
|
||||||
|
|
||||||
|
const result = loadFunction(modulepath);
|
||||||
|
|
||||||
|
if(isFunction(result)){
|
||||||
|
userFunction = result;
|
||||||
|
res.status(202).send();
|
||||||
|
} else {
|
||||||
|
res.status(500).send(JSON.stringify(result));
|
||||||
}
|
}
|
||||||
res.status(202).send();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -68,7 +98,8 @@ app.use(bodyParser.json());
|
|||||||
app.use(bodyParser.raw());
|
app.use(bodyParser.raw());
|
||||||
app.use(bodyParser.text({ type : "text/*" }));
|
app.use(bodyParser.text({ type : "text/*" }));
|
||||||
|
|
||||||
app.post('/specialize', specialize);
|
app.post('/specialize', withEnsureGeneric(specialize));
|
||||||
|
app.post('/v2/specialize', withEnsureGeneric(specializeV2));
|
||||||
|
|
||||||
// Generic route -- all http requests go to the user function.
|
// Generic route -- all http requests go to the user function.
|
||||||
app.all('/', function (req, res) {
|
app.all('/', function (req, res) {
|
||||||
|
|||||||
+51
-44
@@ -1,19 +1,19 @@
|
|||||||
# Fission Node.js Examples
|
# Fission Node.js Examples
|
||||||
|
|
||||||
|
This is V2 example, check [here](README_V1.md) for V1.
|
||||||
|
|
||||||
This directory contains several examples to get you started using Node.js with Fission.
|
This directory contains several examples to get you started using Node.js with Fission.
|
||||||
|
|
||||||
## Environment
|
|
||||||
|
|
||||||
Before running any of these functions, make sure you have created a `nodejs` Fission environment:
|
Before running any of these functions, make sure you have created a `nodejs` Fission environment:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create an environment with default nodejs images
|
||||||
|
$ fission env create --name nodeenv --image fission/node-env:latest --builder fission/node-builder:latest
|
||||||
|
# Create zip file from our example
|
||||||
|
$ zip -jr nodejs.zip nodejs/
|
||||||
|
# Create a package with the zip file
|
||||||
|
$ fission pkg create --sourcearchive nodejs.zip --env nodeenv
|
||||||
```
|
```
|
||||||
$ fission env create --name nodejs --image fission/node-env
|
|
||||||
```
|
|
||||||
|
|
||||||
Note: The default `fission/node-env` image is based on Alpine, which is much smaller than the main Debian Node image (65MB vs 680MB) while still being suitable for most use cases.
|
|
||||||
If you need to use the full Debian image use the `fission/node-env-debian` image instead.
|
|
||||||
See the [official Node docker hub repo](https://hub.docker.com/_/node/) for considerations
|
|
||||||
relating to this choice.
|
|
||||||
|
|
||||||
## Function signature
|
## Function signature
|
||||||
|
|
||||||
@@ -27,28 +27,54 @@ module.exports = async function(context) {
|
|||||||
headers: {
|
headers: {
|
||||||
'Foo': 'Bar'
|
'Foo': 'Bar'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Since it is an `async` function, you can `await` `Promise`s, as demonstrated in the `stock.js` function.
|
|
||||||
|
|
||||||
## hello.js
|
## hello.js
|
||||||
|
|
||||||
This is a basic "Hello, World!" example. It simply returns a status of `200` and text body.
|
This is a basic "Hello, World!" example. It simply returns a status of `200` and text body.
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
Since it is an `async` function, you can `await` `Promise`s, as demonstrated in the `weather.js` function.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Upload your function code to fission
|
# Create a function
|
||||||
$ fission function create --name hello --env nodejs --code hello.js
|
$ fission fn create --name hello --pkg [pkgname] --entrypoint "hello"
|
||||||
|
|
||||||
# Map GET /hello to your new function
|
# Test the function
|
||||||
$ fission route create --method GET --url /hello --function hello
|
$ fission fn test --name hello
|
||||||
|
```
|
||||||
|
|
||||||
# Run the function.
|
## index.js
|
||||||
$ curl http://$FISSION_ROUTER/hello
|
|
||||||
Hello, world!
|
This file does nothing but for demonstrating `require` feature.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
```bash
|
||||||
|
# Create a function, you can skip `--entrypoint` as node will look for `index.js` by default
|
||||||
|
$ fission fn create --name index --pkg [pkgname]
|
||||||
|
|
||||||
|
# Test the function
|
||||||
|
$ fission fn test --name index
|
||||||
|
```
|
||||||
|
|
||||||
|
## multi-entry.js
|
||||||
|
|
||||||
|
This is a multiple exports example. There are two exports: entry1 and entry2
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
```bash
|
||||||
|
# Create a function for entry1
|
||||||
|
$ fission fn create --name entry1 --pkg [pkgname] --entrypoint "multi-entry.entry1"
|
||||||
|
|
||||||
|
# Test the function
|
||||||
|
$ fission fn test --name entry1
|
||||||
|
|
||||||
|
# Create a function for entry2
|
||||||
|
$ fission fn create --name entry2 --pkg [pkgname] --entrypoint "multi-entry.entry2"
|
||||||
|
|
||||||
|
# Test the function
|
||||||
|
$ fission fn test --name entry2
|
||||||
```
|
```
|
||||||
|
|
||||||
## hello-callback.js
|
## hello-callback.js
|
||||||
@@ -60,8 +86,8 @@ This is a basic "Hello, World!" example implemented with the legacy callback imp
|
|||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Upload your function code to fission
|
# Create a function
|
||||||
$ fission function create --name hello-callback --env nodejs --code hello-callback.js
|
$ fission fn create --name hello-callback --pkg [pkgname] --entrypoint "hello-callback"
|
||||||
|
|
||||||
# Map GET /hello-callback to your new function
|
# Map GET /hello-callback to your new function
|
||||||
$ fission route create --method GET --url /hello-callback --function hello-callback
|
$ fission route create --method GET --url /hello-callback --function hello-callback
|
||||||
@@ -71,25 +97,6 @@ $ curl http://$FISSION_ROUTER/hello-callback
|
|||||||
Hello, world!
|
Hello, world!
|
||||||
```
|
```
|
||||||
|
|
||||||
## stock.js
|
|
||||||
|
|
||||||
This is a basic example of how you can easily use asynchronous requests in your functions. By default, the Node.js environment makes the [`request-promise-native`](https://github.com/request/request-promise-native) library available. In this example, the Google Finance API is used to determine when a stock was last traded.
|
|
||||||
|
|
||||||
### Usage
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Upload your function code to fission
|
|
||||||
$ fission function create --name stock --env nodejs --code stock.js
|
|
||||||
|
|
||||||
# Map GET /stock to your new function
|
|
||||||
$ fission route create --method POST --url /stock --function stock
|
|
||||||
|
|
||||||
# Run the function.
|
|
||||||
$ curl -H "Content-Type: application/json" -X POST -d '{"symbol":"AAPL"}' http://$FISSION_ROUTER/stock
|
|
||||||
|
|
||||||
{"text":"AAPL last traded at 138.99"}
|
|
||||||
```
|
|
||||||
|
|
||||||
## kubeEventsSlack.js
|
## kubeEventsSlack.js
|
||||||
|
|
||||||
This example watches Kubernetes events and sends them to a Slack channel. To use this, create an incoming webhook for your Slack channel, and replace the `slackWebhookPath` in the example code.
|
This example watches Kubernetes events and sends them to a Slack channel. To use this, create an incoming webhook for your Slack channel, and replace the `slackWebhookPath` in the example code.
|
||||||
@@ -98,7 +105,7 @@ This example watches Kubernetes events and sends them to a Slack channel. To use
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Upload your function code to fission
|
# Upload your function code to fission
|
||||||
$ fission fn create --name kubeEventsSlack --env nodejs --code kubeEventsSlack.js
|
$ fission fn create --name kubeEventsSlack --pkg [pkgname] --entrypoint "hello-callback"
|
||||||
|
|
||||||
# Watch all services in the default namespace:
|
# Watch all services in the default namespace:
|
||||||
$ fission watch create --function kubeEventsSlack --type service --ns default
|
$ fission watch create --function kubeEventsSlack --type service --ns default
|
||||||
@@ -112,7 +119,7 @@ In this example, the Yahoo Weather API is used to current weather at a given loc
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Upload your function code to fission
|
# Upload your function code to fission
|
||||||
$ fission function create --name weather --env nodejs --code weather.js
|
$ fission function create --name weather --pkg [pkgname] --entrypoint "weather"
|
||||||
|
|
||||||
# Map GET /stock to your new function
|
# Map GET /stock to your new function
|
||||||
$ fission route create --method POST --url /weather --function weather
|
$ fission route create --method POST --url /weather --function weather
|
||||||
@@ -121,4 +128,4 @@ $ fission route create --method POST --url /weather --function weather
|
|||||||
$ curl -H "Content-Type: application/json" -X POST -d '{"location":"Sieteiglesias, Spain"}' http://$FISSION_ROUTER/weather
|
$ curl -H "Content-Type: application/json" -X POST -d '{"location":"Sieteiglesias, Spain"}' http://$FISSION_ROUTER/weather
|
||||||
|
|
||||||
{"text":"It is 2 celsius degrees in Sieteiglesias, Spain and Mostly Clear"}
|
{"text":"It is 2 celsius degrees in Sieteiglesias, Spain and Mostly Clear"}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
# Fission Node.js Examples
|
||||||
|
|
||||||
|
This directory contains several examples to get you started using Node.js with Fission.
|
||||||
|
|
||||||
|
## Environment
|
||||||
|
|
||||||
|
Before running any of these functions, make sure you have created a `nodejs` Fission environment:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ fission env create --name nodejs --image fission/node-env
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: The default `fission/node-env` image is based on Alpine, which is much smaller than the main Debian Node image (65MB vs 680MB) while still being suitable for most use cases.
|
||||||
|
If you need to use the full Debian image use the `fission/node-env-debian` image instead.
|
||||||
|
See the [official Node docker hub repo](https://hub.docker.com/_/node/) for considerations
|
||||||
|
relating to this choice.
|
||||||
|
|
||||||
|
## Function signature
|
||||||
|
|
||||||
|
Every Node.js function has the same basic form:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
module.exports = async function(context) {
|
||||||
|
return {
|
||||||
|
status: 200,
|
||||||
|
body: 'Your body here',
|
||||||
|
headers: {
|
||||||
|
'Foo': 'Bar'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Since it is an `async` function, you can `await` `Promise`s, as demonstrated in the `weather.js` function.
|
||||||
|
|
||||||
|
## hello.js
|
||||||
|
|
||||||
|
This is a basic "Hello, World!" example. It simply returns a status of `200` and text body.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Upload your function code to fission
|
||||||
|
$ fission function create --name hello --env nodejs --code hello.js
|
||||||
|
|
||||||
|
# Map GET /hello to your new function
|
||||||
|
$ fission route create --method GET --url /hello --function hello
|
||||||
|
|
||||||
|
# Run the function.
|
||||||
|
$ curl http://$FISSION_ROUTER/hello
|
||||||
|
Hello, world!
|
||||||
|
```
|
||||||
|
|
||||||
|
## hello-callback.js
|
||||||
|
|
||||||
|
This is a basic "Hello, World!" example implemented with the legacy callback implementation. If you declare your function with two arguments (`context`, `callback`), a callback taking three arguments (`status`, `body`, `headers`) is provided.
|
||||||
|
|
||||||
|
⚠️️ Callback support is only provided for backwards compatibility! We recommend that you use `async` functions instead.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Upload your function code to fission
|
||||||
|
$ fission function create --name hello-callback --env nodejs --code hello-callback.js
|
||||||
|
|
||||||
|
# Map GET /hello-callback to your new function
|
||||||
|
$ fission route create --method GET --url /hello-callback --function hello-callback
|
||||||
|
|
||||||
|
# Run the function.
|
||||||
|
$ curl http://$FISSION_ROUTER/hello-callback
|
||||||
|
Hello, world!
|
||||||
|
```
|
||||||
|
|
||||||
|
## kubeEventsSlack.js
|
||||||
|
|
||||||
|
This example watches Kubernetes events and sends them to a Slack channel. To use this, create an incoming webhook for your Slack channel, and replace the `slackWebhookPath` in the example code.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Upload your function code to fission
|
||||||
|
$ fission fn create --name kubeEventsSlack --env nodejs --code kubeEventsSlack.js
|
||||||
|
|
||||||
|
# Watch all services in the default namespace:
|
||||||
|
$ fission watch create --function kubeEventsSlack --type service --ns default
|
||||||
|
```
|
||||||
|
|
||||||
|
## weather.js
|
||||||
|
|
||||||
|
In this example, the Yahoo Weather API is used to current weather at a given location.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Upload your function code to fission
|
||||||
|
$ fission function create --name weather --env nodejs --code weather.js
|
||||||
|
|
||||||
|
# Map GET /stock to your new function
|
||||||
|
$ fission route create --method POST --url /weather --function weather
|
||||||
|
|
||||||
|
# Run the function.
|
||||||
|
$ curl -H "Content-Type: application/json" -X POST -d '{"location":"Sieteiglesias, Spain"}' http://$FISSION_ROUTER/weather
|
||||||
|
|
||||||
|
{"text":"It is 2 celsius degrees in Sieteiglesias, Spain and Mostly Clear"}
|
||||||
|
```
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
module.exports = function(context, callback) {
|
module.exports = function(context, callback) {
|
||||||
callback(200, "Hello, world!\n");
|
callback(200, "Hello, world callback!\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
module.exports = require('./hello');
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
module.exports.entry1 = async function(context) {
|
||||||
|
return {
|
||||||
|
status: 200,
|
||||||
|
body: "Hello, entry 1!\n"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.entry2 = async function(context) {
|
||||||
|
return {
|
||||||
|
status: 200,
|
||||||
|
body: "Hello, entry 2!\n"
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "fission-nodejs-example",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"author": "Soam Vasani",
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Soam Vasani",
|
||||||
|
"email": "soamvasani@platform9.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Gary Yeap",
|
||||||
|
"email": "contact@garyyeap.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Nodejs example for Fission framework",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=7.6.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"body-parser": "*",
|
||||||
|
"co": "~4.6.0",
|
||||||
|
"express": "*",
|
||||||
|
"minimist": "*",
|
||||||
|
"morgan": "*",
|
||||||
|
"mz": "~2.7.0",
|
||||||
|
"request": "^2.81.0",
|
||||||
|
"request-promise-native": "^1.0.3",
|
||||||
|
"underscore": ">=1.8.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const rp = require('request-promise-native');
|
|
||||||
|
|
||||||
module.exports = async function (context) {
|
|
||||||
const body = context.request.body;
|
|
||||||
console.log(`body = ${body}`);
|
|
||||||
const symbol = body['text'].split(' ')[1];
|
|
||||||
|
|
||||||
console.log(`Got symbol: ${symbol}`);
|
|
||||||
|
|
||||||
if (!symbol) {
|
|
||||||
return {
|
|
||||||
status: 400,
|
|
||||||
body: {
|
|
||||||
text: 'You must provide a stock symbol.'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await rp(`http://finance.google.com/finance/info?q=NYSE:${symbol}`);
|
|
||||||
const parsed = JSON.parse(response.slice(3));
|
|
||||||
const lastTrade = parsed[0]['l_cur'];
|
|
||||||
return {
|
|
||||||
status: 200,
|
|
||||||
body: {
|
|
||||||
text: `${symbol} last traded at ${lastTrade}`
|
|
||||||
},
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
return {
|
|
||||||
status: 500,
|
|
||||||
body: e
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user