From 7262ee5f1ec855654a93baba0042dd128870bf51 Mon Sep 17 00:00:00 2001 From: choir27 Date: Wed, 21 Aug 2024 17:06:39 -0400 Subject: [PATCH 1/6] docs: separate bodyText and bodyJson separately. Remove mention of bodyRaw. Add function api endpoint, version, region, and api key to environment variable table --- .../products/functions/develop/+page.markdoc | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/routes/docs/products/functions/develop/+page.markdoc b/src/routes/docs/products/functions/develop/+page.markdoc index e4f4ade3f2..bcb1b17f9d 100644 --- a/src/routes/docs/products/functions/develop/+page.markdoc +++ b/src/routes/docs/products/functions/develop/+page.markdoc @@ -477,9 +477,6 @@ Explore the request object with the following function, which logs all request p * Request * Description --- -* `req.bodyRaw` -* Returns the raw body text data. ---- * `req.bodyText` * Returns text that has been converted from binary data. --- @@ -494,8 +491,8 @@ Explore the request object with the following function, which logs all request p {% multicode %} ```js export default async ({ req, res, log }) => { - log(req.bodyJson); // Raw request body, contains request data - log(JSON.stringify(req.bodyJson)); // Object from parsed JSON request body, otherwise string + log(req.bodyText); // Raw request body, contains request data + log(req.bodyJson); // Object from parsed JSON request body, otherwise string log(JSON.stringify(req.headers)); // String key-value pairs of all request headers, keys are lowercase log(req.scheme); // Value of the x-forwarded-proto header, usually http or https log(req.method); // Request method, such as GET, POST, PUT, DELETE, PATCH, etc. @@ -512,7 +509,6 @@ export default async ({ req, res, log }) => { ```php log($context->req->bodyRaw); // Raw request body, contains request data $context->log(json_encode($context->req->body)); // Object from parsed JSON request body, otherwise string $context->log(json_encode($context->req->headers)); // String key-value pairs of all request headers, keys are lowercase $context->log($context->req->scheme); // Value of the x-forwarded-proto header, usually http or https @@ -629,7 +625,6 @@ using System.Text.Json; public class Handler { public async Task Main(RuntimeContext Context) { - Context.Log(Context.Req.BodyRaw); // Raw request body, contains request data Context.Log(JsonSerializer.Serialize(Context.Req.Body)); // Object from parsed JSON request body, otherwise string Context.Log(JsonSerializer.Serialize(Context.Req.Headers)); // String key-value pairs of all request headers, keys are lowercase Context.Log(Context.Req.Scheme); // Value of the x-forwarded-proto header, usually http or https @@ -683,7 +678,6 @@ public class Main { public RuntimeOutput main(RuntimeContext context) { Gson gson = new Gson(); - context.log(context.getReq().getBodyRaw()); // Raw request body, contains request data context.log(gson.toString(context.getReq().getBody())); // Object from parsed JSON request body, otherwise string context.log(gson.toString(context.getReq().getHeaders())); // String key-value pairs of all request headers, keys are lowercase context.log(context.getReq().getScheme()); // Value of the x-forwarded-proto header, usually http or https @@ -991,7 +985,7 @@ To get the different response types, set one of the following query parameters i ## Logging {% #logging %} To protect user privacy, the request and response objects are not logged to the Appwrite Console by default. -This means, to see logs or debug function executions you need to use the `log()` and `error()` methods. +This means, to see logs or debug function executions you need to use the `log()` and `error()` methods. These logs are only visible to developers with access to the Appwrite Console. Here's an example of using logs and errors. @@ -1144,6 +1138,10 @@ If you need to pass constants or secrets to Appwrite Functions, you can use envi | Variable | Description | |-----------------------------------|------------------------------------------------| +| `APPWRITE_FUNCTION_API_ENDPOINT` | The API endpoint of the running function | +| `APPWRITE_VERSION` | The Appwrite version used to run the function | +| `APPWRITE_REGION` | The region where the function will run from | +| `APPWRITE_FUNCTION_API_KEY` | The function API key is used for server authentication | | `APPWRITE_FUNCTION_ID` | The ID of the running function. | | `APPWRITE_FUNCTION_NAME` | The Name of the running function. | | `APPWRITE_FUNCTION_DEPLOYMENT` | The deployment ID of the running function. | From 3d2cd7d375c1c05aa9603c524c0bfa7f3420ae8b Mon Sep 17 00:00:00 2001 From: choir27 Date: Thu, 22 Aug 2024 10:59:46 -0400 Subject: [PATCH 2/6] add go code snippets, update bodyText/bodyJson, and server-nodejs code snippet highlighting --- .../products/functions/develop/+page.markdoc | 239 +++++++++++++++++- 1 file changed, 225 insertions(+), 14 deletions(-) diff --git a/src/routes/docs/products/functions/develop/+page.markdoc b/src/routes/docs/products/functions/develop/+page.markdoc index bcb1b17f9d..cf6efbb21d 100644 --- a/src/routes/docs/products/functions/develop/+page.markdoc +++ b/src/routes/docs/products/functions/develop/+page.markdoc @@ -206,6 +206,54 @@ export default ({ req, res, log, error }: any) => { }); }; ``` +```go +package handler + +import ( + "fmt" + "os" + + "github.com/appwrite/sdk-for-go/appwrite" + "github.com/open-runtimes/types-for-go/v4/openruntimes" +) + +type Response struct { + Motto string `json:"motto"` + Learn string `json:"learn"` + Connect string `json:"connect"` + GetInspired string `json:"getInspired"` +} + +func Main(Context openruntimes.Context) openruntimes.Response { + // This is your Appwrite function + // It's executed each time we get a request service + var _ = appwrite.NewClient( + appwrite.WithProject(os.Getenv("APPWRITE_FUNCTION_PROJECT_ID")), + appwrite.WithKey(Context.Req.Headers["x-appwrite-key"]), + ) + + // You can log messages to the console + fmt.Println("Hello, Logs!") + + fmt.Fprintln(os.Stderr, "Error:", "Hello, Errors!") + + // The `Context.Req` object contains the request data + if Context.Req.Method == "GET" { + // Send a response with the Context.Res object helpers + // `Context.Res.Text()` dispatches a string back to the client + return Context.Res.Text("Hello, World!") + } + + // `res.json()` is a handy helper for sending JSON + return Context.Res.Json( + Response{ + Motto: "Build like a team of hundreds_", + Learn: "https://appwrite.io/docs", + Connect: "https://appwrite.io/discord", + GetInspired: "https://builtwith.appwrite.io", + }) +} +``` ```dart import 'dart:async'; import 'package:dart_appwrite/dart_appwrite.dart'; @@ -437,7 +485,7 @@ You'll see us use destructuring in examples, which has the following syntax. [Learn more about destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment). {% multicode %} -```js +```server-nodejs // before destructuring export default async function (context) { context.log("This is a log!"); @@ -489,10 +537,10 @@ Explore the request object with the following function, which logs all request p {% /table %} {% multicode %} -```js +```server-nodejs export default async ({ req, res, log }) => { log(req.bodyText); // Raw request body, contains request data - log(req.bodyJson); // Object from parsed JSON request body, otherwise string + log(JSON.stringify(req.bodyJson)); // Object from parsed JSON request body, otherwise string log(JSON.stringify(req.headers)); // String key-value pairs of all request headers, keys are lowercase log(req.scheme); // Value of the x-forwarded-proto header, usually http or https log(req.method); // Request method, such as GET, POST, PUT, DELETE, PATCH, etc. @@ -509,7 +557,7 @@ export default async ({ req, res, log }) => { ```php log(json_encode($context->req->body)); // Object from parsed JSON request body, otherwise string + $context->log(json_encode($context->req->bodyJson));// Object from parsed JSON request body, otherwise string $context->log(json_encode($context->req->headers)); // String key-value pairs of all request headers, keys are lowercase $context->log($context->req->scheme); // Value of the x-forwarded-proto header, usually http or https $context->log($context->req->method); // Request method, such as GET, POST, PUT, DELETE, PATCH, etc. @@ -527,7 +575,7 @@ return function ($context) { import json def main(context): - context.log(context.req.body_raw) # Raw request body, contains request data + context.log(context.req.bodyText) # Raw request body, contains request data context.log(json.dumps(context.req.bodyJson)) # Object from parsed JSON request body, otherwise string context.log(json.dumps(context.req.headers)) # String key-value pairs of all request headers, keys are lowercase context.log(context.req.scheme) # Value of the x-forwarded-proto header, usually http or https @@ -545,7 +593,7 @@ def main(context): require 'json' def main(context) - context.log(context.req.bodyJson) # Raw request body, contains request data + context.log(context.req.bodyText) # Raw request body, contains request data context.log(JSON.generate(context.req.bodyJson)) # Object from parsed JSON request body, otherwise string context.log(JSON.generate(context.req.headers)) # String key-value pairs of all request headers, keys are lowercase context.log(context.req.scheme) # Value of the x-forwarded-proto header, usually http or https @@ -562,7 +610,7 @@ end ``` ```deno export default async ({ req, res, log }: any) => { - log(req.bodyJson); // Raw request body, contains request data + log(req.bodyText); // Raw request body, contains request data log(JSON.stringify(req.bodyJson)); // Object from parsed JSON request body, otherwise string log(JSON.stringify(req.headers)); // String key-value pairs of all request headers, keys are lowercase log(req.scheme); // Value of the x-forwarded-proto header, usually http or https @@ -577,12 +625,37 @@ export default async ({ req, res, log }: any) => { return res.text("All the request parameters are logged to the Appwrite Console."); } ``` +```go +package handler + +import ( + "encoding/json" + + "github.com/open-runtimes/types-for-go/v4/openruntimes" +) + +func Main(Context openruntimes.Context) openruntimes.Response { + Context.Log(Context.Req.BodyText) // Raw request body, contains request data + Context.Log(json.Marshal(Context.Req.BodyJson)) // Object from parsed JSON request body, otherwise string + Context.Log(json.Marshal(Context.Req.Headers)) // String key-value pairs of all request headers, keys are lowercase + Context.Log(Context.Req.Scheme) // Value of the x-forwarded-proto header, usually http or https + Context.Log(Context.Req.Method) // Request method, such as GET, POST, PUT, DELETE, PATCH, etc. + Context.Log(Context.Req.Url) // Full URL, for example: http://awesome.appwrite.io:8000/v1/hooks?limit=12&offset=50 + Context.Log(Context.Req.Host) // Hostname from the host header, such as awesome.appwrite.io + Context.Log(Context.Req.Port) // Port from the host header, for example 8000 + Context.Log(Context.Req.Path) // Path part of URL, for example /v1/hooks + Context.Log(Context.Req.QueryString) // Raw query params string. For example "limit=12&offset=50" + Context.Log(json.Marshal(Context.Req.Query)) // Parsed query params. For example, req.query.limit + + return Context.Res.Text("All the request parameters are logged to the Appwrite Console.") +} +``` ```dart import 'dart:async'; import 'dart:convert'; Future main(final context) async { - context.log(context.req.bodyJson); // Raw request body, contains request data + context.log(context.req.bodyText); // Raw request body, contains request data context.log(json.encode(context.req.bodyJson)); // Object from parsed JSON request body, otherwise string context.log(json.encode(context.req.headers)); // String key-value pairs of all request headers, keys are lowercase context.log(context.req.scheme); // Value of the x-forwarded-proto header, usually http or https @@ -625,7 +698,7 @@ using System.Text.Json; public class Handler { public async Task Main(RuntimeContext Context) { - Context.Log(JsonSerializer.Serialize(Context.Req.Body)); // Object from parsed JSON request body, otherwise string + Context.Log(JsonSerializer.Serialize(Context.Req.BodyJson)); // Object from parsed JSON request body, otherwise string Context.Log(JsonSerializer.Serialize(Context.Req.Headers)); // String key-value pairs of all request headers, keys are lowercase Context.Log(Context.Req.Scheme); // Value of the x-forwarded-proto header, usually http or https Context.Log(Context.Req.Method); // Request method, such as GET, POST, PUT, DELETE, PATCH, etc. @@ -739,7 +812,7 @@ There are several possible ways to send a response, explore them in the followin {% /table %} {% multicode %} -```js +```server-nodejs export default async ({ req, res, log }) => { switch (req.query.type) { @@ -834,6 +907,28 @@ export default async ({ req, res, log }) => { } } ``` +```go +package handler + +import ( + "github.com/open-runtimes/types-for-go/v4/openruntimes" +) + +func Main(Context openruntimes.Context) openruntimes.Response { + switch Context.Req.Query["type"] { + case "empty": + return Context.Res.Empty() + case "json": + return Context.Res.Json(map[string]string{"type": "This is a JSON response"}) + case "redirect": + return Context.Res.Redirect("https://appwrite.io") + case "html": + return Context.Res.Text("

This is an HTML response

") + default: + return Context.Res.Text("This is a text response") + } +} +``` ```dart import 'dart:async'; @@ -991,7 +1086,7 @@ These logs are only visible to developers with access to the Appwrite Console. Here's an example of using logs and errors. {% multicode %} -```js +```server-nodejs export default async ({ req, res, log, error }) => { log("This is a log, use for logging information to console"); log(`This function was called with ${req.method} method`); @@ -1156,7 +1251,7 @@ Learn to add variables to you function You can access the environment variables through the systems library of each language. {% multicode %} -```js +```server-nodejs export default async ({ req, res, log }) => { return res.text(process.env.MY_VAR); } @@ -1502,6 +1597,42 @@ export default function ({req, res, error}: any){ return res.text("Document created"); } ``` +```go +package handler + +import ( + "os" + "fmt" + + "github.com/appwrite/sdk-for-go/appwrite" + "github.com/appwrite/sdk-for-go/id" + "github.com/open-runtimes/types-for-go/v4/openruntimes" +) + +func Main(Context openruntimes.Context) openruntimes.Response { + // Set project and set API key + client := appwrite.NewClient( + appwrite.WithProject(os.Getenv("APPWRITE_FUNCTION_PROJECT_ID")), + appwrite.WithKey(Context.Req.Headers["x-appwrite-key"]), + ) + + databases := appwrite.NewDatabases(client) + + _, err := databases.CreateDocument( + "", + "", + id.Unique(), + map[string]interface{}{}, + ) + + if err != nil { + Context.Log(fmt.Sprintf("Failed to create document: %v", err)) + return Context.Res.Text("Failed to create document") + } + + return Context.Res.Text("Document created") +} +``` ```dart import 'dart:io'; import 'dart:async'; @@ -1828,6 +1959,47 @@ export default function ({req, res, error}: any){ return res.text("Document created"); } ``` +```go +package handler + +import ( + "fmt" + "log" + + "github.com/appwrite/sdk-for-go/appwrite" + "github.com/appwrite/sdk-for-go/id" + "github.com/open-runtimes/types-for-go/v4/openruntimes" +) + +func Main(Context openruntimes.Context) openruntimes.Response { + client := appwrite.NewClient( + appwrite.WithProject(""), + ) + + jwt, exists := Context.Req.Headers["x-appwrite-user-jwt"] + if !exists || len(jwt) == 0 { + appwrite.WithJWT(Context.Req.Headers["x-appwrite-user-jwt"]) + } else { + return Context.Res.Text("Please sign in, JWT not found") + } + + databases := appwrite.NewDatabases(client) + + _, err := databases.CreateDocument( + "", + "", + id.Unique(), + map[string]interface{}{}, + ) + + if err != nil { + Context.Log(fmt.Sprintf("Failed to create document: %v", err)) + return Context.Res.Text(str) + } + + return Context.Res.Text("Document created") +} +``` ```dart import 'dart:io'; import 'dart:async'; @@ -2015,13 +2187,13 @@ As your functions grow, you may find yourself needing to split your code into mu {% tabs %} {% tabsitem #nodejs title="Node.js" %} -```js +```server-nodejs // src/utils.js export function add(a, b) { return a + b; } ``` -```js +```server-nodejs // src/main.js import { add } from './utils.js'; @@ -2099,6 +2271,45 @@ export default function ({res}: {res: any}) { ``` {% /tabsitem %} +{% tabsitem #go title="Go" %} +```go +// src/utils/go.mod +module example.com/utils + +go 1.23.0 +``` +```go +// src/utils/utils.go +package utils + +func Add(a int, b int) int { + return a + b +} +``` +```go +// src/main/go.mod +module example.com/main + +go 1.23.0 + +replace example.com/utils => ../utils // Run go mod edit -replace example.com/go=../go + +require example.com/utils v0.0.0-00010101000000-000000000000 // Run go mod tidy +``` +```go +// src/main/main.go +package main + +import "example.com/utils" + +func main() { + // Get a greeting message and print it. + message := utils.Add(5, 4) + print(message) +} +``` +{% /tabsitem %} + {% tabsitem #dart title="Dart" %} ```dart // lib/utils.dart From 9f934f27ab93a08fad9820a1e7d60c1c5904b858 Mon Sep 17 00:00:00 2001 From: choir27 Date: Thu, 22 Aug 2024 16:16:51 -0400 Subject: [PATCH 3/6] add binary examples returning image. Add logging spread content and update log/error with spread example. Add go code log code sample. add go to dependencies. Fix placholder variables <> consistency. --- .../products/functions/develop/+page.markdoc | 149 ++++++++++++++---- 1 file changed, 117 insertions(+), 32 deletions(-) diff --git a/src/routes/docs/products/functions/develop/+page.markdoc b/src/routes/docs/products/functions/develop/+page.markdoc index cf6efbb21d..61db17378a 100644 --- a/src/routes/docs/products/functions/develop/+page.markdoc +++ b/src/routes/docs/products/functions/develop/+page.markdoc @@ -813,6 +813,8 @@ There are several possible ways to send a response, explore them in the followin {% multicode %} ```server-nodejs +const fs = require('fs'); + export default async ({ req, res, log }) => { switch (req.query.type) { @@ -820,6 +822,8 @@ export default async ({ req, res, log }) => { return res.empty(); case 'json': return res.json({"type": "This is a JSON response"}); + case 'binary': + return res.binary(InputFile.fromPath('/path/to/file', 'filename')); case 'redirect': return res.redirect("https://appwrite.io", 301); case 'html': @@ -834,6 +838,7 @@ export default async ({ req, res, log }) => { ``` ```php req->query['type']) { @@ -841,6 +846,8 @@ return function ($context) { return $context->res->empty(); case 'json': return $context->res->json(["type" => "This is a JSON response"]); + case 'binary': + return $context->res->binary(InputFile::withPath('file.png')); case 'redirect': return $context->res->redirect("https://appwrite.io", 301); case 'html': @@ -853,13 +860,17 @@ return function ($context) { }; ``` ```python +from appwrite.input_file import InputFile + def main(context): type = context.req.query['type'] if type == 'empty': return context.res.empty() - elif type =='json': + elif type == 'json': return context.res.json({"type": "This is a JSON response"}) + elif type == 'binary': + return context.res.binary(InputFile.from_path('file.png')) elif type == 'redirect': return context.res.redirect("https://appwrite.io", 301) elif type == 'html': @@ -876,6 +887,8 @@ def main(context) return context.res.empty() when 'json' return context.res.json({"type": "This is a JSON response"}) + when 'binary' + return context.res.binary(InputFile.from_path('dir/file.png')) when 'redirect' return context.res.redirect("https://appwrite.io", 301) when 'html' @@ -895,6 +908,8 @@ export default async ({ req, res, log }) => { return res.empty(); case 'json': return res.json({type: "This is a JSON response"}); + case 'binary': + return res.binary(InputFile.fromPath('/path/to/file.png', 'file.png')); case 'redirect': return res.redirect("https://appwrite.io", 301); case 'html': @@ -911,6 +926,9 @@ export default async ({ req, res, log }) => { package handler import ( + "io" + "os" + "github.com/open-runtimes/types-for-go/v4/openruntimes" ) @@ -920,6 +938,10 @@ func Main(Context openruntimes.Context) openruntimes.Response { return Context.Res.Empty() case "json": return Context.Res.Json(map[string]string{"type": "This is a JSON response"}) + case "binary": + file, _ := os.Open("./destiny.png") + imageData, _ := io.ReadAll(file) + return Context.Res.Binary(imageData) case "redirect": return Context.Res.Redirect("https://appwrite.io") case "html": @@ -938,6 +960,8 @@ Future main(final context) async { return context.res.empty(); case 'json': return context.res.json({'type': 'This is a JSON response'}); + case 'binary': + return context.res.binary(InputFile(path: './path-to-files/image.jpg', filename: 'image.jpg')); case 'redirect': return context.res.redirect('https://appwrite.io', 301); case 'html': @@ -957,6 +981,8 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput { return context.res.empty() case "json": return context.res.text(["type": "This is a JSON response"]) + case "binary": + return context.res.binary(InputFile.fromPath("file.png")) case "redirect": return context.res.redirect("https://appwrite.io", 301) case "html": @@ -978,6 +1004,8 @@ public class Handler { return Context.Res.Empty(); case "json": return Context.Res.Text(new Dictionary() { { "type", "This is a JSON response" } }); + case "binary": + return Context.Res.Binary(InputFile.FromPath("./path-to-files/image.jpg")); case "redirect": return Context.Res.Redirect("https://appwrite.io", 301); case "html": @@ -995,12 +1023,14 @@ package io.openruntimes.kotlin.src import io.openruntimes.kotlin.RuntimeContext import io.openruntimes.kotlin.RuntimeOutput +import io.appwrite.models.InputFile class Main { fun main(context: RuntimeContext): RuntimeOutput { when (context.req.query["type"]) { "empty" -> return context.res.empty() "json" -> return context.res.text(mapOf("type" to "This is a JSON response")) + "binary" -> return context.res.binary(InputFile.fromPath("file.png")) "redirect" -> return context.res.redirect("https://appwrite.io", 301) "html" -> return context.res.text("

This is an HTML response

", 200, mapOf("content-type" to "text/html")) else -> return context.res.text("This is a text response") @@ -1013,6 +1043,7 @@ package io.openruntimes.java.src; import io.openruntimes.java.RuntimeContext; import io.openruntimes.java.RuntimeOutput; +import io.appwrite.models.InputFile; import java.util.Map; import java.util.HashMap; @@ -1025,6 +1056,8 @@ public class Main { HashMap data = new HashMap<>(); data.put("type", "This is a JSON response"); return context.getRes().text(data); + case "binary" + return context.getRes().binary(InputFile.fromPath("file.png")); case "redirect": return context.getRes().redirect("https://appwrite.io", 301); case "html": @@ -1053,6 +1086,8 @@ namespace runtime { Json::Value data; data["type"] = "This is a JSON response"; return context.res.text(data); + } else if (type == "binary") { + return context.res.binary(InputFile.fromPath("file.png")) } else if (type == "redirect") { return context.res.redirect("https://appwrite.io", 301); } else if (type == "html") { @@ -1080,6 +1115,9 @@ To get the different response types, set one of the following query parameters i ## Logging {% #logging %} To protect user privacy, the request and response objects are not logged to the Appwrite Console by default. + +We support the spread operator across most of the languages, meaning you can write code that is more concise and flexible. + This means, to see logs or debug function executions you need to use the `log()` and `error()` methods. These logs are only visible to developers with access to the Appwrite Console. @@ -1088,9 +1126,11 @@ Here's an example of using logs and errors. {% multicode %} ```server-nodejs export default async ({ req, res, log, error }) => { - log("This is a log, use for logging information to console"); + const message = "This is a log, use for logging information to console"; + log("Message: ", message); log(`This function was called with ${req.method} method`); - error("This is an error, use for logging errors to console"); + const errorMessage = "This is an error, use for logging errors to console" + error("Error: ", errorMessage); return res.text("Check the Appwrite Console to see logs and errors!"); }; @@ -1099,46 +1139,75 @@ export default async ({ req, res, log, error }) => { log("This is a log, use for logging information to console"); + $message = "This is a log, use for logging information to console"; + $context->log("Message: ", message); $context->log("This function was called with " . $context->req->method . " method"); - $context->error("This is an error, use for logging errors to console"); + $errorMessage = "Check the Appwrite Console to see logs and errors!" + $context->error("Error: ", errorMessage); return $context->text("Check the Appwrite Console to see logs and errors!"); }; ``` ```python def main(context): - context.log("This is a log, use for logging information to console") + message = "This is a log, use for logging information to console" + context.log("Message: ", message) context.log(f"This function was called with {context.req.method} method") - context.error("This is an error, use for logging errors to console") + errorMessage = "This is an error, use for logging errors to console" + context.error("Error: ", errorMessage) return context.res.text("Check the Appwrite Console to see logs and errors!") ``` ```ruby def main(context) - context.log("This is a log, use for logging information to console") + message = "This is a log, use for logging information to console" + context.log("Message: ", message) context.log("This function was called with #{context.req.method} method") - context.error("This is an error, use for logging errors to console") + errorMessage = "This is an error, use for logging errors to console" + context.error("Error: ", errorMessage) return context.res.text("Check the Appwrite Console to see logs and errors!") end ``` ```deno export default async ({ res, log, error }: any) => { - log("This is a log, use for logging information to console"); + let message = "This is a log, use for logging information to console"; + log("Message: ", message); log(`This function was called with ${context.req.method} method`); - error("This is an error, use for logging errors to console"); + let errorMessage = "This is an error, use for logging errors to console"; + error("Error: ", errorMessage); return res.text("Check the Appwrite Console to see logs and errors!"); }; ``` +```go +package handler + +import ( + "fmt" + + "github.com/open-runtimes/types-for-go/v4/openruntimes" +) + +func Main(Context openruntimes.Context) openruntimes.Response { + message := "This is a log, use for logging information to console" + Context.Log("Message: ", message) + Context.Log(fmt.Sprintf("This function was called with %s method", Context.Req.Method)) + errorMessage := "This is an error, use for logging errors to console" + Context.Error("Error: ", errorMessage) + + return Context.Res.Text("Check the Appwrite Console to see logs and errors!") +} +``` ```dart import 'dart:async'; Future main(final context) async { - context.log("This is a log, use for logging information to console"); + var message = "This is a log, use for logging information to console"; + context.log("message: ", var); context.log("This function was called with ${context.req.method} method"); - context.error("This is an error, use for logging errors to console"); + var errorMessage = "This is an error, use for logging errors to console"; + context.error("Error: ", errorMessage); return context.res.text("Check the Appwrite Console to see logs and errors!"); } @@ -1147,9 +1216,11 @@ Future main(final context) async { import Foundation func main(context: RuntimeContext) async throws -> RuntimeOutput { - context.log("This is a log, use for logging information to console") + var message: String = "This is a log, use for logging information to console" + context.log("Message: ", message) context.log("This function was called with \(context.req.method) method") - context.error("This is an error, use for logging errors to console") + var message: String = "This is an error, use for logging errors to console" + context.error("Error: ", message) return context.res.text("Check the Appwrite Console to see logs and errors!") } @@ -1160,9 +1231,11 @@ namespace DotNetRuntime; public class Handler { public async Task Main(RuntimeContext Context) { - Context.Log("This is a log, use for logging information to console"); + string message = "This is a log, use for logging information to console"; + Context.Log("Message: ", message); Context.Log($"This function was called with {Context.Req.Method} method"); - Context.Error("This is an error, use for logging errors to console"); + string errorMessage = "This is an error, use for logging errors to console"; + Context.Error("Error: ", errorMessage); return Context.Res.Text("Check the Appwrite Console to see logs and errors!"); } @@ -1176,9 +1249,11 @@ import io.openruntimes.kotlin.RuntimeOutput class Main { fun main(context: RuntimeContext): RuntimeOutput { - context.log("This is a log, use for logging information to console") + var message: String = "This is a log, use for logging information to console" + context.log("Message: ", message) context.log("This function was called with ${context.req.method} method") - context.error("This is an error, use for logging errors to console") + var errorMessage: String = "This is an error, use for logging errors to console" + context.error("Error: ", errorMessage) return context.res.text("Check the Appwrite Console to see logs and errors!") } @@ -1192,9 +1267,11 @@ import io.openruntimes.java.RuntimeOutput; public class Main { public RuntimeOutput main(RuntimeContext context) throws Exception { - context.log("This is a log, use for logging information to console"); + String message = "This is a log, use for logging information to console"; + context.log("Message: ", message); context.log("This function was called with " + context.req.method + " method"); - context.error("This is an error, use for logging errors to console"); + string errorMessage = "This is an error, use for logging errors to console"; + context.error("Error: ", errorMessage); return context.getRes().text("Check the Appwrite Console to see logs and errors!"); } @@ -1210,9 +1287,11 @@ namespace runtime { class Handler { public: static RuntimeOutput main(RuntimeContext &context) { - context.log("This is a log, use for logging information to console"); + const std::string message = "This is a log, use for logging information to console"; + context.log("Message: ", message); context.log("This function was called with " + context.req.method + " method"); - context.error("This is an error, use for logging errors to console"); + const std::string errorMessage = "This is an error, use for logging errors to console"; + context.error("Error: ", errorMessage); return context.res.text("Check the Appwrite Console to see logs and errors!"); } @@ -1391,6 +1470,12 @@ By default, we include the following package managers in each runtime. * deno * `deno cache ` --- +* {% only_dark %}{% icon_image src="/images/platforms/dark/go.svg" alt="Go logo" size="m" /%}{% /only_dark %} +{% only_light %}{% icon_image src="/images/platforms/go.svg" alt="Go logo" size="m" /%}{% /only_light %} +* Go +* Go Modules +* N/A +--- * {% only_dark %}{% icon_image src="/images/platforms/dark/dart.svg" alt="Dart logo" size="m" /%}{% /only_dark %} {% only_light %}{% icon_image src="/images/platforms/dart.svg" alt="Dart logo" size="m" /%}{% /only_light %} * Dart @@ -1468,7 +1553,7 @@ export default async ({ req, res, log, error }) => { try { await databases.createDocument( '', - '[COLLECTION_ID]', + '', ID.unique(), {} ) @@ -1501,7 +1586,7 @@ return function ($context) { try { $databases->createDocument( databaseId: '', - collectionId: '[COLLECTION_ID]', + collectionId: '', documentId: ID::unique(), data: [] ); @@ -1559,7 +1644,7 @@ def main(context) begin databases.create_document( databaseId: '', - collectionId: '[COLLECTION_ID]', + collectionId: '', documentId: ID.unique(), data: {} ) @@ -1649,7 +1734,7 @@ Future main(final context) async { try { await databases.createDocument( databaseId: '', - collectionId: '[COLLECTION_ID]', + collectionId: '', documentId: ID.unique(), data: {} ); @@ -1820,7 +1905,7 @@ export default async ({ req, res, log }) => { try { await databases.createDocument( '', - '[COLLECTION_ID]', + '', ID.unique(), {} ) @@ -1857,7 +1942,7 @@ return function ($context) { try { $databases->createDocument( databaseId: '', - collectionId: '[COLLECTION_ID]', + collectionId: '', documentId: ID::unique(), data: [] ); @@ -1920,7 +2005,7 @@ def main(context) databases = Appwrite::Databases.new(client) begin - databases.create_document('', '[COLLECTION_ID]', Appwrite::ID.unique(), {}) + databases.create_document('', '', Appwrite::ID.unique(), {}) rescue Appwrite::Exception => e context.error("Failed to create document: " + e.message) return context.response.text("Failed to create document") @@ -1973,7 +2058,7 @@ import ( func Main(Context openruntimes.Context) openruntimes.Response { client := appwrite.NewClient( - appwrite.WithProject(""), + appwrite.WithProject("APPWRITE_FUNCTION_PROJECT_ID"), ) jwt, exists := Context.Req.Headers["x-appwrite-user-jwt"] @@ -2020,7 +2105,7 @@ Future main(final context) async { try { await databases.createDocument( databaseId: '', - collectionId: '[COLLECTION_ID]', + collectionId: '', documentId: ID.unique(), data: {} ); From 3ae8d528aeddd4ca70a1a3a05c9c07153a04f5fb Mon Sep 17 00:00:00 2001 From: choir27 Date: Thu, 22 Aug 2024 16:47:36 -0400 Subject: [PATCH 4/6] update copy for res.text when there is no JWT token available --- .../products/functions/develop/+page.markdoc | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/routes/docs/products/functions/develop/+page.markdoc b/src/routes/docs/products/functions/develop/+page.markdoc index 61db17378a..d3fa216732 100644 --- a/src/routes/docs/products/functions/develop/+page.markdoc +++ b/src/routes/docs/products/functions/develop/+page.markdoc @@ -1897,7 +1897,7 @@ export default async ({ req, res, log }) => { if (req.headers['x-appwrite-user-jwt']) { client.setJWT(req.headers['x-appwrite-user-jwt']) } else { - return res.text("Please sign in, JWT not found") + return res.text("Access denied: This function requires authentication. Please sign in to continue."); } const databases = new Databases(client); @@ -1934,7 +1934,7 @@ return function ($context) { if (isset($context->req->headers['x-appwrite-user-jwt'])) { $client->setJWT($context->req->headers['x-appwrite-user-jwt']); } else { - return $context->res->text("Please sign in, JWT not found"); + return $context->res->text("Access denied: This function requires authentication. Please sign in to continue."); } $databases = new Databases($client); @@ -1970,7 +1970,7 @@ def main(context): if "x-appwrite-user-jwt" in context.req.headers: client.set_jwt(context.req.headers["x-appwrite-user-jwt"]) else: - return context.res.text("Please sign in, JWT not found") + return context.res.text("Access denied: This function requires authentication. Please sign in to continue.") databases = Databases(client) @@ -1999,7 +1999,7 @@ def main(context) if context.request.headers['x-appwrite-user-jwt'] client.set_jwt(context.request.headers['x-appwrite-user-jwt']) else - return context.response.text("Please sign in, JWT not found") + return context.response.text("Access denied: This function requires authentication. Please sign in to continue.") end databases = Appwrite::Databases.new(client) @@ -2024,7 +2024,7 @@ export default function ({req, res, error}: any){ if (req.headers["x-appwrite-user-jwt"]) { client.setJWT(req.headers["x-appwrite-user-jwt"]); } else { - return res.text("Please sign in, JWT not found"); + return res.text("Access denied: This function requires authentication. Please sign in to continue."); } const databases = new Databases(client); @@ -2065,7 +2065,7 @@ func Main(Context openruntimes.Context) openruntimes.Response { if !exists || len(jwt) == 0 { appwrite.WithJWT(Context.Req.Headers["x-appwrite-user-jwt"]) } else { - return Context.Res.Text("Please sign in, JWT not found") + return Context.Res.Text("Access denied: This function requires authentication. Please sign in to continue.") } databases := appwrite.NewDatabases(client) @@ -2097,7 +2097,7 @@ Future main(final context) async { if (context.req.headers['x-appwrite-user-jwt'] != null) { client.setJWT(context.req.headers['x-appwrite-user-jwt']); } else { - return context.res.text("Please sign in, JWT not found"); + return context.res.text("Access denied: This function requires authentication. Please sign in to continue."); } final databases = Databases(client); @@ -2129,7 +2129,7 @@ func main(context: RuntimeContext) async throws -> RuntimeOutput { if let jwt = context.req.headers["x-appwrite-user-jwt"] { client.setJWT(jwt) } else { - return context.res.text("Please sign in, JWT not found") + return context.res.text("Access denied: This function requires authentication. Please sign in to continue.") } let databases = Databases(client: client) @@ -2166,7 +2166,7 @@ namespace DotNetRuntime if (Context.Req.Headers.ContainsKey("x-appwrite-user-jwt")) { client.SetJWT(Context.Req.Headers["x-appwrite-user-jwt"]); } else { - return Context.Res.Text("Please sign in, JWT not found"); + return Context.Res.Text("Access denied: This function requires authentication. Please sign in to continue.d"); } var databases = new Databases(client); @@ -2205,7 +2205,7 @@ class Main { if (context.req.headers["x-appwrite-user-jwt"] != null) { client.setJWT(context.req.headers["x-appwrite-user-jwt"]) } else { - return context.res.text("Please sign in, JWT not found") + return context.res.text("Access denied: This function requires authentication. Please sign in to continue.") } val databases = Databases(client) @@ -2242,7 +2242,7 @@ public class Main { if (context.req.headers.containsKey("x-appwrite-user-jwt")) { client.setJWT(context.req.headers.get("x-appwrite-user-jwt")); } else { - return context.res.text("Please sign in, JWT not found"); + return context.res.text("Access denied: This function requires authentication. Please sign in to continue."); } Databases databases = new Databases(client); From 68c1fd6bd472e65e1234ee639cdbbf394c32716c Mon Sep 17 00:00:00 2001 From: choir27 Date: Fri, 23 Aug 2024 09:32:29 -0400 Subject: [PATCH 5/6] fix typo --- src/routes/docs/products/functions/develop/+page.markdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/docs/products/functions/develop/+page.markdoc b/src/routes/docs/products/functions/develop/+page.markdoc index d3fa216732..45fcef4523 100644 --- a/src/routes/docs/products/functions/develop/+page.markdoc +++ b/src/routes/docs/products/functions/develop/+page.markdoc @@ -2166,7 +2166,7 @@ namespace DotNetRuntime if (Context.Req.Headers.ContainsKey("x-appwrite-user-jwt")) { client.SetJWT(Context.Req.Headers["x-appwrite-user-jwt"]); } else { - return Context.Res.Text("Access denied: This function requires authentication. Please sign in to continue.d"); + return Context.Res.Text("Access denied: This function requires authentication. Please sign in to continue"); } var databases = new Databases(client); From 31f38384073e39b65cb98a604889aa50afdfe2a9 Mon Sep 17 00:00:00 2001 From: choir27 Date: Fri, 23 Aug 2024 11:35:24 -0400 Subject: [PATCH 6/6] add on build/runtime availability for environment variables. Add go res.text snippet. --- .../products/functions/develop/+page.markdoc | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/src/routes/docs/products/functions/develop/+page.markdoc b/src/routes/docs/products/functions/develop/+page.markdoc index 45fcef4523..fa43df494f 100644 --- a/src/routes/docs/products/functions/develop/+page.markdoc +++ b/src/routes/docs/products/functions/develop/+page.markdoc @@ -1310,18 +1310,18 @@ You can access these logs through the following steps. # Accessing environment variables {% #environment-variables %} If you need to pass constants or secrets to Appwrite Functions, you can use environment variables. -| Variable | Description | -|-----------------------------------|------------------------------------------------| -| `APPWRITE_FUNCTION_API_ENDPOINT` | The API endpoint of the running function | -| `APPWRITE_VERSION` | The Appwrite version used to run the function | -| `APPWRITE_REGION` | The region where the function will run from | -| `APPWRITE_FUNCTION_API_KEY` | The function API key is used for server authentication | -| `APPWRITE_FUNCTION_ID` | The ID of the running function. | -| `APPWRITE_FUNCTION_NAME` | The Name of the running function. | -| `APPWRITE_FUNCTION_DEPLOYMENT` | The deployment ID of the running function. | -| `APPWRITE_FUNCTION_PROJECT_ID` | The project ID of the running function. | -| `APPWRITE_FUNCTION_RUNTIME_NAME` | The runtime of the running function. | -| `APPWRITE_FUNCTION_RUNTIME_VERSION` | The runtime version of the running function. | +| Variable | Description | Available at Build and/or Run Time | +|-----------------------------------|------------------------------------------------|-----------------------------------------------------| +| `APPWRITE_FUNCTION_API_ENDPOINT` | The API endpoint of the running function | Both | +| `APPWRITE_VERSION` | The Appwrite version used to run the function | Both | +| `APPWRITE_REGION` | The region where the function will run from | Both | +| `APPWRITE_FUNCTION_API_KEY` | The function API key is used for server authentication | Build time | +| `APPWRITE_FUNCTION_ID` | The ID of the running function. | Both | +| `APPWRITE_FUNCTION_NAME` | The Name of the running function. | Both | +| `APPWRITE_FUNCTION_DEPLOYMENT` | The deployment ID of the running function. | Both | +| `APPWRITE_FUNCTION_PROJECT_ID` | The project ID of the running function. | Both | +| `APPWRITE_FUNCTION_RUNTIME_NAME` | The runtime of the running function. | Both | +| `APPWRITE_FUNCTION_RUNTIME_VERSION` | The runtime version of the running function. | Both | {% arrow_link href="/docs/products/functions/functions#environment-variables" %} Learn to add variables to you function @@ -1356,6 +1356,19 @@ export default async ({ req, res, log }) => { return res.text(Deno.env.get('MY_VAR')); } ``` +```go +package handler + +import ( + "os" + + "github.com/open-runtimes/types-for-go/v4/openruntimes" +) + +func Main(Context openruntimes.Context) openruntimes.Response { + return res.text(os.Getenv(MY_VAR)) +} +``` ```dart import 'dart:io'; import 'dart:async'; @@ -1686,8 +1699,8 @@ export default function ({req, res, error}: any){ package handler import ( + "fmt" "os" - "fmt" "github.com/appwrite/sdk-for-go/appwrite" "github.com/appwrite/sdk-for-go/id" @@ -1695,7 +1708,7 @@ import ( ) func Main(Context openruntimes.Context) openruntimes.Response { - // Set project and set API key + // Set project and set API key client := appwrite.NewClient( appwrite.WithProject(os.Getenv("APPWRITE_FUNCTION_PROJECT_ID")), appwrite.WithKey(Context.Req.Headers["x-appwrite-key"]), @@ -1704,16 +1717,16 @@ func Main(Context openruntimes.Context) openruntimes.Response { databases := appwrite.NewDatabases(client) _, err := databases.CreateDocument( - "", + "", "", id.Unique(), map[string]interface{}{}, ) - if err != nil { - Context.Log(fmt.Sprintf("Failed to create document: %v", err)) - return Context.Res.Text("Failed to create document") - } + if err != nil { + Context.Log(fmt.Sprintf("Failed to create document: %v", err)) + return Context.Res.Text("Failed to create document") + } return Context.Res.Text("Document created") }