Skip to content

Commit 814a99a

Browse files
authored
Add a sample for streaming callables (#1185)
1 parent 26c4b78 commit 814a99a

File tree

10 files changed

+5267
-0
lines changed

10 files changed

+5267
-0
lines changed

Node/pnpm-lock.yaml

+299
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
firebase-debug.log*
8+
firebase-debug.*.log*
9+
10+
# Firebase cache
11+
.firebase/
12+
13+
# Firebase config
14+
15+
# Uncomment this if you'd like others to create their own Firebase project.
16+
# For a team working on the same Firebase project(s), it is recommended to leave
17+
# it commented so all members can deploy to the same project(s) in .firebaserc.
18+
# .firebaserc
19+
20+
# Runtime data
21+
pids
22+
*.pid
23+
*.seed
24+
*.pid.lock
25+
26+
# Directory for instrumented libs generated by jscoverage/JSCover
27+
lib-cov
28+
29+
# Coverage directory used by tools like istanbul
30+
coverage
31+
32+
# nyc test coverage
33+
.nyc_output
34+
35+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
36+
.grunt
37+
38+
# Bower dependency directory (https://bower.io/)
39+
bower_components
40+
41+
# node-waf configuration
42+
.lock-wscript
43+
44+
# Compiled binary addons (http://nodejs.org/api/addons.html)
45+
build/Release
46+
47+
# Dependency directories
48+
node_modules/
49+
50+
# Optional npm cache directory
51+
.npm
52+
53+
# Optional eslint cache
54+
.eslintcache
55+
56+
# Optional REPL history
57+
.node_repl_history
58+
59+
# Output of 'npm pack'
60+
*.tgz
61+
62+
# Yarn Integrity file
63+
.yarn-integrity
64+
65+
# dotenv environment variables file
66+
.env
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Firebase HTTPS Callable functions streaming quickstart
2+
================================================
3+
4+
This quickstart demonstrates how to send requests to a server-side function and _stream_ a response to a client SDK.
5+
6+
[Read more about Cloud Functions for Firebase](https://firebase.google.com/docs/functions/)
7+
8+
9+
Getting Started
10+
---------------
11+
12+
1. Install dependencies with `npm install`
13+
1. Start the hosting and functions emulators with `firebase emulators:start --only functions,hosting`
14+
1. Visit the url of the emulated Hosting site, and click "Get forecasts"
15+
16+
License
17+
-------
18+
19+
© Google, 2025. Licensed under an [Apache-2](../../../LICENSE) license.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"functions": {
3+
"codebase": "callable-functions",
4+
"predeploy": [
5+
"npm --prefix \"$RESOURCE_DIR\" run lint"
6+
]
7+
},
8+
"hosting": {
9+
"public": "website"
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Copyright 2023 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
module.exports = {
18+
root: true,
19+
env: {
20+
es2020: true,
21+
node: true,
22+
},
23+
extends: [
24+
"eslint:recommended",
25+
"google",
26+
],
27+
rules: {
28+
quotes: ["error", "double"],
29+
},
30+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* Copyright 2022 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
// [START full-sample]
18+
// Dependencies for callable functions.
19+
const {onCall, HttpsError} = require("firebase-functions/v2/https");
20+
21+
/**
22+
* Gets the weather from the national weather service
23+
* https://www.weather.gov/documentation/services-web-api
24+
*
25+
* @param {number} lat
26+
* @param {number} lng
27+
*/
28+
async function weatherForecastApi(lat, lng) {
29+
const resp = await fetch(`https://api.weather.gov/points/${lat},${lng}`);
30+
31+
if (!resp.ok) {
32+
return `error: ${resp.status}`;
33+
}
34+
35+
const forecastUrl = (await resp.json()).properties.forecast;
36+
const forecastResp = await fetch(forecastUrl);
37+
38+
if (!forecastResp.ok) {
39+
return `error: ${forecastResp.status}`;
40+
}
41+
42+
// add an artificial wait to emphasize stream-iness
43+
await new Promise((resolve) => setTimeout(resolve, Math.random() * 1500));
44+
45+
return forecastResp.json();
46+
}
47+
48+
// [START streaming-callable]
49+
exports.getForecast = onCall(async (request, response) => {
50+
if (request.data?.locations?.length < 1) {
51+
throw new HttpsError("invalid-argument", "Missing locations to forecast");
52+
}
53+
54+
// fetch forecast data for all requested locations
55+
const allRequests = request.data.locations.map(
56+
async ({latitude, longitude}) => {
57+
const forecast = await weatherForecastApi(latitude, longitude);
58+
const result = {latitude, longitude, forecast};
59+
60+
// clients that support streaming will have each
61+
// forecast streamed to them as they complete
62+
if (request.acceptsStreaming) {
63+
response.sendChunk(result);
64+
}
65+
66+
return result;
67+
},
68+
);
69+
70+
// Return the full set of data to all clients
71+
return Promise.all(allRequests);
72+
});
73+
// [END streaming-callable]
74+
// [END full-sample]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "callable-functions-streaming",
3+
"description": "Cloud Functions for Firebase",
4+
"scripts": {
5+
"lint": "eslint .",
6+
"lintfix": "eslint . --fix",
7+
"serve": "firebase emulators:start --only functions",
8+
"shell": "firebase functions:shell",
9+
"start": "npm run shell",
10+
"deploy": "firebase deploy --only functions",
11+
"logs": "firebase functions:log",
12+
"compile": "cp ../../../../tsconfig.template.json ./tsconfig-compile.json && tsc --project tsconfig-compile.json"
13+
},
14+
"engines": {
15+
"node": "22"
16+
},
17+
"main": "index.js",
18+
"dependencies": {
19+
"firebase-admin": "^13.0.2",
20+
"firebase-functions": "^6.3.1"
21+
},
22+
"devDependencies": {
23+
"eslint": "^8.57.1",
24+
"eslint-config-google": "^0.14.0",
25+
"firebase-functions-test": "^3.4.0"
26+
},
27+
"private": true
28+
}

0 commit comments

Comments
 (0)