From 9e27b730b183d7fe8d736e828afa2e4dd18febaa Mon Sep 17 00:00:00 2001 From: David Boyne Date: Mon, 29 Jul 2024 11:56:49 +0100 Subject: [PATCH] adding doc examples into project --- docs/examples/basic-auth-api.md | 147 ++++++++++++++++++ docs/examples/deploy-a-static-website.md | 81 ++++++++++ .../introduction-to-preflight-and-inflight.md | 11 ++ docs/examples/introduction-to-wing.md | 12 ++ .../processing-messages-in-a-queue.md | 64 ++++++++ docs/examples/redis.md | 51 ++++++ 6 files changed, 366 insertions(+) create mode 100644 docs/examples/basic-auth-api.md create mode 100644 docs/examples/deploy-a-static-website.md create mode 100644 docs/examples/introduction-to-preflight-and-inflight.md create mode 100644 docs/examples/introduction-to-wing.md create mode 100644 docs/examples/processing-messages-in-a-queue.md create mode 100644 docs/examples/redis.md diff --git a/docs/examples/basic-auth-api.md b/docs/examples/basic-auth-api.md new file mode 100644 index 00000000000..7eb35ac0cad --- /dev/null +++ b/docs/examples/basic-auth-api.md @@ -0,0 +1,147 @@ +--- +title: "API using basic authentication" +subtitle: "Example application that exposes an API behind basic authentication" +type: + - "pattern" +platform: + - "awscdk" + - "tf-aws" + - "sim" +language: + - "wing" +githubURL: "https://github.com/winglang/examples.git && cd examples/examples/api-basic-auth" +coverImage: "/img/examples/basic-api-auth.png" +coverImageInPage: true +resources: + - label: "Understand preflight and inflight concepts" + href: "/docs/concepts/inflights" + - label: "Explore the Wing api resource" + href: "/docs/api/standard-library/cloud/api" +authors: + - name: "David Boyne" + role: "Developer Advocate, Wing" + twitter: "https://twitter.com/boyney123" + github: "https://github.com/boyney123" +cloudResources: + - api +--- + +This example application deploys an [API](/docs/api/standard-library/cloud/api) with a GET route called `/user`. The route is behind basic authentication and returns a 401 if un-authorized. + +In this example a custom **BasicAuth** class is created. This class exposes a public inflight method (called verify) that is used within the API to verify the request. + +> **Did you know resources have a preflight and inflight API?** [Preflight](/docs/concepts/inflights) code runs once, at compile time whereas [inflight](/docs/concepts/inflights) code is run at runtime. In this example we create the BasicAuth and API resources on preflight (default for Wing files) and then use the BasicAuth method (verify) in the API itself (on inflight). To learn more you can read [preflight and inflight](/docs/concepts/inflights#preflight-code) core concepts. + + +```js example playground +bring cloud; +bring util; +bring http; + +struct Credentials { + username: str; + password: str; +} + +// Custom class for the authentication logic +class BasicAuth { + user: str; + password: str; + + new(user: str?, password: str?) { + // Default credentials + this.user = user ?? "admin"; + this.password = password ?? "admin"; + + // Custom icon and color for the node + nodeof(this).icon = "lock-closed"; + nodeof(this).color = "red"; + } + + // public function to verify the requests + pub inflight verify(req: cloud.ApiRequest): bool { + try { + let authHeader = this.authHeader(req.headers); + let credentials = this.authCredentials(authHeader); + let username = credentials.username; + let password = credentials.password; + return username == this.user && password == this.password; + } catch e { + log("exception caught {e}"); + return false; + } + } + + // Decodes the given header and returns username and password + inflight authCredentials(header: str): Credentials { + let auth = util.base64Decode(header.split(" ").at(1)); + let splittedAuth = auth.split(":"); + let username = splittedAuth.at(0); + let password = splittedAuth.at(1); + + return Credentials { + username: username, + password: password + }; + } + // Returns the authorization header + inflight authHeader(headers: Map?): str { + if (this.authHeaderPresent(headers)) { + let authHeaderOptional = headers?.tryGet("authorization"); + let var authHeader = headers?.tryGet("Authorization"); + + if (authHeader == nil) { + authHeader = authHeaderOptional; + } + + return authHeader!; + } else { + log("headers: {Json.stringify(headers)}"); + log("no auth header"); + throw("no auth header"); + } + } + + inflight authHeaderPresent(headers: Map?): bool { + if (headers?.has("authorization") == false) && (headers?.has("Authorization") == false) { + return false; + } + return true; + } + +} + +// Create a new instance of the BasicAuth class +let auth = new BasicAuth() as "Basic auth verification"; + +// Create a new API +let api = new cloud.Api() as "Users API"; + +// Create the route /user and protect with basic auth +api.get("/user", inflight (req) => { + let authenticated = auth.verify(req); + + if (!authenticated) { + return { + status: 401, + headers: { + "Content-Type" => "text/plain" + }, + body: "Unauthorized" + }; + } + + return { + status: 200, + headers: { + "Content-Type" => "text/plain" + }, + body: Json.stringify({ "firstname": "David", "lastname": "Boyne" }) + }; +}); +``` + +### Resources used in this example + +- [Api](/docs/api/standard-library/cloud/api) - Resource for cloud api + diff --git a/docs/examples/deploy-a-static-website.md b/docs/examples/deploy-a-static-website.md new file mode 100644 index 00000000000..3c2d8a4ccc3 --- /dev/null +++ b/docs/examples/deploy-a-static-website.md @@ -0,0 +1,81 @@ +--- +title: "Deploy a static website with Wing" +subtitle: "Example application that deploys a static website into the cloud" +type: + - "pattern" +platform: + - "awscdk" + - "tf-aws" + - "sim" +language: + - "wing" +githubURL: "https://github.com/winglang/examples.git && cd examples/examples/static-website" +coverImage: "/img/examples/static-website.png" +coverImageInPage: true +coverImageOptions: + awscdk: "/img/examples/static-website-aws.png" + "tf-aws": "/img/examples/static-website-aws.png" +resources: + - label: "Understanding inflight and preflight" + href: "/docs/concepts/inflights" + - label: "Explore the Wing website cloud resource" + href: "/docs/api/standard-library/cloud/website" + - label: "Explore the Wing api cloud resource" + href: "/docs/api/standard-library/cloud/api" +authors: + - name: "David Boyne" + role: "Developer Advocate, Wing" + twitter: "https://twitter.com/boyney123" + github: "https://github.com/boyney123" +cloudResources: + - website + - api + - counter +--- + +This example application deploys a static website to the cloud using a [website](/docs/api/standard-library/cloud/website) resource. Additionally, it includes an [API resource](/docs/api/standard-library/cloud/api) featuring a `/hello-static` **POST** endpoint. + +The deployed website shows a button which makes a POST request to the API to increment a counter value. + +> The `/hello-static` POST endpoint in this example returns an [inflight function](/docs/concepts/inflights#inflight-code). This is runtime code. When a request is received at this endpoint, the inflight code is executed. + +```js example playground +bring cloud; +bring util; +bring http; +bring expect; + +let website = new cloud.Website( + path: "./static", +); + +let api = new cloud.Api({ + cors: true, + corsOptions: { + allowHeaders: ["*"], + allowMethods: [http.HttpMethod.POST], + }, +}); +website.addJson("config.json", { api: api.url }); + +let counter = new cloud.Counter() as "website-counter"; + +api.post("/hello-static", inflight (request) => { + return { + status: 200, + headers: { + "Content-Type" => "text/html", + "Access-Control-Allow-Origin" => "*", + }, + body: "
Hello {counter.inc()}
", + }; +}); + +``` + +### Resources used in this example + +- [Website](/docs/api/standard-library/cloud/website) - Deploy static websites into the cloud +- [API](/docs/api/standard-library/cloud/api) - Create APIs and deploy them into the cloud +- [Counter](/docs/api/standard-library/cloud/counter) - Stateful container for one or more numbers in the cloud + diff --git a/docs/examples/introduction-to-preflight-and-inflight.md b/docs/examples/introduction-to-preflight-and-inflight.md new file mode 100644 index 00000000000..0cd6abe9d10 --- /dev/null +++ b/docs/examples/introduction-to-preflight-and-inflight.md @@ -0,0 +1,11 @@ +--- +title: "Introduction to preflight and inflight" +subtitle: "A hands on tutorial to teach preflight and inflight execution phases" +type: + - "interactive tutorial" +coverImage: "/img/examples/introduction-to-preflight-and-inflight.png" +url: https://www.winglang.io/learn/preflight-inflight +cloudResources: + - bucket + - function +--- \ No newline at end of file diff --git a/docs/examples/introduction-to-wing.md b/docs/examples/introduction-to-wing.md new file mode 100644 index 00000000000..8478e5b0a6d --- /dev/null +++ b/docs/examples/introduction-to-wing.md @@ -0,0 +1,12 @@ +--- +title: "Introduction to Wing" +subtitle: "A step-by-step introductory guide to the Winglang cloud programming language" +type: + - "interactive tutorial" +coverImage: "/img/examples/introduction-to-wing.png" +url: https://www.winglang.io/learn +cloudResources: + - queue + - bucket + - function +--- \ No newline at end of file diff --git a/docs/examples/processing-messages-in-a-queue.md b/docs/examples/processing-messages-in-a-queue.md new file mode 100644 index 00000000000..ab1270c8cc2 --- /dev/null +++ b/docs/examples/processing-messages-in-a-queue.md @@ -0,0 +1,64 @@ +--- +title: "Processing messages in a queue" +subtitle: "Example application that processes messages form a queue and puts information into a bucket" +type: + - "pattern" +platform: + - "awscdk" + - "tf-aws" + - "sim" +language: + - "wing" +githubURL: "https://github.com/winglang/examples.git && cd examples/examples/hello-wing" +coverImage: "/img/examples/basic-bucket-queue.png" +coverImageInPage: true +resources: + - label: "Understanding inflight and preflight" + href: "/docs/concepts/inflights" + - label: "Explore the Wing queues" + href: "/docs/api/standard-library/cloud/queue" + - label: "Explore the Wing buckets" + href: "/docs/api/standard-library/cloud/bucket" +authors: + - name: "David Boyne" + role: "Developer Advocate, Wing" + twitter: "https://twitter.com/boyney123" + github: "https://github.com/boyney123" +cloudResources: + - queue + - bucket +--- + +This pattern creates a [bucket](/docs/api/standard-library/cloud/bucket) and a [queue](/docs/api/standard-library/cloud/queue). When messages are pushed the queue an [inflight function](/docs/concepts/inflights#inflight-code) processes the message and puts the contents of the message into a bucket. + +> The [inflight function](/docs/concepts/inflights#inflight-code) is executed at runtime. During this execution, inflight code can interact with resources through their inflight APIs (e.g. [bucket inflight APIS](/docs/api/standard-library/cloud/bucket#inflight-methods)). In this example, information is added to the bucket by using the inflight [put API](/docs/api/standard-library/cloud/bucket#@winglang/sdk.cloud.IBucketClient.put) provided by the bucket. + +```js example playground +bring cloud; +bring util; +bring expect; + +let bucket = new cloud.Bucket(); +let queue = new cloud.Queue(); + +queue.setConsumer(inflight (message) => { + bucket.put("wing.txt", "Hello, {message}"); +}, timeout: 30s); + +test "Hello, world!" { + queue.push("world!"); + + let found = util.waitUntil(() => { + log("Checking if wing.txt exists"); + return bucket.exists("wing.txt"); + }); + + expect.equal(bucket.get("wing.txt"), "Hello, world!"); +} +``` + +### Resources used in this example + +- [Queue](/docs/api/standard-library/cloud/queue) - Resource for holding lists of messages. +- [Bucket](/docs/api/standard-library/cloud/bucket) - Resource for storing data in the cloud. + diff --git a/docs/examples/redis.md b/docs/examples/redis.md new file mode 100644 index 00000000000..df2adae1eea --- /dev/null +++ b/docs/examples/redis.md @@ -0,0 +1,51 @@ +--- +title: "Using Redis with Wing" +subtitle: "Example application that uses Redis to set cache values from a queue" +type: + - "pattern" +platform: + - "awscdk" + - "sim" +language: + - "wing" +githubURL: "https://github.com/winglang/examples.git && cd examples/examples/redis" +coverImage: "/img/examples/redis.png" +coverImageInPage: true +resources: + - label: "Redis winglib" + href: "https://github.com/winglang/winglibs/tree/main/redis" + - label: "Explore Wing functions" + href: "/docs/api/standard-library/cloud/function" +authors: + - name: "David Boyne" + role: "Developer Advocate, Wing" + twitter: "https://twitter.com/boyney123" + github: "https://github.com/boyney123" +cloudResources: + - function +--- + +This basic pattern uses the [redis winglib](https://github.com/winglang/winglibs/tree/main/redis) with a [cloud function](/docs/api/standard-library/cloud/function). + +When the cloud function is invoked a value is set in the redis database using the redis inflight API. + + +```js example +bring redis; +bring cloud; + +// Create a reddit resource +let redisInstance = new redis.Redis(); + +new cloud.Function(inflight () => { + // Set value in the redis cache + redisInstance.set("mykey", "myvalue"); +}); +``` + + +### Resources used in this example + +- [Function](/docs/api/standard-library/cloud/function) - Resource for holding lists of messages. +- [Redis winglib](https://github.com/winglang/winglibs/tree/main/redis) - Resource for storing data in the cloud. +