-
Notifications
You must be signed in to change notification settings - Fork 196
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
David Boyne
authored and
David Boyne
committed
Jul 29, 2024
1 parent
2b18e76
commit 9e27b73
Showing
6 changed files
with
366 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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>?): 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<str>?): 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 | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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: "<div id=\"hello\" class=\"mt-4\">Hello {counter.inc()}</div>", | ||
}; | ||
}); | ||
|
||
``` | ||
|
||
### 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 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
--- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
--- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. | ||
|