From 2c71147d6768c03e863fce4440f1e37803ee408b Mon Sep 17 00:00:00 2001 From: cohix Date: Thu, 31 Mar 2022 09:22:55 -0400 Subject: [PATCH] bump versions and add changelog for v0.4.5, remove docs --- .subo.yml | 2 - atmo/release/version.go | 2 +- changelogs/v0.4.5.md | 1 + docs/README.md | 27 ---- docs/SUMMARY.md | 45 ------ docs/concepts/runnables.md | 14 -- docs/concepts/state.md | 59 -------- docs/concepts/static-directory.md | 29 ---- docs/concepts/the-directive.md | 40 ------ docs/getstarted/README.md | 16 --- docs/getstarted/building-and-running.md | 44 ------ docs/getstarted/creating-a-project.md | 32 ----- docs/more-info/background.md | 12 -- docs/runnable-api/authentication.md | 16 --- docs/runnable-api/cache.md | 56 -------- docs/runnable-api/example-runnable.md | 35 ----- docs/runnable-api/file.md | 30 ---- docs/runnable-api/graphql-requests.md | 30 ---- docs/runnable-api/http.md | 98 ------------- docs/runnable-api/introduction.md | 58 -------- docs/runnable-api/logging.md | 74 ---------- docs/runnable-api/request.md | 184 ------------------------ docs/runnable-api/response.md | 52 ------- docs/usage/building-a-bundle.md | 29 ---- docs/usage/connections.md | 69 --------- docs/usage/creating-handlers.md | 58 -------- docs/usage/creating-runnables.md | 28 ---- docs/usage/deploying-atmo.md | 53 ------- docs/usage/error-handling.md | 48 ------- docs/usage/headless.md | 50 ------- docs/usage/managing-state.md | 60 -------- docs/usage/schedules.md | 29 ---- docs/usage/streams.md | 17 --- docs/usage/using-sql-databases.md | 96 ------------- example-project/Directive.yaml | 2 +- 35 files changed, 3 insertions(+), 1492 deletions(-) create mode 100644 changelogs/v0.4.5.md delete mode 100644 docs/README.md delete mode 100644 docs/SUMMARY.md delete mode 100644 docs/concepts/runnables.md delete mode 100644 docs/concepts/state.md delete mode 100644 docs/concepts/static-directory.md delete mode 100644 docs/concepts/the-directive.md delete mode 100644 docs/getstarted/README.md delete mode 100644 docs/getstarted/building-and-running.md delete mode 100644 docs/getstarted/creating-a-project.md delete mode 100644 docs/more-info/background.md delete mode 100644 docs/runnable-api/authentication.md delete mode 100644 docs/runnable-api/cache.md delete mode 100644 docs/runnable-api/example-runnable.md delete mode 100644 docs/runnable-api/file.md delete mode 100644 docs/runnable-api/graphql-requests.md delete mode 100644 docs/runnable-api/http.md delete mode 100644 docs/runnable-api/introduction.md delete mode 100644 docs/runnable-api/logging.md delete mode 100644 docs/runnable-api/request.md delete mode 100644 docs/runnable-api/response.md delete mode 100644 docs/usage/building-a-bundle.md delete mode 100644 docs/usage/connections.md delete mode 100644 docs/usage/creating-handlers.md delete mode 100644 docs/usage/creating-runnables.md delete mode 100644 docs/usage/deploying-atmo.md delete mode 100644 docs/usage/error-handling.md delete mode 100644 docs/usage/headless.md delete mode 100644 docs/usage/managing-state.md delete mode 100644 docs/usage/schedules.md delete mode 100644 docs/usage/streams.md delete mode 100644 docs/usage/using-sql-databases.md diff --git a/.subo.yml b/.subo.yml index 19845fce..f717a4c7 100644 --- a/.subo.yml +++ b/.subo.yml @@ -1,8 +1,6 @@ dotVersionFiles: - example-project/Directive.yaml - atmo/release/version.go - - docs/concepts/the-directive.md - - docs/usage/creating-handlers.md preMakeTargets: - build diff --git a/atmo/release/version.go b/atmo/release/version.go index 492a7f66..011abd26 100644 --- a/atmo/release/version.go +++ b/atmo/release/version.go @@ -1,4 +1,4 @@ package release // AtmoDotVersion represents the dot version for atmo -var AtmoDotVersion = "0.4.4" +var AtmoDotVersion = "0.4.5" diff --git a/changelogs/v0.4.5.md b/changelogs/v0.4.5.md new file mode 100644 index 00000000..d984ba9f --- /dev/null +++ b/changelogs/v0.4.5.md @@ -0,0 +1 @@ +Atmo Beta-4.5 brings some minor fixes and the ability to define static peers with the `ATMO_PEERS` env var. \ No newline at end of file diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 97e52442..00000000 --- a/docs/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Welcome - -### Welcome to the Atmo guide - -Building web services should be simple. Atmo makes it easy to create a powerful server application without needing to worry about scalability, infrastructure, or complex networking. - -Atmo enables you to write small self-contained functions called **Runnables** using a variety of languages, and define your business logic by **declaratively composing** them. Atmo then automatically scales out a **flat network** of instances to handle traffic. Atmo is currently focused on building web services, particularly APIs, and can be used with a variety of architectures including HTTP- and stream-based environments. - -The Atmo **Directive** is a YAML file wherein you declare your application's behaviour. Because the Directive can describe everything you need to make your application work \(including routes, logic, and more\), there is no need to write boilerplate ever again. - -Atmo is a server-side runtime and application framework. It uses a **bundle** containing your Runnables and Directive to automatically run your application. - -With Atmo, you only need to do three things: - -1. Write self-contained, composable functions -2. Declare how you want Atmo to handle requests by creating a "Directive" -3. Build and deploy your Runnable bundle. - - -## Status - -Atmo is currently in **beta**, and is the flagship project in the Suborbital Development Platform. Visit [the Suborbital website](https://suborbital.dev) to sign up for email updates related to new versions of Atmo. - -Atmo is built atop [Vektor](https://github.com/suborbital/vektor), [Grav](https://github.com/suborbital/grav), and [Reactr](https://github.com/suborbital/reactr). - -Copyright Suborbital contributors 2021. - diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md deleted file mode 100644 index 609a6a3e..00000000 --- a/docs/SUMMARY.md +++ /dev/null @@ -1,45 +0,0 @@ -# Table of contents - -* [Welcome](README.md) -* [Get Started](getstarted/README.md) - * [Creating a Project](getstarted/creating-a-project.md) - * [Building and Running](getstarted/building-and-running.md) - -## Concepts - -* [Runnables](concepts/runnables.md) -* [The Directive](concepts/the-directive.md) -* [State](concepts/state.md) -* [Static Directory](concepts/static-directory.md) - -## Usage - -* [Creating Runnables](usage/creating-runnables.md) -* [Creating handlers](usage/creating-handlers.md) -* [Managing state](usage/managing-state.md) -* [Error handling](usage/error-handling.md) -* [Scheduled jobs](usage/schedules.md) -* [Streams](usage/streams.md) -* [Connections](usage/connections.md) -* [Using SQL databases](usage/using-sql-databases.md) -* [Building a Bundle](usage/building-a-bundle.md) -* [Deploying Atmo](usage/deploying-atmo.md) -* [Headless Mode](usage/headless.md) - -## Runnable API - -* [Introduction](runnable-api/introduction.md) -* [Example Runnable](runnable-api/example-runnable.md) -* [Handling requests](runnable-api/request.md) -* [Modifying responses](runnable-api/response.md) -* [Structured logging](runnable-api/logging.md) -* [HTTP requests](runnable-api/http.md) -* [GraphQL requests](runnable-api/graphql-requests.md) -* [Authentication](runnable-api/authentication.md) -* [Accessing cache](runnable-api/cache.md) -* [Static files](runnable-api/file.md) - -## More info - -* [Background](more-info/background.md) - diff --git a/docs/concepts/runnables.md b/docs/concepts/runnables.md deleted file mode 100644 index 1f4f7718..00000000 --- a/docs/concepts/runnables.md +++ /dev/null @@ -1,14 +0,0 @@ -# Runnables - -When building an application with Atmo, you segment your application's logic into individual functions known as **Runnables**. A Runnable can be written in any of the supported languages \(such as TypeScript, Rust or Swift\), and is compiled to WebAssembly when you build it. - -Runnables are completely independent from one another, and have no knowledge of each other's execution. Runnables take an input from Atmo, use the **Runnable API** to run your application logic, and then return an output. - -{% hint style="info" %} -You can see some example Runnables in the [example project](https://github.com/suborbital/atmo/tree/main/example-project). -{% endhint %} - -Atmo loads a **Bundle** of Runnables at startup and uses your application **Directive** \(discussed next\) to set up and execute your application. Runnables are executed using a job scheduler, meaning that Atmo will "figure out" how to run your application as you've designed, rather than needing to imperatively call functions and structure a large code project like you might be used to with other frameworks. - -The **Runnable API** is a library that you include with your application code to gain access to resources such as logging, caching, and access to the network. Atmo dynamically binds resources to your Runnables at runtime, meaning you can swap out various components such as the cache being used without re-writing any code. The CLI tool **subo** takes care of setting up projects, creating Runnables, and building Bundles. - diff --git a/docs/concepts/state.md b/docs/concepts/state.md deleted file mode 100644 index 3d238892..00000000 --- a/docs/concepts/state.md +++ /dev/null @@ -1,59 +0,0 @@ -# State - -Since Runnables are completely unaware of one another when being executed, there needs to be a way to pass data between them. Atmo uses a shared object called the **request state** to accomplish this. Request state is a key/value map that is updated automatically after each step in a handler. - -Let's take a look at a handler from the Directive: - -```yaml -handlers: - - type: request - resource: /hello - method: POST - steps: - - fn: verify-request - - group: - - fn: modify-url - - fn: cache-get - - fn: fetch -``` - -Here we can see a request with three steps. The first and third are single functions being called, and the second is a function group. - -After each step in the handler, the request state is updated from the output of the functions in that step. - -For example, after the **first step**, the state will look like this: - -```text -{ - "verify-request": "ok" -} -``` - -And then after the **second step**: - -```text -{ - "verify-request": "ok" - "modify-url": "https://github.com/suborbital" - "cache-get": {"Auth-Header": "nuw45tpjno998w3un10nfwe8h"} -} -``` - -When each step executes, the current request state is made available to the Runnable using **Runnable API** functions. - -{% hint style="info" %} -Request state is updated after each **step**, so it is important to note that multiple functions in a **group** will all receive the same state from the beginning of the step, and all of their outputs will be added to state after they've all completed executing. -{% endhint %} - -You can access request state like the following Runnable example written in Rust. - -```rust -use suborbital::req; - -[...] - -let url = req::state("modify-url"); -``` - -There are several clauses that allow you to control how the request state is set up \(for example, choosing the key that a function's output is stored in\), which will be covered later. - diff --git a/docs/concepts/static-directory.md b/docs/concepts/static-directory.md deleted file mode 100644 index 47e8c06b..00000000 --- a/docs/concepts/static-directory.md +++ /dev/null @@ -1,29 +0,0 @@ -# Static Directory - -An Atmo project can optionally contain a `static` directory. When present, the `subo` CLI will package the static directory into your application Bundle. Example: - -```text -important-api --- get-users --- create-user --- static - -- index.html - -- main.css - -- bundle.js --- Directive.yaml -``` - -{% hint style="warning" %} -Do not use the static directory for sensitive data such as secrets. Atmo will be gaining a secrets management system in 2021. -{% endhint %} - -Since the directory is included in your Bundle, your Runnables can access the files! Atmo will mount the directory as a read-only filesystem that can be accessed using the `file` namespace of the [Runnable API](../runnable-api/introduction.md). For example: - -```rust -use suborbital::file; - -let indexHtml = file::get_static("index.html"); -``` - -This allows Atmo to serve static sites, access template files, and more! - diff --git a/docs/concepts/the-directive.md b/docs/concepts/the-directive.md deleted file mode 100644 index 8891289c..00000000 --- a/docs/concepts/the-directive.md +++ /dev/null @@ -1,40 +0,0 @@ -# The Directive - -The Directive is a declarative file that allows you to describe your application's business logic. By describing your application declaratively, you can avoid all of the boilerplate code that normally comes with building a web service such as binding to ports, setting up TLS, constructing a router, etc. - -Here's an example Directive: - -```yaml -identifier: com.suborbital.guide -appVersion: v0.0.1 -atmoVersion: v0.4.4 - -handlers: - - type: request - resource: /hello - method: POST - steps: - - group: - - fn: modify-url - - fn: helloworld-rs - onErr: - any: continue - - - fn: fetch - - - type: request - resource: /set/:key - method: POST - steps: - - fn: cache-set - - - type: request - resource: /get/:key - method: GET - steps: - - fn: cache-get -``` - -This directive encapsulates all of the logic for your application. It describes three endpoints and the logic needed to handle them. Each handler describes a set of `steps` that composes a series of Runnables to handle the request. - -Atmo uses the Directive to build your application and run it automatically, without any need to write boilerplate yourself. diff --git a/docs/getstarted/README.md b/docs/getstarted/README.md deleted file mode 100644 index 4d2af466..00000000 --- a/docs/getstarted/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Get Started - -Atmo is a self-hosted platform that uses a _Runnable bundle_ to run your described application. The bundle includes two things: a [Directive](../concepts/the-directive.md), and a set of [Runnables](../concepts/runnables.md) \(WebAssembly modules compiled from various languages such as TypeScript, Rust and Swift\). A bundle contains everything needed to run your application. - -## Requirements - -{% hint style="info" %} -**You'll need to install the subo CLI tool and Docker to use Atmo**. - -To install the tool, [visit the subo repository](https://github.com/suborbital/subo). - -[Docker](https://www.docker.com/get-started) is used to build Runnables and run the Atmo development server. -{% endhint %} - -Read on to learn about the different aspects of an Atmo project, or skip right to [building your application bundle.](../usage/building-a-bundle.md) - diff --git a/docs/getstarted/building-and-running.md b/docs/getstarted/building-and-running.md deleted file mode 100644 index aeeb0ce5..00000000 --- a/docs/getstarted/building-and-running.md +++ /dev/null @@ -1,44 +0,0 @@ -# Building and Running - -The `subo` command line tool is used again here to build and run your Atmo project. - -## Building - -Inside the `important-api` directory run: - -```text -subo build . -``` - -This automatically compiles each of your Runnables in a Docker container and bundles them together in `runnables.wasm.zip` to be used in Atmo. - -```text -⏩ START: building runnables in . -ℹ️ 🐳 using Docker toolchain -⏩ START: building runnable: helloworld (rust) - Updating crates.io index -[...] - -✅ DONE: bundle was created -> runnables.wasm.zip @ v0.1.0 -``` - -{% hint style="info" %} -If you prefer not to use Docker, you can also [build your Runnables natively](https://github.com/suborbital/subo/blob/main/docs/get-started.md#building-without-docker). -{% endhint %} - -## Running a development server - -Now that we have our application bundle built, we can start a development server. In the `important-api` directory, run: - -```text -subo dev -``` - -This creates a Docker container running Atmo, copies your `runnables.wasm.zip` into the container, and starts an Atmo server listening on `http://localhost:8080`. - -You can test the `/hello` route in a second terminal by sending a POST request with a body to it: - -```text -curl localhost:8080/hello -d 'from the Kármán line!' -``` - diff --git a/docs/getstarted/creating-a-project.md b/docs/getstarted/creating-a-project.md deleted file mode 100644 index 2f3d915b..00000000 --- a/docs/getstarted/creating-a-project.md +++ /dev/null @@ -1,32 +0,0 @@ -# Creating a Project - -With subo installed, you can now create a project: - -```text -subo create project important-api -``` - -The project contains two important things: a `Directive.yaml` file, and an example Runnable called `helloworld` written in Rust. The [Directive](../concepts/the-directive.md) file defines route handlers and connects [Runnables](../concepts/runnables.md) to them. - -### Overview - -In the Directive file, you'll see a handler set up for you that serves the `POST /hello` route using the `helloworld` Runnable: - -```yaml -# the Directive is a complete description of your application, including all of its business logic. -# appVersion should be updated for each new deployment of your app. -# atmoVersion declares which version of Atmo is used for the `subo dev` command. - -identifier: com.suborbital.important-api -appVersion: v0.1.0 -atmoVersion: v0.2.3 - - -handlers: - - type: request - resource: /hello - method: POST - steps: - - fn: helloworld -``` - diff --git a/docs/more-info/background.md b/docs/more-info/background.md deleted file mode 100644 index c00dda0f..00000000 --- a/docs/more-info/background.md +++ /dev/null @@ -1,12 +0,0 @@ -# Background - -Atmo was born out of a desire to simplify server-side development by making it easy to bootstrap new projects, automatically scale to handle large amounts of traffic, and ensure their security with new technology and best practices. - -Atmo embodies the [SUFA design pattern](https://blog.suborbital.dev/how-to-familiarize-yourself-with-a-new-codebase) by making it easy to develop, deploy, and scale your application. To develop applications using Atmo, a declarative file called the Directive is used to describe how to handle requests and events using composable functions. This allows the developer to describe the entirety of their application's behaviour, while only needing to write code for the functions being called. Atmo then uses the Directive to run the desired application, automatically running a web server, job scheduler, and messaging mesh together to form a powerful platform upon which your application can thrive. - -The core of Atmo is a job scheduler running WebAssembly modules, which allows running functions written in a variety of languages with near-native performance and massive improvements to security and ease of orchestration. - -Atmo scales out using capability groups, which allows groups of Atmo instances to access sensitive resources, scale independently, and ensure your application is able to grow efficiently to handle increases in traffic with ease. Atmo's built in meshing capabilities means that building a flat network of instances is automated, secure, and efficient. - -Atmo strives to make everything about developing and deploying your application simple so that you can focus on the hard problems of building your product. Atmo's mission statement is "help developers build applications that are powerful but never complicated". - diff --git a/docs/runnable-api/authentication.md b/docs/runnable-api/authentication.md deleted file mode 100644 index 72a7b412..00000000 --- a/docs/runnable-api/authentication.md +++ /dev/null @@ -1,16 +0,0 @@ -# Authentication - -While not a direct part of the Runnable API, Atmo does include a method of providing authentication for HTTP and GraphQL made by the Runnable API. Atmo helps with authenticating these requests by injecting the `Authorization` header to your Runnable's requests based on the configuration in your Directive. For example: - -```yaml -authentication: - domains: - api.github.com: - headerType: bearer - value: env(GITHUB_TOKEN) -``` - -This uses the `env` keyword to augment any request \(either HTTP or GraphQL\) to the `api.github.com` domain with an `Authorization` header containing the value `bearer {GITHUB_TOKEN}`, with the environment variable evaluated at runtime. The `value` can be a static string if needed, but the `env` keyword is more common as it allows your application to be configured in different environments. - -This strategy of authentication injection allows Atmo to handle sensitive values without ever giving the code inside the Runnable sandbox access to them. This is an important aspect of Atmo's security model, and helps maintain healthy security practices. - diff --git a/docs/runnable-api/cache.md b/docs/runnable-api/cache.md deleted file mode 100644 index 7bc4b10b..00000000 --- a/docs/runnable-api/cache.md +++ /dev/null @@ -1,56 +0,0 @@ -# Accessing cache - -Runnables can access an attached cache \(such as Redis\) using the `cache` namespace of the Runnable API. Atmo will configure the cache, and will bind it to the Runnable at runtime. Atmo provides a default in-memory cache if no external cache is connected. - -Documentation for connecting an external cache to Atmo is coming soon. - -For Rust, these methods are available under the `cache` module, for example `cache::get()`. For Swift, they are prefixed with `Cache`, for example `Suborbital.CacheGet()`. For TypeScript/AssemblyScript, they are prefixed with `cache`, for example `import { cacheGet } from '@suborbital/suborbital'` - -The following namespace methods are available: - -## Set - -Set a given key's value in the cache. The provided TTL is in seconds. - -Rust: - -```rust -pub fn set(key: &str, val: Vec, ttl: i32) -``` - -AssemblyScript: - -```typescript -function cacheSet(key: string, value: ArrayBuffer, ttl: i32): void -``` - -Swift: - -```swift -public func CacheSet(key: String, value: String, ttl: Int) -``` - -## Get - -Get the provided key from the cache. - -Rust: - -```rust -pub fn get(key: &str) -> Result, RunErr> -``` - -AssemblyScript: - -```typescript -function cacheGet(key: string): ArrayBuffer -``` - -Swift: - -```swift -public func CacheGet(key: String) -> String -``` - -Additional cache operations are coming soon. - diff --git a/docs/runnable-api/example-runnable.md b/docs/runnable-api/example-runnable.md deleted file mode 100644 index 3e4c1023..00000000 --- a/docs/runnable-api/example-runnable.md +++ /dev/null @@ -1,35 +0,0 @@ -# Example Runnable - -Here is an example of a Runnable, written in Rust. - -{% hint style="info" %} -The `subo` CLI tool will automatically create new Runnables for you with the `subo create runnable` command. -{% endhint %} - -```rust -use suborbital::runnable::*; -use suborbital::{req, util}; - -struct Foobar{} - -impl Runnable for Foobar { - fn run(&self, _: Vec) -> Result, RunErr> { - let body = req::body_raw(); - let body_string = util::to_string(body); - - Ok(String::from(format!("hello {}", body_string)).as_bytes().to_vec()) - } -} - - -// initialize the runner, do not edit below // -static RUNNABLE: &Foobar = &Foobar{}; - -#[no_mangle] -pub extern fn init() { - use_runnable(RUNNABLE); -} -``` - -This Runnable uses the `req` namespace to fetch the body of the HTTP request being handled, and then returns it. To learn about all of the Runnable API namespaces, read on! - diff --git a/docs/runnable-api/file.md b/docs/runnable-api/file.md deleted file mode 100644 index bc99352f..00000000 --- a/docs/runnable-api/file.md +++ /dev/null @@ -1,30 +0,0 @@ -# Static files - -Files in the `static` directory of an Atmo project will be copied into the Runnable Bundle by `subo`. Those files can then be accessed by Runnables. The directory is mounted as a sandboxed read-only filesystem. - -For Rust, these methods are available under the `file` module, for example `file::get_static()`. - -The following namespace methods are available: - -## Get Static - -Retrieves the contents of the static file with the given name - -Rust: - -```rust -pub fn get_static(name: &str) -> Result, RunErr> -``` - -AssemblyScript: - -```typescript -// not yet supported -``` - -Swift: - -```swift -public func GetStaticFile(name: String) -> String -``` - diff --git a/docs/runnable-api/graphql-requests.md b/docs/runnable-api/graphql-requests.md deleted file mode 100644 index 29c536c6..00000000 --- a/docs/runnable-api/graphql-requests.md +++ /dev/null @@ -1,30 +0,0 @@ -# GraphQL requests - -You can use the `graphql` namespace of the Runnable API to make GraphQL queries from your Runnable code. GraphQL is a common way of exposing external APIs, and makes connecting to external services very straightforward. - -For Rust, these methods are available under the `graphql` module, for example `graphql::query()`. For TypeScript/AssemblyScript, they are prefixed with graphQL, for example `import { graphQLQuery } from '@suborbital/suborbital'` - -The following namespace methods are available: - -## QUERY - -Performs a graphQL query: - -Rust: - -```rust -pub fn query(endpoint: &str, query: &str) -> Result,super::runnable::RunErr> -``` - -AssemblyScript: - -```typescript -function graphQLQuery(endpoint: string, query: string): ArrayBuffer -``` - -Swift: - -```swift -// not yet supported -``` - diff --git a/docs/runnable-api/http.md b/docs/runnable-api/http.md deleted file mode 100644 index 92a869a6..00000000 --- a/docs/runnable-api/http.md +++ /dev/null @@ -1,98 +0,0 @@ -# HTTP requests - -You can use the `http` namespace of the Runnable API to make HTTP requests from your Runnable code. These methods are currently the only way to access the network from Runnable code. Arbitrary socket and network access is not currently possible. - -For Rust, these methods are available under the `http` module, for example `http::get()`. For Swift, they are prefixed with `Http`, for example `Suborbital.HttpGet()` For TypeScript/AssemblyScript, they are prefixed with `http`, for example `import { httpPost } from '@suborbital/suborbital'` - -The following namespace methods are available: - -## GET - -Performs an HTTP GET request - -Rust: - -```rust -pub fn get(url: &str, headers: Option>) -> Result, RunErr> -``` - -AssemblyScript: - -```typescript -function httpGet(url: string, headers: Map | null): ArrayBuffer -``` - -Swift: - -```swift -public func HttpGet(url: String) -> String -``` - -## POST - -Performs an HTTP POST request: - -Rust: - -```rust -pub fn post(url: &str, body: Option>, headers: Option>) -> Result, RunErr> -``` - -AssemblyScript: - -```typescript -function httpPost(url: string, body: ArrayBuffer, headers: Map | null): ArrayBuffer -``` - -Swift: - -```swift -public func HttpPost(url: String, body: String) -> String -``` - -## PATCH - -Performs an HTTP PATCH request: - -Rust: - -```rust -pub fn patch(url: &str, body: Option>, headers: Option>) -> Result, RunErr> -``` - -AssemblyScript: - -```typescript -function httpPatch(url: string, body: ArrayBuffer, headers: Map | null): ArrayBuffer -``` - -Swift: - -```swift -public func HttpPatch(url: String, body: String) -> String -``` - -## DELETE - -Performs an HTTP DELETE request: - -Rust: - -```rust -pub fn delete(url: &str, headers: Option>) -> Result, RunErr> -``` - -AssemblyScript: - -```typescript -function httpDelete(url: string, headers: Map | null): ArrayBuffer -``` - -Swift: - -```swift -public func HttpDelete(url: String) -> String -``` - -Swift does not yet support passing headers to a request. - diff --git a/docs/runnable-api/introduction.md b/docs/runnable-api/introduction.md deleted file mode 100644 index e9209fd5..00000000 --- a/docs/runnable-api/introduction.md +++ /dev/null @@ -1,58 +0,0 @@ -# Introduction - -The Runnables that you write for your Atmo application are compiled to WebAssembly, and are run in a controlled sandbox. The **Runnable API** is the set of capabilities Atmo grants to the sandbox which can be used to build your application's logic. - -When a Runnable is handling a particular request, Atmo binds that request to the module while it's being run. The Runnable API allows your code to access everything about the request, and also gives you the ability to access the "outside world" by giving functions for HTTP requests, accessing static files, logging, and more. This section describes all of the capabilities available via the Runnable API and how to use them in Rust and Swift Runnable code. - -The Runnable API is provided via a library for each of the supported languages, and simply needs to be imported to turn your module into a Runnable. `subo` will configure all of this on your behalf. - -The first and most basic part of the Runnable API is the `Runnable` interface \(also known as a Rust trait or Swift protocol\). Every Runnable you write will provide an instance of an object that conforms to this interface. It is very simple, and only requires one method, `run`. - -{% hint style="success" %} -The Rust Runnable API crate is considered stable -{% endhint %} - -In Rust: - -```rust -pub trait Runnable { - fn run(&self, input: Vec) -> Result, RunErr>; -} -``` - -{% hint style="warning" %} -The TypeScript/AssemblyScript Runnable API library is still considered experimental. -{% endhint %} - -In TypeScript/AssemblyScript: - -```typescript -export function run(input: ArrayBuffer): ArrayBuffer -``` - -{% hint style="warning" %} -The Swift Runnable API library is still considered experimental, and tends to lag slightly behind the others in terms of available features. -{% endhint %} - -And in Swift: - -```swift -public protocol Runnable { - func run(input: String) -> String -} -``` - -Your Runnable object will be created automatically by `subo` when you use the `create runnable` command. All you need to do is write your logic within the `run` method, and Atmo will handle executing it. - -There are several namespaces available in the Runnable API, each are discussed in the following pages. - -* [req](request.md) -* [resp](response.md) -* [http](http.md) -* [graphql](graphql-requests.md) -* [cache](cache.md) -* [file](file.md) -* [log](https://github.com/suborbital/atmo/tree/215d8b0db4673915847a5fd25d4d5c84b8d89186/docs/runnable-api/log.md) - -When handling an HTTP request, the input to the `run` method is the body of the request being handled. The other details of the request are available using the `req` namespace, which will be discussed next. - diff --git a/docs/runnable-api/logging.md b/docs/runnable-api/logging.md deleted file mode 100644 index 800398cd..00000000 --- a/docs/runnable-api/logging.md +++ /dev/null @@ -1,74 +0,0 @@ -# Structured logging - -Your Runnable code can log to Atmo's structured output using the logging methods. - -For Rust, these methods are available under the `log` module, for example `log::info()`. For Swift, they are prefixed with `Log`, for example `Suborbital.LogInfo()` For TypeScript/AssemblyScript, they are prefixed with `log`, for example `import { logInfo } from '@suborbital/suborbital'` - -The following namespace methods are available: - -## Info - -Logs the message with the 'info' level: - -Rust: - -```rust -pub fn info(msg: &str) -``` - -AssemblyScript: - -```typescript -function logInfo(msg: string): void -``` - -Swift: - -```swift -public func LogInfo(msg: String) -``` - -## Warn - -Logs the message with the 'warn' level: - -Rust: - -```rust -pub fn warn(msg: &str) -``` - -AssemblyScript: - -```typescript -function logWarn(msg: string): void -``` - -Swift: - -```swift -public func LogWarn(msg: String) -``` - -## Error - -Logs the message with the 'err' level: - -Rust: - -```rust -pub fn error(msg: &str) -``` - -AssemblyScript: - -```typescript -function logErr(msg: string): void -``` - -Swift: - -```swift -public func LogErr(msg: String) -``` - diff --git a/docs/runnable-api/request.md b/docs/runnable-api/request.md deleted file mode 100644 index f922ca50..00000000 --- a/docs/runnable-api/request.md +++ /dev/null @@ -1,184 +0,0 @@ -# Handling requests - -When a Runnable is used to handle an HTTP request, Atmo will bind that request to the Runnable. The `req` namespace of the Runnable API can then be used to access all of the information about the request. Note if the Runnable is not being used to handle a request, then all methods in the `req` namespace will return empty or an error. - -For Rust, these methods are available under the `req` module, for example `req::method()`. For Swift, they are prefixed with `Req`, for example `Suborbital.ReqMethod()`. For TypeScript/AssemblyScript, they are prefixed with `req`, for example `import { reqState } from '@suborbital/suborbital'` - -The following namespace methods are available: - -## State - -Returns the value from [request state](../usage/managing-state.md) for the provided key: - -Rust: - -```rust -pub fn state(key: &str) -> Option -``` - -AssemblyScript: - -```typescript -function reqState(key: string): string -``` - -Swift: - -```swift -public func State(key: String) -> String -``` - -## Method - -Returns the HTTP method for the request: - -Rust: - -```rust -pub fn method() -> String -``` - -AssemblyScript: - -```typescript -function reqMethod(): string -``` - -Swift: - -```swift -public func ReqMethod() -> String -``` - -## URL - -Returns the full URL of the request: - -Rust: - -```rust -pub fn url() -> String -``` - -AssemblyScript: - -```typescript -function reqURL(): string -``` - -Swift: - -```swift -public func ReqURL() -> String -``` - -## ID - -Returns the unique ID assigned to the request by Atmo: - -Rust: - -```rust -pub fn id() -> String -``` - -AssemblyScript: - -```typescript -function reqID(): string -``` - -Swift: - -```swift -public func ReqID() -> String -``` - -## Body - -Returns the full request body as bytes: - -Rust: - -```rust -pub fn body_raw() -> Vec -``` - -AssemblyScript: - -```typescript -function reqBody(): ArrayBuffer -``` - -Swift: - -```swift -public func ReqBodyRaw() -> String -``` - -## Body Field - -Returns the value for the provided key, if the request body is formatted as JSON: - -Rust: - -```rust -pub fn body_field(key: &str) -> String -``` - -AssemblyScript: - -```typescript -function reqBodyField(key: string): string -``` - -Swift: - -```swift -public func ReqBodyField(key: String) -> String -``` - -## Header - -Returns the header value for the provided key: - -Rust: - -```rust -pub fn header(key: &str) -> String -``` - -AssemblyScript: - -```typescript -function reqHeader(key: string): string -``` - -Swift: - -```swift -public func ReqHeader(key: String) -> String -``` - -## URL Parameter - -Returns the URL parameter for the provided key, for example `/api/v1/user/:uuid` - -Rust: - -```rust -pub fn url_param(key: &str) -> String -``` - -AssemblyScript: - -```typescript -function reqURLParam(key: string): string -``` - -Swift: - -```swift -public func ReqParam(key: String) -> String -``` - diff --git a/docs/runnable-api/response.md b/docs/runnable-api/response.md deleted file mode 100644 index d7234fc4..00000000 --- a/docs/runnable-api/response.md +++ /dev/null @@ -1,52 +0,0 @@ -# Modifying responses - -When a Runnable is used to handle an HTTP request, Atmo will bind that request to the Runnable. The `resp` namespace of the Runnable API can then be used to modify the response that Atmo will send to the caller. - -For Rust, these methods are available under the `resp` module, for example `resp::set_header()`. Swift and TypeScript/AssemblyScript support is coming soon. - -The following namespace methods are available: - -## Response header - -Sets an HTTP response header: - -Rust: - -```rust -pub fn set_header(key: &str, val: &str) -``` - -AssemblyScript: - -```typescript -// not yet available -``` - -Swift: - -```swift -// not yet available -``` - -## Content-Type - -An alias of `set_header` that allows easily setting the response Content-Type - -Rust: - -```rust -pub fn content_type(ctype: &str) -``` - -AssemblyScript: - -```typescript -// not yet available -``` - -Swift: - -```swift -// not yet available -``` - diff --git a/docs/usage/building-a-bundle.md b/docs/usage/building-a-bundle.md deleted file mode 100644 index 1e28ebd6..00000000 --- a/docs/usage/building-a-bundle.md +++ /dev/null @@ -1,29 +0,0 @@ -# Building a Bundle - -To run your Atmo application, we need to create a Runnable Bundle. A Bundle is a `.wasm.zip` file that includes your Directive, along with all of your Runnables compiled to WebAssembly modules. Bundles are built using `subo`. **Note** that you should pass the root of your Atmo project as the first argument: - -```bash -subo build . -``` -**Note:** If building the example project with subo from the root of the repository, pass the directory: subo build ./example-project - -The end of this command should read: - -`✅ DONE: bundle was created -> ./runnables.wasm.zip` - -## Running the Atmo development server - -Once you have your Runnable Bundle, you can run Atmo: - -```text -> subo dev -``` - -Atmo will start up serving on port 8080, and you will begin to see its structured logs in your terminal. **Note** Check Docker to ensure only Atmo is running on the port or else the Atmo developement server will not start correctly. Make a request to `POST localhost:8080/hello` with a request body to see it in action. - -{% hint style="info" %} -The version of Atmo being run by `subo dev` is dictated by the `atmoVersion` key in your Directive. -{% endhint %} - -Continue on to learn how to operate Atmo in real-world scenarios. - diff --git a/docs/usage/connections.md b/docs/usage/connections.md deleted file mode 100644 index 22ba4411..00000000 --- a/docs/usage/connections.md +++ /dev/null @@ -1,69 +0,0 @@ -# Connections - -In order to build a useful application, Atmo needs to be able to connect to external resources. Currently, Atmo can connect to [NATS](https://nats.io/) and [Redis](https://redis.io/), and upcoming releases will include additional types such as databases and more. - -To create connections, add a `connections` section to your Directive. When Atmo starts up, it will establish the connections you've configured, and make them available to your application in a few different ways. - -## Stream sources -There are two available stream sources (NATS and Kafka) that can be used as sources for your handlers: -```yaml -connections: - nats: - serverAddress: nats://localhost:4222 - kafka: - brokerAddress: localhost:9092 -``` - -The NATS or Kafka connection is made available as a stream source: - -```yaml - - type: stream - source: nats - resource: user.created - steps: - - fn: record-signup -``` - -By setting the `source` field of the handler, we tell Atmo to listen to that particular connection and handle messages it sends us. The `resource` field dictates which topic or subject the handler is listening to, which is useful for messaging systems such as NATS and Kafka. - -Streams that use an external source can also use the `respondTo` field to set which topic or subject the response message is sent to: - -```yaml -- type: stream - source: nats - resource: user.login - steps: - - fn: record-login - respondTo: user.send-login-email -``` - -## Data sources -SQL databases and caches can be connected to Atmo to be made available to your Runnables using the Runnable API: -```yaml -connections: - database: - type: postgresql - connectionString: env(DATABASE) - redis: - serverAddress: localhost:6379 -``` -SQL database connections of type `mysql` and `postgresql` are available, and they are discussed in detail in the [next section](./using-sql-databases.md). - -Redis connections are made available to Runnables utilizing the `cache` capability: -```rust -use suborbital::runnable::*; -use suborbital::req; -use suborbital::cache; - -struct CacheGet{} - -impl Runnable for CacheGet { - fn run(&self, _: Vec) -> Result, RunErr> { - let key = req::url_param("key"); - - let val = cache::get(key.as_str()).unwrap_or_default(); - - Ok(val) - } -} -``` \ No newline at end of file diff --git a/docs/usage/creating-handlers.md b/docs/usage/creating-handlers.md deleted file mode 100644 index f35a4e09..00000000 --- a/docs/usage/creating-handlers.md +++ /dev/null @@ -1,58 +0,0 @@ -# Creating handlers - -{% hint style="info" %} -If you haven't created a project yet, see [Get started](../getstarted/) first. -{% endhint %} - -Your project contains a `Directive.yaml` file that controls your entire application. The Directive is included in the Runnable Bundle used by Atmo to run your application. - -The Directive has some metadata such as a unique application identifier and a version number, as well as some handlers. - -Each handler tells Atmo how to handle a **resource.** A resource is an input that Atmo makes available via HTTP endpoints, event handlers, and more. To start, Atmo supports handlers for HTTP requests, particulary designed to help building web APIs. Here is an example Directive: - -```yaml -identifier: com.suborbital.test -appVersion: v0.0.1 -atmoVersion: v0.4.4 - -handlers: - - type: request - resource: /hello - method: POST - steps: - - group: - - fn: modify-url - - fn: helloworld-rs - as: hello - - fn: fetch-test - with: - url: modify-url - logme: hello -``` - -This describes the application being constructed. It declares a resource \(`HTTP POST /hello`\) and a set of `steps` to handle that request. The `steps` are a set of Runnable functions to be **composed** when handling requests to the `/hello` endpoint. - -There are two types of `step`. The first step you see above is a `group`, meaning that all of the functions in that group will be executed **concurrently**. - -The second step shown above is a single `fn` , which calls a Runnable that uses the [Runnable API](../runnable-api/introduction.md) to make an HTTP request. The API is continually evolving to include more capabilities. In addition to making HTTP requests, it includes logging, database connections, caching, and more. - -The output of the final function in a handler is used as the response data for the request, by default. If you wish to use the output from a different function, you can include the `response` option in your handler, listing the name of the function to use as a response. If the final step is a group, then the `response` clause must be included. - -For example: - -```yaml -steps: - - group: - - fn: modify-url - - fn: helloworld-rs - as: hello - - fn: fetch-test - with: - url: modify-url - logme: hello -response: hello -``` - -Your application can contain as many handlers as needed, and functions can be re-used among many handlers. Each Runnable in your project can be called by its name. The `subo` tool will validate your directive to ensure it is not calling any Runnables that don't exist in your project. - -The `as` and `with` clauses shown above will be discussed [next](managing-state.md). diff --git a/docs/usage/creating-runnables.md b/docs/usage/creating-runnables.md deleted file mode 100644 index dcfdb0dc..00000000 --- a/docs/usage/creating-runnables.md +++ /dev/null @@ -1,28 +0,0 @@ -# Creating Runnables - -{% hint style="info" %} -**You'll need to install the subo CLI tool and Docker to use Atmo**. - -To install the tool, [visit the subo repository](https://github.com/suborbital/subo). - -Docker is used to build Runnables and run the Atmo development server. -{% endhint %} - -## Create a Runnable - -You can create a new Runnable with subo: - -```text -> subo create runnable myfunction -``` - -By default, Rust will be used. To use Swift, pass `--lang`: - -```text -> subo create runnable myswiftfunction --lang=swift -``` - -Each runnable has a `.runnable.yaml` that describes it. The name you provide to the `create runnable` command is the name that will be used to call the Runnable in Directive handlers, which are discussed next. - -Your Runnables will use the [Runnable API](../runnable-api/introduction.md) to access resources such as the network, files, and more. Read more by clicking on the link or continuing through the guide. - diff --git a/docs/usage/deploying-atmo.md b/docs/usage/deploying-atmo.md deleted file mode 100644 index 5159b15b..00000000 --- a/docs/usage/deploying-atmo.md +++ /dev/null @@ -1,53 +0,0 @@ -# Deploying Atmo - -{% hint style="warning" %} -Atmo is still in early Beta, and as such should not yet be used for production workloads. -{% endhint %} - -Atmo is distributed as a Docker image: `suborbital/atmo` - -To run Atmo, you can mount your Runnable Bundle as a volume, build your own container image that embeds it, or set Atmo to wait for a bundle to be uploaded. - -## Volume mount - -To mount as a volume: - -```text -> docker run -v /path/to/bundle/directory:/home/atmo -e ATMO_HTTP_PORT=8080 -p 8080:8080 suborbital/atmo:latest atmo -``` - -This will launch Atmo, assign it to listen on port 8080, and run in HTTP mode. - -## Embed Bundle - -To create your own Docker image with your Bundle embedded, you can use a Dockerfile similar to this: - -```yaml -FROM suborbital/atmo:latest - -COPY ./runnables.wasm.zip . - -ENTRYPOINT atmo -``` - -Building this Dockerfile would result in an image that doesn't need a volume mount. - -## Bundle upload - -To upload a bundle after launching Atmo, use the `--wait` flag or set the `ATMO_WAIT=true` env var. This will cause Atmo to check the disk once per second until it finds a bundle rather than exiting with an error if no bundle is found. This method allows you to launch Atmo and then upload a bundle seperately by copying it into the running container, as with the [experimental Kubernetes deployment](https://github.com/suborbital/atmo-k8s-helm). - -### HTTPS - -To run with HTTPS, replace `ATMO_HTTP_PORT=8080` with `ATMO_DOMAIN=example.com` to enable LetsEncrypt on ports 443 and 80. You will need to pass the `-p` Docker flag for each. - -### Logging - -To control logging in Atmo, you can use its environment variables: - -* `ATMO_LOG_LEVEL` can be set to any of `trace, debug, info, warn, error` -* `ATMO_LOG_FILE` can be set to a file to log to \(stdout will become plaintext logs, structured logs will be written to the file\) - -### Schedules - -To prevent an Atmo instance from executing the [Schedules](schedules.md) defined in your Directive, you can set the `ATMO_RUN_SCHEDULES=false` env var. This can be useful for running non-idempotent jobs on a specific worker instance. - diff --git a/docs/usage/error-handling.md b/docs/usage/error-handling.md deleted file mode 100644 index 9316e4c3..00000000 --- a/docs/usage/error-handling.md +++ /dev/null @@ -1,48 +0,0 @@ -# Error handling - -When building your Atmo app, handling errors returned from Runnables is pretty essential. When a Runnable returns an error, it contains a `code` and a `message`. The `code` must be a valid [HTTP response status code](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status). Using the Directive, you can manage how your application behaves when an error is returned: - -{% hint style="info" %} -The default behaviour for any error is for the handler to return. -{% endhint %} - -Any time a Runnable returns an error, you can decide what to do with it using the `onErr` clause: - -```yaml -- type: request - resource: /repo/report/*repo - method: GET - steps: - - fn: check-cache - as: report - onErr: - any: continue - - - fn: send-report -``` - -In its basic form, onErr allows you to tell Atmo to ignore any error from a Runnable. When using `continue`, the JSON of the error will be placed into state, such as `{"code":404,"message":"not found"}` - -To gain more control, you can choose what to do based on error codes: - -```yaml -- type: request - resource: /repo/report/*repo - method: GET - steps: - - fn: check-cache - as: report - onErr: - code: - 404: continue - other: return - - - fn: send-report -``` - -Technically, any `return` \(such as an 'any' or 'other'\) can be omitted since it is the default behaviour, but it can improve readability of your Directive when included. - -When defining specific error codes, you cannot use 'any', use 'other' instead. If no specific codes are specified, use 'any'. - -Whenever Atmo decides to return based on your Directive's instructions, the error's JSON is returned to the caller with the status code set to the error code. - diff --git a/docs/usage/headless.md b/docs/usage/headless.md deleted file mode 100644 index 453f9954..00000000 --- a/docs/usage/headless.md +++ /dev/null @@ -1,50 +0,0 @@ -# Headless Mode - -Atmo can be run 'headless' mode, which causes it to ignore the Directive and instead make each Runnable in your application available as an individual endpoint. This can be useful for a number of things such as automated testing \(being able to test each Runnable in isolation with controlled inputs\). - -Each function will be made available at a URI such as this: - -```text -POST /com.suborbital.test/default/get-file/v0.0.1 -``` - -The format of this URL is: `/[identifier]/[namespace]/[name]/[appVersion]`. Your Directive defines the identifier and appVersion, and the namespace and name of each Runnable are listed in the `.runnable.yaml` file within each Runnable's directory. - -To define the inputs for the request, you can use the following: - -| Desired input | Headless Request | Runnable API | -| :--- | :--- | :--- | -| Request body | POST request body | `req::body()` | -| Request state | `X-Atmo-State` header, formatted as JSON key/value pairs | `req::state(key)` | -| URL parameters \(such as /:name\) | `X-Atmo-Params` header, formatted as JSON key/value pairs | `req::param(key)` | - -For example, if your Runnable expects data in the `user` [request state](../concepts/state.md) key, you would set the `X-Atmo-State` header as such: - -```text -{"user": "user@suborbital.dev"} -``` - -And if your Runnable expects to parse URL parameters such as `/api/:user`, you can use the `X-Atmo-Params` header in a similar fashion. - -When running in headless mode, the unique UUID for each request will be returned in the `X-Atmo-Requestid` response header field. - -## Running in Headless mode - -To run Atmo in headless mode, set the `ATMO_HEADLESS` env var: - -```text -ATMO_HEADLESS=true -``` - -In a Dockerfile, you can use the `ENV` command: - -```text -ENV ATMO_HEADLESS=true -``` - -Or with the Docker CLI: - -```text -docker run [...] -e ATMO_HEADLESS=true suborbital/atmo atmo -``` - diff --git a/docs/usage/managing-state.md b/docs/usage/managing-state.md deleted file mode 100644 index 137c9a0b..00000000 --- a/docs/usage/managing-state.md +++ /dev/null @@ -1,60 +0,0 @@ -# Managing state - -Let's take another look at the example Directive: - -```yaml -identifier: com.suborbital.test -appVersion: v0.0.1 -atmoVersion: v0.0.6 - -handlers: - - type: request - resource: /hello - method: POST - steps: - - group: - - fn: modify-url - - fn: helloworld-rs - as: hello - - fn: fetch-test - with: - url: modify-url - logme: hello -``` - -After each `step`, its function results gets stored in the request handler's `state`. The `state` is an ephemeral set of key/value pairs created for each request. State is used to pass values between functions, since they are completely isolated and unaware of one another. - -The `modify-url` function for example takes the request body \(in this case, a URL\), and modifies it \(by adding `/suborbital` to it\). - -The second step \(`fetch-test`\) takes that modified URL and makes an HTTP request to fetch it. - -There are two clauses, `as` and `with` that make working with request state easier. - -## As - -`as` will assign the value returned by a function to a particular name in state. In the above example, `helloworld-rs` is saved into state as `hello`. You can think of this just like storing a value into a variable! - -For example, the request state after the first step will look like this: - -```text -{ - "modify-url": "https://github.com/suborbital" - "hello": "hello github.com" -} -``` - -## With - -`with` allows the developer to pass a "desired state" into a given function. Rather than passing the entire state with the existing keys, the developer can optionally define a custom state by choosing aliases for some or all of the keys available in request state. This is just like choosing parameter values to pass into function arguments! - -For example, the `fetch-test` function above will recieve a state object that looks like this: - -```text -{ - "url": "https://github.com/suborbital", - "logme": "hello github.com" -} -``` - -`subo` will validate your directive to help ensure that your Directive is correct, including validating that you're not accessing keys that don't exist in state. - diff --git a/docs/usage/schedules.md b/docs/usage/schedules.md deleted file mode 100644 index 5383c4a7..00000000 --- a/docs/usage/schedules.md +++ /dev/null @@ -1,29 +0,0 @@ -# Scheduled jobs - -You can easily define background jobs in your Directive that Atmo will run on a schedule. Schedules run a set of steps, exactly like a handler. Schedules can be set up with an initial state to provide input. - -```yaml -schedules: - - name: atmo-report - every: - hours: 1 - state: - repo: suborbital/atmo - steps: - - fn: ghstars - - - fn: send-report - with: - stargazers: ghstars -``` - -As you can see, you can choose how often the job runs using the `every` clause. You can set seconds, minutes, hours, or days \(and you can combine them for values such as 'every 1 hour and 15 minutes'\). - -{% hint style="info" %} -If you need to change a Runnable's behaviour to run in a schedule, you can check `req::method() == "SCHED"`. This can be useful when using the same Runnable for both request handlers and schedules. -{% endhint %} - -Setting the `state` clause will allow you to 'seed' the job with values, and that state will update after each step, just as with request handlers. See [state](../concepts/state.md) for more details. - -Any issues running schedules \(such as Runnables returning errors or any failures to execute the Runnables\) will be logged, but nothing else. - diff --git a/docs/usage/streams.md b/docs/usage/streams.md deleted file mode 100644 index 7f69d9ec..00000000 --- a/docs/usage/streams.md +++ /dev/null @@ -1,17 +0,0 @@ -# Streams - -Atmo can handle several different types of input. The default is an HTTP request, which is defined with `type: request` in a Directive handler. There is another type of input called `stream` which allows Atmo to listen to streaming data sources and handle messages it receives from them. - -A stream handler looks like this: - -```yaml -- type: stream - resource: /stream - steps: - - fn: handle-message -``` - -By default, a stream handler allows a client to connect to Atmo's webserver using a **standard websocket**. The `resource` defines the URI that the websocket handler is available on, and it uses Atmo's built-in server to expose these endpoints. Each message sent by the client over this connection is handled by executing the `steps` in the handler. - -Streams can also come from external sources such as NATS and Kafka, which is detailed in the next section. - diff --git a/docs/usage/using-sql-databases.md b/docs/usage/using-sql-databases.md deleted file mode 100644 index 49dcf301..00000000 --- a/docs/usage/using-sql-databases.md +++ /dev/null @@ -1,96 +0,0 @@ -# Using SQL databases - -To connect Atmo with your SQL database, you will define the connection using the `connections` section of the Directive, and then define queries that your Runnables can execute. Runnables are not allowed to execute arbitrary queries. Instead, a list of named queries are provided in a Queries.yaml file, and then your Runnables are allowed to execute them. - -If you haven't already, take a look at Connections to define the connection to your database, then come back here. - -{% hint style="info" %} -Atmo's Database capability is in preview, and we would love your feedback on the approach as well as the Rust APIs. We are eager to improve it, and we hope you'll try it out! Please join our Discord to give us feedback. -{% endhint %} - -## Defining queries - -Once the connection to your database is defined, create a `Queries.yaml` file in your project's directory, right next to `Directive.yaml`. It will have this structure: -```yaml -queries: - - name: "InsertUser" - query: |- - INSERT INTO users (uuid, email, created_at, state, identifier) - VALUES ($1, $2, NOW(), 'A', 12345) - - - name: "SelectUserWithUUID" - query: |- - SELECT * FROM users - WHERE uuid = $1 - - - name: "UpdateUserWithUUID" - query: |- - UPDATE users SET state='B' - WHERE uuid = $1 -``` - -You can define any number of queries. Each query must have a name and a query value. - -Queries can optionally have a `type` field (specifying `select | update | insert | delete`) and a `varCount` field to specify the number of variables in the query. In most circumstances, these optional fields are detected automatically by Atmo, but if for any reason they are detected incorrectly, you can set them explicitly. - -## Query variables -Queries can contain variables in either the MySQL style `?` or in the PostgreSQL style `$1`. Both will be auto-detected by Atmo, and Runnables will be required to provide the correct number of arguments to fill those variables whenever a query is called. - -## How it works -SQL queries in Atmo are automatically turned into prepared statements that ensure your queries are executed safely. Atmo uses industry-standard database drivers to maintain a connection pool with your database. Runnables are allowed to execute the defined queries and provide the arguments to be inserted into those queries. Your code does not need to concern itself with the underlying database connections, pooling, credentials, etc. You can focus on building your business logic. - -## Executing queries -Once you've defined queries in your Queries.yaml file, the `suborbital` Rust crate has APIs for executing various query types: -```rust -use suborbital::runnable::*; -use suborbital::db; -use suborbital::db::query; -use suborbital::log; -use uuid::Uuid; - -struct CreateUser{} - -impl Runnable for CreateUser { - fn run(&self, _: Vec) -> Result, RunErr> { - let uuid = Uuid::new_v4().to_string(); - - let mut args: Vec = Vec::new(); - args.push(query::QueryArg::new("uuid", uuid.as_str())); - args.push(query::QueryArg::new("email", "connor@suborbital.dev")); - - match db::insert("InsertUser", args) { - Ok(_) => log::info("insert successful"), - Err(e) => { - return Err(RunErr::new(500, e.message.as_str())) - } - }; - - let mut args2: Vec = Vec::new(); - args2.push(query::QueryArg::new("uuid", uuid.as_str())); - - match db::update("UpdateUserWithUUID", args2.clone()) { - Ok(_) => log::info("update successful"), - Err(e) => { - return Err(RunErr::new(500, e.message.as_str())) - } - }; - - match db::select("SelectUserWithUUID", args2) { - Ok(result) => Ok(result), - Err(e) => { - Err(RunErr::new(500, e.message.as_str())) - } - } - } -} - -// initialize the runner, do not edit below // -static RUNNABLE: &CreateUser = &CreateUser{}; - -#[no_mangle] -pub extern fn _start() { - use_runnable(RUNNABLE); -} - -``` -Runnables can execute any of the queries defined in `Queries.yaml`. The `args` they provide are inserted into the queries' variables by Atmo, and then executed. The query's results are returned to the Runnable in JSON form. \ No newline at end of file diff --git a/example-project/Directive.yaml b/example-project/Directive.yaml index 97474200..4c18711b 100644 --- a/example-project/Directive.yaml +++ b/example-project/Directive.yaml @@ -1,6 +1,6 @@ identifier: com.suborbital.test appVersion: v0.0.1 -atmoVersion: v0.4.4 +atmoVersion: v0.4.5 # uncomment to try out connections! connections: