diff --git a/.github/workflows/test_dart.yml b/.github/workflows/test_dart.yml new file mode 100644 index 0000000000..751df78226 --- /dev/null +++ b/.github/workflows/test_dart.yml @@ -0,0 +1,57 @@ +# Copyright 2026 Google LLC +# +# 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. + +name: CI Tests + +on: + pull_request: + paths: + - 'Dart/**' + + push: + branches: + - main + paths: + - 'Dart/**' + +env: + CI: true + +jobs: + unit: + runs-on: ubuntu-latest + strategy: + matrix: + dart-version: + - "3.11.4" + steps: + - uses: actions/checkout@v4 + + - name: Set up Dart ${{ matrix.dart-version }} + uses: dart-lang/setup-dart@v1.6.0 + with: + sdk: ${{ matrix.dart-version }} + + - name: Test Dart Samples + run: | + set -e + for dir in $(find Dart -name pubspec.yaml -exec dirname {} \;); do + echo "::group::Testing $dir" + cd "$dir" + dart pub get + dart format --set-exit-if-changed . + dart analyze . + cd - > /dev/null + echo "::endgroup::" + done diff --git a/.gitignore b/.gitignore index 127eafecb4..9535b26697 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ **/.firebase **/.firebaserc **/.runtimeconfig.json +**/functions.yaml +**/firestore-debug.log */npm-debug.log lerna-debug.log *~ diff --git a/Dart/quickstarts/callable-functions-streaming/.gitignore b/Dart/quickstarts/callable-functions-streaming/.gitignore new file mode 100644 index 0000000000..8ae1a6ef6d --- /dev/null +++ b/Dart/quickstarts/callable-functions-streaming/.gitignore @@ -0,0 +1,5 @@ +.dart_tool/ +.packages +build/ +*.dart_tool +pubspec.lock diff --git a/Dart/quickstarts/callable-functions-streaming/README.md b/Dart/quickstarts/callable-functions-streaming/README.md new file mode 100644 index 0000000000..c2a4c5f1a4 --- /dev/null +++ b/Dart/quickstarts/callable-functions-streaming/README.md @@ -0,0 +1,31 @@ +# Firebase SDK for Cloud Functions Quickstart - Callable Functions Streaming + +This quickstart demonstrates how to send requests to a server-side function and _stream_ a response to a client SDK using Dart. + +[Read more about Cloud Functions for Firebase](https://firebase.google.com/docs/functions/) + + +## Frontend Client + +You can find the frontend code in [`../../../Node/quickstarts/callable-functions-streaming/website`](../../../Node/quickstarts/callable-functions-streaming/website). + +**IMPORTANT NOTE**: Due to limitations during the experimental release of Dart support in Cloud Functions for Firebase, the code in the website must be modified. Instead of using `httpsCallable`, you must use [`httpsCallableFromURL`](https://firebase.google.com/docs/reference/js/functions.md#httpscallablefromurl_7af6987) and pass the full function url (`https://.run.app` or the emulator equivalent), which can be found in the Cloud console or the emulator logs. + + +## Deploy the app to prod + +First you need to get the `dart` dependencies of the functions: + +```bash +dart pub get +``` + +Deploy to Firebase using the following command: + +```bash +firebase deploy --only functions +``` + +## License + +© Google, 2026. Licensed under an [Apache-2](../../../LICENSE) license. diff --git a/Dart/quickstarts/callable-functions-streaming/bin/server.dart b/Dart/quickstarts/callable-functions-streaming/bin/server.dart new file mode 100644 index 0000000000..eb73c36d32 --- /dev/null +++ b/Dart/quickstarts/callable-functions-streaming/bin/server.dart @@ -0,0 +1,92 @@ +// Copyright 2026 Google LLC +// +// 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 full-sample] +// Dependencies for callable functions. +import 'dart:convert'; +import 'dart:math'; + +import 'package:firebase_functions/firebase_functions.dart'; +import 'package:http/http.dart' as http; + +/// Gets the weather from the national weather service +/// https://www.weather.gov/documentation/services-web-api +Future weatherForecastApi(num lat, num lng) async { + final resp = await http.get( + Uri.parse('https://api.weather.gov/points/$lat,$lng'), + ); + + if (resp.statusCode >= 400) { + return 'error: ${resp.statusCode}'; + } + + final pointData = jsonDecode(resp.body) as Map; + final forecastUrl = pointData['properties']['forecast'] as String; + final forecastResp = await http.get(Uri.parse(forecastUrl)); + + if (forecastResp.statusCode >= 400) { + return 'error: ${forecastResp.statusCode}'; + } + + // add an artificial wait to emphasize stream-iness + final randomWait = Random().nextDouble() * 1500; + await Future.delayed(Duration(milliseconds: randomWait.toInt())); + + return jsonDecode(forecastResp.body); +} + +void main(List args) async { + await fireUp(args, (firebase) { + // [START streaming-callable] + firebase.https.onCall(name: 'getForecast', (request, response) async { + final data = request.data as Map?; + final locations = data?['locations'] as List?; + + if (locations == null || locations.isEmpty) { + throw InvalidArgumentError('Missing locations to forecast'); + } + + // fetch forecast data for all requested locations + final allRequests = locations.map((location) async { + if (location case { + 'latitude': num latitude, + 'longitude': num longitude, + }) { + final forecast = await weatherForecastApi(latitude, longitude); + final result = { + 'latitude': latitude, + 'longitude': longitude, + 'forecast': forecast, + }; + + // clients that support streaming will have each + // forecast streamed to them as they complete + if (request.acceptsStreaming) { + await response.sendChunk(result); + } + + return result; + } + + throw InvalidArgumentError('Invalid location format'); + }); + + // Return the full set of data to all clients + return CallableResult(await Future.wait(allRequests)); + }); + // [END streaming-callable] + }); +} + +// [END full-sample] diff --git a/Dart/quickstarts/callable-functions-streaming/firebase.json b/Dart/quickstarts/callable-functions-streaming/firebase.json new file mode 100644 index 0000000000..817dd26e03 --- /dev/null +++ b/Dart/quickstarts/callable-functions-streaming/firebase.json @@ -0,0 +1,6 @@ +{ + "functions": { + "source": ".", + "codebase": "dart-quickstarts-callable-functions-streaming" + } +} diff --git a/Dart/quickstarts/callable-functions-streaming/pubspec.yaml b/Dart/quickstarts/callable-functions-streaming/pubspec.yaml new file mode 100644 index 0000000000..6e8a85407c --- /dev/null +++ b/Dart/quickstarts/callable-functions-streaming/pubspec.yaml @@ -0,0 +1,33 @@ +name: callable_functions_streaming +description: Streaming callable examples for Firebase Functions for Dart +publish_to: none + +environment: + sdk: ^3.11.0 + +dependencies: + firebase_functions: + git: + url: https://github.com/firebase/firebase-functions-dart + ref: main + http: ^1.2.0 + +dev_dependencies: + build_runner: ^2.10.5 + lints: ^6.0.0 + +dependency_overrides: + firebase_functions: + git: + url: https://github.com/firebase/firebase-functions-dart + ref: main + dart_firebase_admin: + git: + url: https://github.com/firebase/firebase-admin-dart + path: packages/dart_firebase_admin + ref: main + google_cloud_firestore: + git: + url: https://github.com/firebase/firebase-admin-dart + path: packages/google_cloud_firestore + ref: main diff --git a/Dart/quickstarts/callable-functions/.gitignore b/Dart/quickstarts/callable-functions/.gitignore new file mode 100644 index 0000000000..8ae1a6ef6d --- /dev/null +++ b/Dart/quickstarts/callable-functions/.gitignore @@ -0,0 +1,5 @@ +.dart_tool/ +.packages +build/ +*.dart_tool +pubspec.lock diff --git a/Dart/quickstarts/callable-functions/README.md b/Dart/quickstarts/callable-functions/README.md new file mode 100644 index 0000000000..fc96b7843a --- /dev/null +++ b/Dart/quickstarts/callable-functions/README.md @@ -0,0 +1,29 @@ +# Firebase SDK for Cloud Functions Quickstart - Callable Functions + +This quickstart demonstrates how to send requests to a server-side function and get a response back using one of the Client SDKs. + +## Introduction + +The function `addNumbers` Returns the sum of two numbers. + +Further reading: + + - [Read more about Cloud Functions for Firebase](https://firebase.google.com/docs/functions/) + +## Deploy the app to prod + +First you need to get the `dart` dependencies of the functions: + +```bash +dart pub get +``` + +Deploy to Firebase using the following command: + +```bash +firebase deploy --only functions +``` + +## License + +© Google, 2026. Licensed under an [Apache-2](../../../LICENSE) license. diff --git a/Dart/quickstarts/callable-functions/bin/server.dart b/Dart/quickstarts/callable-functions/bin/server.dart new file mode 100644 index 0000000000..5feeb7f68a --- /dev/null +++ b/Dart/quickstarts/callable-functions/bin/server.dart @@ -0,0 +1,70 @@ +// Copyright 2026 Google LLC +// +// 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 imports] +// Dependencies for callable functions. +import 'package:firebase_functions/firebase_functions.dart'; +// [END imports] + +void main(List args) async { + await fireUp(args, (firebase) { + // [START allAdd] + // [START addFunctionTrigger] + // Adds two numbers to each other. + firebase.https.onCall(name: 'addNumbers', (request, response) async { + // [END addFunctionTrigger] + // [START readAddData] + // Numbers passed from the client. + final data = request.data as Map?; + final firstNumber = data?['firstNumber']; + final secondNumber = data?['secondNumber']; + // [END readAddData] + + // [START addHttpsError] + // Checking that attributes are present and are numbers. + if (firstNumber is! num || secondNumber is! num) { + // Throwing an HttpsError so that the client gets the error details. + throw InvalidArgumentError( + 'The function must be called with two arguments "firstNumber" and "secondNumber" which must both be numbers.', + ); + } + // [END addHttpsError] + + // [START authIntegration] + // Authentication / user information is automatically added to the request. + final uid = request.auth?.uid; + final token = request.auth?.token; + final name = token?['name']; + final picture = token?['picture']; + final email = token?['email']; + + // Use variables to suppress 'unused' lint warnings + print( + 'User details: uid=$uid, name=$name, picture=$picture, email=$email', + ); + // [END authIntegration] + + // [START returnAddData] + // returning result. + return CallableResult({ + 'firstNumber': firstNumber, + 'secondNumber': secondNumber, + 'operator': '+', + 'operationResult': firstNumber + secondNumber, + }); + // [END returnAddData] + }); + // [END allAdd] + }); +} diff --git a/Dart/quickstarts/callable-functions/firebase.json b/Dart/quickstarts/callable-functions/firebase.json new file mode 100644 index 0000000000..fd5f337b9d --- /dev/null +++ b/Dart/quickstarts/callable-functions/firebase.json @@ -0,0 +1,6 @@ +{ + "functions": { + "source": ".", + "codebase": "dart-quickstarts-callable-functions" + } +} diff --git a/Dart/quickstarts/callable-functions/pubspec.yaml b/Dart/quickstarts/callable-functions/pubspec.yaml new file mode 100644 index 0000000000..edd292f0c0 --- /dev/null +++ b/Dart/quickstarts/callable-functions/pubspec.yaml @@ -0,0 +1,32 @@ +name: callable_functions +description: Callable examples for Firebase Functions for Dart +publish_to: none + +environment: + sdk: ^3.11.0 + +dependencies: + firebase_functions: + git: + url: https://github.com/firebase/firebase-functions-dart + ref: main + +dev_dependencies: + build_runner: ^2.10.5 + lints: ^6.0.0 + +dependency_overrides: + firebase_functions: + git: + url: https://github.com/firebase/firebase-functions-dart + ref: main + dart_firebase_admin: + git: + url: https://github.com/firebase/firebase-admin-dart + path: packages/dart_firebase_admin + ref: main + google_cloud_firestore: + git: + url: https://github.com/firebase/firebase-admin-dart + path: packages/google_cloud_firestore + ref: main diff --git a/Dart/quickstarts/https-increment-number/.gitignore b/Dart/quickstarts/https-increment-number/.gitignore new file mode 100644 index 0000000000..8ae1a6ef6d --- /dev/null +++ b/Dart/quickstarts/https-increment-number/.gitignore @@ -0,0 +1,5 @@ +.dart_tool/ +.packages +build/ +*.dart_tool +pubspec.lock diff --git a/Dart/quickstarts/https-increment-number/README.md b/Dart/quickstarts/https-increment-number/README.md new file mode 100644 index 0000000000..a84020417d --- /dev/null +++ b/Dart/quickstarts/https-increment-number/README.md @@ -0,0 +1,48 @@ +# HTTPS Increment Number Quickstart + +This quickstart demonstrates how to handle HTTP requests for Cloud Functions using Dart. +It features two endpoints: +- `incrementLocal`: Simple POST request that takes a local count and returns it incremented by 1. +- `incrementSynced`: GET and POST endpoints that sync a counter variable to Firestore, returning the newly updated count. + + + +## Local Testing + +First, fetch dependencies: +```bash +dart pub get +``` + +Then, you can use the Firebase CLI to test the function locally. To ensure both endpoints work properly, make sure to start both the functions and firestore emulators: +```bash +firebase emulators:start --project="demo-example" --only firestore,functions +``` + +### Testing `incrementLocal` + +In a separate terminal, use cURL to POST to the function (replace the URL with the one provided by the emulator): + +```bash +curl -X POST http://127.0.0.1:5001/demo-example/us-central1/increment-local \ + -H "Content-Type: application/json" \ + -d '{"count": 5}' +``` + +You should see: +```json +{"message":"Local increment complete!","newCount":6} +``` + +### Testing `incrementSynced` + +To test using Firestore, fetch the initial count: +```bash +curl -X GET http://127.0.0.1:5001/demo-example/us-central1/increment-synced +``` + +Then increment it using POST: +```bash +curl -X POST http://127.0.0.1:5001/demo-example/us-central1/increment-synced \ + -H "Content-Type: application/json" +``` diff --git a/Dart/quickstarts/https-increment-number/bin/server.dart b/Dart/quickstarts/https-increment-number/bin/server.dart new file mode 100644 index 0000000000..12f11c1dc5 --- /dev/null +++ b/Dart/quickstarts/https-increment-number/bin/server.dart @@ -0,0 +1,65 @@ +import 'dart:convert'; +import 'package:firebase_functions/firebase_functions.dart'; +import 'package:google_cloud_firestore/google_cloud_firestore.dart' + show FieldValue; +import 'package:shared/shared.dart'; + +void main(List args) async { + await fireUp(args, (firebase) { + // Listen for calls to the http request and name defined in the shared package. + firebase.https.onRequest(name: incrementCallable, (request) async { + // In a production app, verify the user with request.auth?.uid here. + print('Incrementing counter on the server...'); + + // Get firestore database instance + final firestore = firebase.adminApp.firestore(); + + // Get a reference to the counter document + final counterDoc = firestore.collection('counters').doc('global'); + + // Get the current snapshot for the count data + final snapshot = await counterDoc.get(); + + // Increment response we will send back + IncrementResponse incrementResponse; + + // Check for the current count and if the snapshot exists + if (snapshot.data() case {'count': int value} when snapshot.exists) { + if (request.method == 'GET') { + // Get the current result + incrementResponse = IncrementResponse( + success: true, + message: 'Read-only sync complete', + newCount: value, + ); + } else if (request.method == 'POST') { + // Increment count by one + final step = request.url.queryParameters['step'] as int? ?? 1; + await counterDoc.update({'count': FieldValue.increment(step)}); + incrementResponse = IncrementResponse( + success: true, + message: 'Atomic increment complete', + newCount: value + 1, + ); + } else { + return Response(405, body: 'Method Not Allowed'); + } + } else { + // Create a new document with a count of 1 + await counterDoc.set({'count': 1}); + incrementResponse = const IncrementResponse( + success: true, + message: 'Cloud-sync complete', + newCount: 1, + ); + } + + // Return the response as JSON + return Response( + 200, + body: jsonEncode(incrementResponse.toJson()), + headers: {'Content-Type': 'application/json'}, + ); + }); + }); +} diff --git a/Dart/quickstarts/https-increment-number/firebase.json b/Dart/quickstarts/https-increment-number/firebase.json new file mode 100644 index 0000000000..e155cc8e57 --- /dev/null +++ b/Dart/quickstarts/https-increment-number/firebase.json @@ -0,0 +1,9 @@ +{ + "functions": { + "source": ".", + "codebase": "dart-quickstarts-https-increment-number" + }, + "firestore": { + "rules": "firestore.rules" + } +} diff --git a/Dart/quickstarts/https-increment-number/firestore.rules b/Dart/quickstarts/https-increment-number/firestore.rules new file mode 100644 index 0000000000..0e33c9c2d4 --- /dev/null +++ b/Dart/quickstarts/https-increment-number/firestore.rules @@ -0,0 +1,8 @@ +rules_version = '2'; +service cloud.firestore { + match /databases/{database}/documents { + match /{document=**} { + allow read: if true; + } + } +} diff --git a/Dart/quickstarts/https-increment-number/pubspec.yaml b/Dart/quickstarts/https-increment-number/pubspec.yaml new file mode 100644 index 0000000000..b18643ae2d --- /dev/null +++ b/Dart/quickstarts/https-increment-number/pubspec.yaml @@ -0,0 +1,40 @@ +name: https_increment_number +description: HTTPS trigger examples showcasing state increment operations. +publish_to: none + +environment: + sdk: ^3.11.0 + +dependencies: + shared: + path: ../shared + firebase_functions: + git: + url: https://github.com/firebase/firebase-functions-dart + ref: main + dart_firebase_admin: + git: + url: https://github.com/firebase/firebase-admin-dart + path: packages/dart_firebase_admin + ref: main + google_cloud_firestore: + git: + url: https://github.com/firebase/firebase-admin-dart + path: packages/google_cloud_firestore + ref: main + +dev_dependencies: + build_runner: ^2.10.5 + lints: ^6.0.0 + +dependency_overrides: + dart_firebase_admin: + git: + url: https://github.com/firebase/firebase-admin-dart + path: packages/dart_firebase_admin + ref: main + google_cloud_firestore: + git: + url: https://github.com/firebase/firebase-admin-dart + path: packages/google_cloud_firestore + ref: main diff --git a/Dart/quickstarts/https-time-server/.gitignore b/Dart/quickstarts/https-time-server/.gitignore new file mode 100644 index 0000000000..8ae1a6ef6d --- /dev/null +++ b/Dart/quickstarts/https-time-server/.gitignore @@ -0,0 +1,5 @@ +.dart_tool/ +.packages +build/ +*.dart_tool +pubspec.lock diff --git a/Dart/quickstarts/https-time-server/README.md b/Dart/quickstarts/https-time-server/README.md new file mode 100644 index 0000000000..36b7841fe0 --- /dev/null +++ b/Dart/quickstarts/https-time-server/README.md @@ -0,0 +1,95 @@ +# Firebase SDK for Cloud Functions Quickstart - HTTPS trigger + +This quickstart demonstrates using the **Firebase SDK for Cloud Functions** with an HTTPS trigger through building an endpoint returning the current time. + + +## Introduction + +The function `date` returns the current server date. You can pass it a `format` URL Query parameter to format the date. + +Further reading: + + - [Read more about the Firebase SDK for Cloud Functions](https://firebase.google.com/docs/functions) + + +## Initial setup, build tools and dependencies + +### 1. Clone this repo + +Clone or download this repo and open the `Dart/quickstarts/https-time-server` directory. + + +### 2. Create a Firebase project and configure the quickstart + +Create a Firebase Project on the [Firebase Console](https://console.firebase.google.com). + +Set up your Firebase project by running `firebase use --add`, select your Project ID and follow the instructions. + + +### 3. Install the Firebase CLI and enable Functions on your Firebase CLI + +You need to have installed the Firebase CLI. If you haven't run: + +```bash +npm install -g firebase-tools +``` + +> Doesn't work? You may need to [change npm permissions](https://docs.npmjs.com/getting-started/fixing-npm-permissions). + + +## Deploy the app to prod + +First you need to get the `dart` dependencies of the functions: + +```bash +dart pub get +``` + +This installs locally: + - The Firebase Functions Dart SDK. + - The [intl](https://pub.dev/packages/intl) pub package to format time. + +Deploy to Firebase using the following command: + +```bash +firebase deploy +``` + +This deploys and activates the date Function. + +> The first time you call `firebase deploy` on a new project with Functions will take longer than usual. + + +Alteratively, you can call `firebase emulators:start` to test the functions on the local emulator suite. + + +## Try the sample + +After deploying the function, check the CLI's output to see the URL for your function. + +It will look something like: `https://-..run.app` + +You can also send the format in the request body. For instance using cURL in the command line: + +```bash +curl -H 'Content-Type: application/json' / + -d '{"format": "MMMM d yyyy, h:mm:ss a"}' / + +``` +Formatted dates should be displayed. + +We are responding with a 403 error in case of PUT requests: + +```bash +curl -X PUT -d '{"format": "MMMM d yyyy, h:mm:ss a"}' +``` + + +## Contributing + +We'd love that you contribute to the project. Before doing so please read our [Contributor guide](../../CONTRIBUTING.md). + + +## License + +© Google, 2026. Licensed under an [Apache-2](../../../LICENSE) license. diff --git a/Dart/quickstarts/https-time-server/bin/server.dart b/Dart/quickstarts/https-time-server/bin/server.dart new file mode 100644 index 0000000000..1dd4272b74 --- /dev/null +++ b/Dart/quickstarts/https-time-server/bin/server.dart @@ -0,0 +1,85 @@ +// Copyright 2026 Google LLC +// +// 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 dartHttpImport] +import 'package:firebase_functions/firebase_functions.dart'; +// [END dartHttpImport] + +// [START dartHttpAdditionalImports] +import 'dart:convert'; +import 'package:intl/intl.dart'; +// [END dartHttpAdditionalImports] + +// [START dartHttpAll] +/// Returns the server's date. +/// Options `timeoutSeconds` and `region` are optional. +/// +/// You must provide a `format` URL query parameter or `format` value in +/// the request body with which we'll try to format the date. +/// +/// Format must follow the Dart intl library. See: https://pub.dev/packages/intl +/// +/// Example format: "MMMM d yyyy, h:mm:ss a". +/// Example request using URL query parameters: +/// https://date-..run.app?format=MMMM%20d%20yyyy%2C%20h%3Amm%3Ass%20a +/// Example request using request body with cURL: +/// curl -H 'Content-Type: application/json' / +/// -d '{"format": "MMMM d yyyy, h:mm:ss a"}' / +/// https://date-..run.app +void main(List args) async { + await fireUp(args, (firebase) { + // [START dartHttpTrigger] + firebase.https.onRequest(name: 'date', (request) async { + // [END dartHttpTrigger] + + // [START dartHttpSendError] + // Forbidding PUT requests. + if (request.method == 'PUT') { + return Response.forbidden('Forbidden!'); + } + // [END dartHttpSendError] + + // Reading date format from URL query parameter. + // [START dartHttpReadQueryParam] + var format = request.url.queryParameters['format']; + // [END dartHttpReadQueryParam] + + // Reading date format from request body query parameter + if (format == null) { + // [START dartHttpReadBodyParam] + final bodyString = await request.readAsString(); + try { + if (bodyString.isNotEmpty) { + final body = jsonDecode(bodyString) as Map; + format = body['format'] as String?; + } + } catch (e) { + return Response.badRequest(body: 'invalid JSON'); + } + // [END dartHttpReadBodyParam] + } + + // Set a default format if none was provided + format ??= 'MMMM d yyyy, h:mm:ss a'; + + // [START dartHttpSendResponse] + final formattedDate = DateFormat(format).format(DateTime.now()); + print('Sending formatted date: $formattedDate'); + return Response.ok(formattedDate); + // [END dartHttpSendResponse] + }); + }); +} + +// [END dartHttpAll] diff --git a/Dart/quickstarts/https-time-server/firebase.json b/Dart/quickstarts/https-time-server/firebase.json new file mode 100644 index 0000000000..0007f3af35 --- /dev/null +++ b/Dart/quickstarts/https-time-server/firebase.json @@ -0,0 +1,6 @@ +{ + "functions": { + "source": ".", + "codebase": "dart-quickstarts-https-time-server" + } +} diff --git a/Dart/quickstarts/https-time-server/pubspec.yaml b/Dart/quickstarts/https-time-server/pubspec.yaml new file mode 100644 index 0000000000..688c48824a --- /dev/null +++ b/Dart/quickstarts/https-time-server/pubspec.yaml @@ -0,0 +1,39 @@ +name: https_time_server +description: HTTPS trigger examples for Firebase Functions for Dart +publish_to: none + +environment: + sdk: ^3.11.0 + +dependencies: + firebase_functions: + git: + url: https://github.com/firebase/firebase-functions-dart + ref: main + dart_firebase_admin: + git: + url: https://github.com/firebase/firebase-admin-dart + path: packages/dart_firebase_admin + ref: main + google_cloud_firestore: + git: + url: https://github.com/firebase/firebase-admin-dart + path: packages/google_cloud_firestore + ref: main + intl: ^0.20.2 + +dev_dependencies: + build_runner: ^2.10.5 + lints: ^6.0.0 + +dependency_overrides: + dart_firebase_admin: + git: + url: https://github.com/firebase/firebase-admin-dart + path: packages/dart_firebase_admin + ref: main + google_cloud_firestore: + git: + url: https://github.com/firebase/firebase-admin-dart + path: packages/google_cloud_firestore + ref: main diff --git a/Dart/quickstarts/shared/.gitignore b/Dart/quickstarts/shared/.gitignore new file mode 100644 index 0000000000..8ae1a6ef6d --- /dev/null +++ b/Dart/quickstarts/shared/.gitignore @@ -0,0 +1,5 @@ +.dart_tool/ +.packages +build/ +*.dart_tool +pubspec.lock diff --git a/Dart/quickstarts/shared/lib/shared.dart b/Dart/quickstarts/shared/lib/shared.dart new file mode 100644 index 0000000000..bfbc6405b4 --- /dev/null +++ b/Dart/quickstarts/shared/lib/shared.dart @@ -0,0 +1,19 @@ +class IncrementResponse { + final bool success; + final String message; + final int newCount; + + const IncrementResponse({ + required this.success, + required this.message, + required this.newCount, + }); + + Map toJson() => { + 'success': success, + 'message': message, + 'newCount': newCount, + }; +} + +const String incrementCallable = 'incrementSynced'; diff --git a/Dart/quickstarts/shared/pubspec.yaml b/Dart/quickstarts/shared/pubspec.yaml new file mode 100644 index 0000000000..be30da55fa --- /dev/null +++ b/Dart/quickstarts/shared/pubspec.yaml @@ -0,0 +1,6 @@ +name: shared +description: Shared classes. +publish_to: none + +environment: + sdk: ^3.11.0 diff --git a/README.md b/README.md index 61dc2ac07d..9ecbdf405d 100644 --- a/README.md +++ b/README.md @@ -31,12 +31,19 @@ This quickstart sample demonstrates using **Cloud Functions** triggered by **Fir ### Quickstart: Add numbers and sanitize text with callable functions +- [Dart](/Dart/quickstarts/callable-functions/) - [Node 2nd gen](/Node/quickstarts/callable-functions/) - [Python](/Python/quickstarts/callable-functions) - [Node 1st gen](/Node-1st-gen/quickstarts/callable-functions/) +### Quickstart: Stream responses with callable functions + +- [Dart](/Dart/quickstarts/callable-functions-streaming/) +- [Node 2nd gen](/Node/quickstarts/callable-functions-streaming/) + ### HTTPS trigger quickstart: Time Server +- [Dart](/Dart/quickstarts/https-time-server/) - [Node 2nd gen](/Node/quickstarts/https-time-server/) - [Python](/Python/quickstarts/https-time-server/) - [Node 1st gen](/Node-1st-gen/quickstarts/https-time-server/)