Merge pull request #137 from radu-matei/docs
This commit is contained in:
commit
70b3893127
|
@ -2,5 +2,6 @@
|
||||||
"recommendations": [
|
"recommendations": [
|
||||||
"matklad.rust-analyzer",
|
"matklad.rust-analyzer",
|
||||||
"serayuzgur.crates",
|
"serayuzgur.crates",
|
||||||
|
"fermyon.autobindle",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -2888,10 +2888,7 @@ name = "spin-config"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
|
||||||
"itertools",
|
|
||||||
"serde",
|
"serde",
|
||||||
"tokio",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2899,31 +2896,15 @@ name = "spin-engine"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
|
||||||
"bindle",
|
|
||||||
"bytes 1.1.0",
|
"bytes 1.1.0",
|
||||||
"dirs 4.0.0",
|
|
||||||
"fs_extra",
|
|
||||||
"futures",
|
|
||||||
"git2",
|
|
||||||
"glob",
|
|
||||||
"lazy_static",
|
|
||||||
"regex",
|
|
||||||
"serde",
|
|
||||||
"sha2 0.10.1",
|
|
||||||
"spin-config",
|
"spin-config",
|
||||||
"structopt",
|
|
||||||
"tempfile",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml",
|
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-futures",
|
"tracing-futures",
|
||||||
"tracing-subscriber 0.3.8",
|
|
||||||
"wasi-common",
|
"wasi-common",
|
||||||
"wasi-experimental-http-wasmtime 0.9.0 (git+https://github.com/deislabs/wasi-experimental-http?rev=4ed321d6943f75546e38bba80e14a59797aa29de)",
|
"wasi-experimental-http-wasmtime 0.9.0 (git+https://github.com/deislabs/wasi-experimental-http?rev=4ed321d6943f75546e38bba80e14a59797aa29de)",
|
||||||
"wasmtime",
|
"wasmtime",
|
||||||
"wasmtime-wasi",
|
"wasmtime-wasi",
|
||||||
"wit-bindgen-rust",
|
|
||||||
"wit-bindgen-wasmtime",
|
"wit-bindgen-wasmtime",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2957,7 +2938,6 @@ dependencies = [
|
||||||
"wasi-common",
|
"wasi-common",
|
||||||
"wasmtime",
|
"wasmtime",
|
||||||
"wasmtime-wasi",
|
"wasmtime-wasi",
|
||||||
"wit-bindgen-rust",
|
|
||||||
"wit-bindgen-wasmtime",
|
"wit-bindgen-wasmtime",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,4 @@ authors = [ "Fermyon Engineering <engineering@fermyon.com>" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
async-trait = "0.1.52"
|
|
||||||
itertools = "0.10.3"
|
|
||||||
serde = { version = "1.0", features = [ "derive" ] }
|
serde = { version = "1.0", features = [ "derive" ] }
|
||||||
tokio = "1.16.1"
|
|
||||||
|
|
|
@ -185,7 +185,7 @@ pub struct WagiConfig {
|
||||||
///
|
///
|
||||||
/// This should be a space-separate list of strings. The value
|
/// This should be a space-separate list of strings. The value
|
||||||
/// ${SCRIPT_NAME} will be replaced with the Wagi SCRIPT_NAME,
|
/// ${SCRIPT_NAME} will be replaced with the Wagi SCRIPT_NAME,
|
||||||
/// and the value ${ARGS} will be replaced with the query paramater
|
/// and the value ${ARGS} will be replaced with the query parameter
|
||||||
/// name/value pairs presented as args. For example,
|
/// name/value pairs presented as args. For example,
|
||||||
/// `param1=val1¶m2=val2` will become `param1=val1 param2=val2`,
|
/// `param1=val1¶m2=val2` will become `param1=val1 param2=val2`,
|
||||||
/// which will then be presented to the program as two arguments
|
/// which will then be presented to the program as two arguments
|
||||||
|
|
|
@ -6,31 +6,15 @@ authors = [ "Radu Matei <radu.matei@fermyon.com>" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.44"
|
anyhow = "1.0.44"
|
||||||
async-trait = "0.1.51"
|
|
||||||
bindle = "0.8.0"
|
|
||||||
bytes = "1.1.0"
|
bytes = "1.1.0"
|
||||||
dirs = "4.0"
|
|
||||||
fs_extra = "1.2.0"
|
|
||||||
futures = "0.3.17"
|
|
||||||
git2 = "0.13"
|
|
||||||
glob = "0.3.0"
|
|
||||||
lazy_static = "1.4.0"
|
|
||||||
regex = "1.5.4"
|
|
||||||
serde = { version = "1.0.130", features = [ "derive" ] }
|
|
||||||
sha2 = "0.10.1"
|
|
||||||
spin-config = { path = "../config" }
|
spin-config = { path = "../config" }
|
||||||
structopt = "0.3.23"
|
|
||||||
tempfile = "3.3.0"
|
|
||||||
tokio = { version = "1.10.0", features = [ "fs" ] }
|
tokio = { version = "1.10.0", features = [ "fs" ] }
|
||||||
toml = "0.5.8"
|
|
||||||
tracing = { version = "0.1", features = [ "log" ] }
|
tracing = { version = "0.1", features = [ "log" ] }
|
||||||
tracing-futures = "0.2"
|
tracing-futures = "0.2"
|
||||||
tracing-subscriber = { version = "0.3.7", features = [ "env-filter" ] }
|
|
||||||
wasi-common = "0.34"
|
wasi-common = "0.34"
|
||||||
wasi-experimental-http-wasmtime = { git = "https://github.com/deislabs/wasi-experimental-http", rev = "4ed321d6943f75546e38bba80e14a59797aa29de" }
|
wasi-experimental-http-wasmtime = { git = "https://github.com/deislabs/wasi-experimental-http", rev = "4ed321d6943f75546e38bba80e14a59797aa29de" }
|
||||||
wasmtime = "0.34"
|
wasmtime = "0.34"
|
||||||
wasmtime-wasi = "0.34"
|
wasmtime-wasi = "0.34"
|
||||||
wit-bindgen-rust = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "e9c7c0a3405845cecd3fe06f3c20ab413302fc73" }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wit-bindgen-wasmtime = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "e9c7c0a3405845cecd3fe06f3c20ab413302fc73" }
|
wit-bindgen-wasmtime = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "e9c7c0a3405845cecd3fe06f3c20ab413302fc73" }
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
name = "spin-http-engine"
|
name = "spin-http-engine"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = [ "Radu Matei <radu.matei@fermyon.com>" ]
|
authors = [ "Fermyon Engineering <engineering@fermyon.com>" ]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
doctest = false
|
doctest = false
|
||||||
|
@ -33,8 +33,7 @@ wagi = { git = "https://github.com/deislabs/wagi", rev = "984c3922626b770ba43443
|
||||||
wasi-common = "0.34"
|
wasi-common = "0.34"
|
||||||
wasmtime = "0.34"
|
wasmtime = "0.34"
|
||||||
wasmtime-wasi = "0.34"
|
wasmtime-wasi = "0.34"
|
||||||
wit-bindgen-rust = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "e9c7c0a3405845cecd3fe06f3c20ab413302fc73" }
|
|
||||||
wit-bindgen-wasmtime = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "e9c7c0a3405845cecd3fe06f3c20ab413302fc73" }
|
wit-bindgen-wasmtime = { git = "https://github.com/bytecodealliance/wit-bindgen", rev = "e9c7c0a3405845cecd3fe06f3c20ab413302fc73" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
miniserde = "0.1"
|
miniserde = "0.1"
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
name = "spin-loader"
|
name = "spin-loader"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
authors = [ "Fermyon Engineering <engineering@fermyon.com>" ]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
|
|
|
@ -74,7 +74,7 @@ pub struct RawWasmConfig {
|
||||||
/// Files to be mapped inside the Wasm module at runtime.
|
/// Files to be mapped inside the Wasm module at runtime.
|
||||||
///
|
///
|
||||||
/// In the local configuration file, this is a vector, each element of which
|
/// In the local configuration file, this is a vector, each element of which
|
||||||
/// is either a file paths or glob relative to the spin.toml file, or a
|
/// is either a file path or glob relative to the spin.toml file, or a
|
||||||
/// mapping of a source path to an absolute mount path in the guest.
|
/// mapping of a source path to an absolute mount path in the guest.
|
||||||
pub files: Option<Vec<RawFileMount>>,
|
pub files: Option<Vec<RawFileMount>>,
|
||||||
/// Optional list of HTTP hosts the component is allowed to connect.
|
/// Optional list of HTTP hosts the component is allowed to connect.
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
name = "spin-publish"
|
name = "spin-publish"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
authors = [ "Fermyon Engineering <engineering@fermyon.com>" ]
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
name = "spin-templates"
|
name = "spin-templates"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = [ "Radu Matei <radu.matei@fermyon.com>" ]
|
authors = [ "Fermyon Engineering <engineering@fermyon.com>" ]
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
# Spin architecture and internals
|
||||||
|
|
||||||
|
This document aims to offer an overview to the implementation of Spin, as well
|
||||||
|
as explain how the code is structured and how all parts fit together. This
|
||||||
|
document is continuously evolving, and if you want even more detailed
|
||||||
|
information, make sure to review the code for a given part of Spin.
|
||||||
|
|
||||||
|
## How Spin runs an application
|
||||||
|
|
||||||
|
A Spin application is defined as a `spin.toml` file. It can either be run
|
||||||
|
directly by `spin up`, passing the manifest file (`--file spin.toml`), or it can
|
||||||
|
be pushed to the registry then referenced using its remote ID
|
||||||
|
(`spin bindle push` followed by `spin up --bindle <id>`).
|
||||||
|
|
||||||
|
Regardless of the application origin (local file or remote reference from the
|
||||||
|
registry), a Spin application is defined by
|
||||||
|
`spin_config::Configuration<CoreComponent>` (contained in the
|
||||||
|
[`spin-config`](../crates/config) crate), which is the canonical representation
|
||||||
|
of a Spin application.
|
||||||
|
|
||||||
|
The crate responsible for transforming a custom configuration into a canonical
|
||||||
|
Spin application is [`spin-loader`](../crates/loader), which implements loading
|
||||||
|
applications from local `spin.toml` files and from remote Bindle references (and
|
||||||
|
ensures files referenced in the application configuration are copied and mounted
|
||||||
|
at the location expected in the WebAssmebly module). Once the canonical
|
||||||
|
representation is loaded from an application source, it is passed to a trigger —
|
||||||
|
currently, the only trigger implemented is the HTTP trigger, and we will use it
|
||||||
|
as an example throughout this document.
|
||||||
|
|
||||||
|
The HTTP trigger (defined in the [`spin-http`](../crates/http) crate) takes an
|
||||||
|
application configuration ([#40](https://github.com/fermyon/spin/issues/40)
|
||||||
|
explores a trigger handling multiple applications), starts an HTTP listener, and
|
||||||
|
for each new request, it routes it to the component configured in the
|
||||||
|
application configuration. Then, it instantiates the WebAssembly module (using a
|
||||||
|
`spin_engine::ExecutionContext`) and uses the appropriate executor (either the
|
||||||
|
[`SpinHttpExecutor`](../crates/http/src/spin.rs) or the
|
||||||
|
[`WagiHttpExecutor`](../crates/http/src/wagi.rs), based on the component
|
||||||
|
configuration) to handle the request and return the response.
|
||||||
|
|
||||||
|
## The Spin execution context
|
||||||
|
|
||||||
|
The Spin execution context (or "Spin engine") is the part of Spin that executes
|
||||||
|
WebAssembly components using the
|
||||||
|
[Wasmtime](https://github.com/bytecodealliance/wasmtime) WebAssembly runtime. It
|
||||||
|
is implemented in the [`spin-engine`](../crates/engine/) crate, and serves as
|
||||||
|
the part of Spin that takes a fully formed application configuration and creates
|
||||||
|
Wasm instances based on the component configurations.
|
||||||
|
|
||||||
|
There are two important concepts in this crate:
|
||||||
|
|
||||||
|
- `spin_engine::Builder` — the builder for creating an execution context. It is
|
||||||
|
created using an `ExecutionContextConfiguration` object (which contains a Spin
|
||||||
|
application and Wasmtime configuration), and implements the logic for
|
||||||
|
configuring WASI and the other host implementations provided by Spin. The
|
||||||
|
builder exposes the Wasmtime
|
||||||
|
[`Linker`](https://docs.rs/wasmtime/latest/wasmtime/struct.Linker.html),
|
||||||
|
[`Engine`](https://docs.rs/wasmtime/latest/wasmtime/struct.Engine.html), and
|
||||||
|
[`Store<RuntimeContext<T>>`](https://docs.rs/wasmtime/latest/wasmtime/struct.Store.html)
|
||||||
|
(where `RuntimeContext<T>` is the internal Spin context, which is detailed
|
||||||
|
later in the document), and it uses them to [pre-instantiate]()
|
||||||
|
|
||||||
|
- `spin_engine::ExecutionContext` — the main execution engine in Spin.
|
|
@ -1,144 +1,119 @@
|
||||||
# Configuration for Spin applications
|
# Configuration for Spin applications
|
||||||
|
|
||||||
A _Spin application_ is a collection of at least one _component_, each
|
Spin applications are comprised of general information, and a collection of at
|
||||||
instantiated as a result of an _event_ generated by a _trigger_.
|
least one _component_. In the example below we can see a simple HTTP application
|
||||||
|
with a single component executed when the `/hello` endpoint is accessed:
|
||||||
In the example below we can see a simple application with a single component,
|
|
||||||
executed when the `/hello` endpoint is accessed:
|
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
name = "spin-hello-world"
|
apiVersion = "0.1.0"
|
||||||
version = "1.0.0"
|
name = "spin-hello-world"
|
||||||
description = "A simple application that returns hello and goodbye."
|
description = "A simple application that returns hello world."
|
||||||
authors = [ "Radu Matei <radu@fermyon.com>" ]
|
trigger = { type = "http", base = "/" }
|
||||||
trigger = {type = "http", base = "/" }
|
version = "1.0.0"
|
||||||
|
|
||||||
[[component]]
|
[[component]]
|
||||||
source = "target/wasm32-wasi/release/spinhelloworld.wasm"
|
id = "hello"
|
||||||
id = "hello"
|
source = "target/wasm32-wasi/release/spinhelloworld.wasm"
|
||||||
[component.trigger]
|
[component.trigger]
|
||||||
route = "/hello"
|
route = "/hello"
|
||||||
```
|
```
|
||||||
|
|
||||||
All components of an application must be executed by the same trigger type.
|
## Application configuration
|
||||||
|
|
||||||
## The `spin.toml` configuration file
|
The following are the fields supported by the `spin.toml` configuration file:
|
||||||
|
|
||||||
Currently, the only configuration file for a Spin application is the `spin.toml`
|
|
||||||
file. This might change in the future (it could potentially be generated from
|
|
||||||
multiple configuration sources), as this file currently mixes build- and
|
|
||||||
run-time concerns.
|
|
||||||
|
|
||||||
These are the fields currently supported for the configuration:
|
|
||||||
|
|
||||||
|
- `apiVersion` (REQUIRED): Spin API version. Currently, this value MUST be
|
||||||
|
`"0.1.0"`.
|
||||||
- `name` (REQUIRED): Name of the application.
|
- `name` (REQUIRED): Name of the application.
|
||||||
- `version` (REQUIRED): Version of the application.
|
- `version` (REQUIRED): Version of the application.
|
||||||
- `description` (OPTIONAL): Description of the application.
|
- `description` (OPTIONAL): Description of the application.
|
||||||
- `authors` (OPTIONAL): Authors of the application.
|
- `authors` (OPTIONAL): List with the authors of the application.
|
||||||
- `namespace` (OPTIONAL): Logical grouping of the application at runtime.
|
- `trigger` (REQUIRED): Trigger for the application. Currently, all components
|
||||||
- `component` (REQUIRED): List with the components of the application.
|
of the application must be invoked as a result of the same trigger type.
|
||||||
- `trigger` (REQUIRED): Application trigger and configuration. (Currently, the
|
Currently, the only implemented application trigger is `http`, with the
|
||||||
only implemented trigger is `http`, and the application base path can be
|
following configuration fields:
|
||||||
configured (`base`), and will be prepended to the routes individual components
|
- `type` (REQUIRED): The application trigger type with the value `"http"`.
|
||||||
are handling. For example, if `base = "/foo"`, and a component
|
- `base` (REQUIRED): The base path for the HTTP application which will be
|
||||||
`route = "/bar/..."`, that component will handle incoming requests for
|
prepended to the routes of all components. (For example, if `base = "/foo"`
|
||||||
`/foo/bar/...`.)
|
and a component has `route = "/bar"`, the component will be invoked for
|
||||||
|
requests on `/foo/bar`.)
|
||||||
|
- a list of `component` objects (REQUIRED) defining the application components.
|
||||||
|
|
||||||
|
## Component configuration
|
||||||
|
|
||||||
Each `component` object has the following fields:
|
Each `component` object has the following fields:
|
||||||
|
|
||||||
- `id` (REQUIRED): ID of the component, used at runtime to select between
|
- `id` (REQUIRED): unique (per application) ID of the component, used at runtime
|
||||||
multiple components of the same application.
|
to select between multiple components of the same application.
|
||||||
- `source` (REQUIRED): Source for the component. Can either be a path to a local
|
- `source` (REQUIRED): Source for the WebAssembly module of the component. This
|
||||||
file, or a pair of `reference` (REQUIRED) and `parcel` (REQUIRED) fields
|
field can be _one_ the following:
|
||||||
pointing to a remote bindle.
|
- a string with the path to a local file containing the WebAssembly module for
|
||||||
- `environment` (OPTIONAL): Environment variables to be mapped inside the Wasm
|
the component OR
|
||||||
module at runtime.
|
- a pair of `reference` (REQUIRED) and `parcel` (REQUIRED) fields pointing to
|
||||||
- `files` (OPTIONAL): Paths (relative to the configuration file) of files to be
|
a remote bindle package (Note that this is currently not implemented, see
|
||||||
mapped inside the Wasm module at runtime.
|
[#135](https://github.com/fermyon/spin/issues/135)).
|
||||||
|
- `environment` (OPTIONAL): Environment variables to be made available inside
|
||||||
|
the WebAssembly module at runtime.
|
||||||
|
- `files` (OPTIONAL): Files to be made available inside the WebAssembly module
|
||||||
|
at runtime. This is a list, each element of which is either:
|
||||||
|
- a file path or glob relative to the `spin.toml` file (for example
|
||||||
|
`file.txt`, or `content/static/**/*`) OR
|
||||||
|
- a mapping of a `source` (REQUIRED), a directory relative to `spin.toml` and
|
||||||
|
`destination` (REQUIRED), the absolute mount path to be mapped inside the
|
||||||
|
WebAssembly module. For example
|
||||||
|
`{ source = "/content/", destination = "/"}`.
|
||||||
- `allowed_http_hosts` (OPTIONAL): List of HTTP hosts the component is allowed
|
- `allowed_http_hosts` (OPTIONAL): List of HTTP hosts the component is allowed
|
||||||
to connect to.
|
to make HTTP requests to (using the
|
||||||
- `trigger` (REQUIRED): Trigger configuration for the component.
|
[WASI experimental HTTP library](https://github.com/deislabs/wasi-experimental-http))
|
||||||
- `dependencies` (OPTIONAL): List of dependencies to be resolved and satisfied
|
- `trigger` (REQUIRED): Trigger configuration for the component. Triggers are
|
||||||
at runtime by the host.
|
the components that generate events that cause the execution of components.
|
||||||
- `build` (OPTIONAL): Currently unused build information or configuration that
|
Since the only implemented Spin trigger is HTTP, the component trigger
|
||||||
could be used by a plugin to build the component.
|
configuration currently contains HTTP component trigger configuration, which
|
||||||
|
has the following fields:
|
||||||
### Component sources
|
- `route` (REQUIRED): The HTTP route the component will be invoked for. It can
|
||||||
|
either be an exact route (for example `/foo/test`), or it can contain a
|
||||||
When writing a `spin.toml` file, components can either come from a local file,
|
wildcard (`/foo/test/...`) as the last path segment, which means the
|
||||||
or be they can reference a remote bindle.
|
component will be invoked for every request starting with the `/foo/test`
|
||||||
|
prefix (for example `/foo/test/abc/def`).
|
||||||
As such, the `source` field in the component configuration can either directly
|
- `executor` (REQUIRED): The executor for the HTTP component. There are
|
||||||
point to the path:
|
currently two executor `type`s:
|
||||||
|
- `spin` (DEFAULT): the Spin HTTP executor, which uses
|
||||||
```toml
|
[the WebAssembly component model](https://github.com/WebAssembly/component-model)
|
||||||
source = "path/to/wasm/file.wasm"
|
OR
|
||||||
```
|
- `wagi`: the Wagi CGI executor, which can be used to write components in
|
||||||
|
any language that compiles to WASI. The Wagi executor has the following
|
||||||
Or it can be an object containing the bindle reference and parcel:
|
optional fields:
|
||||||
|
- `argv` (OPTIONAL): The string representation of the `argv` list that
|
||||||
```toml
|
should be passed into the handler. `${SCRIPT_NAME}` will be replaced
|
||||||
[component.source]
|
with the script name, and `${ARGS}` will be replaced with the query
|
||||||
reference = "bindle reference"
|
parameters of the request, formatted as arguments. The default is to
|
||||||
parcel = "parcel"
|
follow the CGI specification, and pass `${SCRIPT_NAME} ${ARGS}`
|
||||||
```
|
- `entrypoint` (OPTIONAL): The name of the function that should be called
|
||||||
|
as the entrypoint to this handler. By default, it is `_start` (which in
|
||||||
### Triggers
|
most languages translates to calling `main` in the guest module).
|
||||||
|
|
||||||
Triggers in Spin are components that generate events that cause the execution of
|
|
||||||
components. Currently, the only trigger implemented for Spin is the HTTP
|
|
||||||
trigger, which contains the following fields:
|
|
||||||
|
|
||||||
- `route` (REQUIRED): The HTTP route the component will be invoked for.
|
|
||||||
- `executor` (REQUIRED): The object that sets an executor. There are currently two executor `type`s:
|
|
||||||
- `spin` uses the Spin HTTP executor
|
|
||||||
- `wagi` uses the Wagi CGI executor
|
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
- Spin HTTP component that contains the files in `static/` mapped to `/`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
[[component]]
|
||||||
|
source = "modules/spin_static_fs.wasm"
|
||||||
|
id = "fileserver"
|
||||||
|
files = [ { source = "static/", destination = "/" } ]
|
||||||
[component.trigger]
|
[component.trigger]
|
||||||
route = "/hello"
|
route = "/static/..."
|
||||||
executor = { type = "spin" }
|
|
||||||
# executor = { type="wagi" }
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Wagi Executor
|
- a Wagi component that contains file mounts and sets the module `argv` and
|
||||||
|
invokes a custom export function as the entrypoint:
|
||||||
Some executors have additional configuration. Wagi supports the following extra configurations:
|
|
||||||
|
|
||||||
- `argv` (OPTIONAL): The string representation of the `argv` list that should be passed into the handler. `${SCRIPT_NAME}` will be replaced with the script name, and `${ARGS}` will be replaced with the query parameters of the request, formatted as arguments. The default is to follow the CGI specification, and pass `${SCRIPT_NAME} ${ARGS}`
|
|
||||||
- `entrypoint` (OPTIONAL, EXPERT): The name of the function that should be called as the entrypoint to this handler. By default, it is `_start` (which in most languages translates to calling `main` in the guest module).
|
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
[[component]]
|
||||||
|
source = "modules/env_wagi.wasm"
|
||||||
|
id = "env"
|
||||||
|
files = [ "content/**/*" , "templates/*", "scripts/*", "config/*"]
|
||||||
[component.trigger]
|
[component.trigger]
|
||||||
route = "/..."
|
route = "/..."
|
||||||
executor = {type="wagi", argv="test ${SCRIPT_NAME} ${ARGS} done", entrypoint="_start"}
|
executor = { type="wagi", argv="test ${SCRIPT_NAME} ${ARGS} done", entrypoint = "some-other-export-function" }
|
||||||
```
|
```
|
||||||
|
|
||||||
### Dependencies
|
|
||||||
|
|
||||||
Each entry in the `dependencies` table should correspond to exactly one import
|
|
||||||
module from the Wasm module. Currently, this map should either contain an
|
|
||||||
interface that should be satisfied by the host runtime (through a host
|
|
||||||
implementation), or an exact reference (_not_ a version range or constraint) to
|
|
||||||
a component from the registry. The fields in a dependency section are:
|
|
||||||
|
|
||||||
- `type` (REQUIRED): The type of the dependency. Possible values: `host` or
|
|
||||||
`component`.
|
|
||||||
- `reference` (OPTIONAL): Reference to a component from the registry. Required
|
|
||||||
if `type` is `component`.
|
|
||||||
- `parcel` (OPTIONAL): Parcel to use from the bindle reference. Required if
|
|
||||||
`type` is `component`.
|
|
||||||
|
|
||||||
## Glossary
|
|
||||||
|
|
||||||
- WebAssembly module (or "module") — compilation artifact targeting
|
|
||||||
`wasm32-wasi` that adheres to
|
|
||||||
[the Wasm specification](https://webassembly.org/specs/).
|
|
||||||
|
|
||||||
- WebAssembly component (or "component") — compilation artifact targeting
|
|
||||||
`wasm32-wasi` that adheres to
|
|
||||||
[the WebAssembly component model](https://github.com/WebAssembly/component-model/blob/main/design/high-level/Goals.md),
|
|
||||||
and whose imports and exports use
|
|
||||||
[interface types](https://github.com/WebAssembly/interface-types)
|
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
# Contributing to Spin
|
||||||
|
|
||||||
|
We are delighted that you are interested in making Spin better! Thank you! This
|
||||||
|
document will guide you in making your first contribution to the project.
|
||||||
|
|
||||||
|
First, any contribution and interaction on any Fermyon project MUST follow our
|
||||||
|
[code of conduct](https://www.fermyon.com/code-of-conduct). Thank you for being
|
||||||
|
part of an inclusive and open community!
|
||||||
|
|
||||||
|
We welcome and appreciate contributions of all types — opening issues, fixing
|
||||||
|
typos, adding examples, one-liner code fixes, tests, or complete features.
|
||||||
|
|
||||||
|
If you plan on contributing anything complex, please go through the issue and PR
|
||||||
|
queues first to make sure someone else has not started working on it. If it
|
||||||
|
doesn't exist already, please open an issue so you have a change to get feedback
|
||||||
|
from the community and the maintainers before you start working on your feature.
|
||||||
|
|
||||||
|
## Making code contributions to Spin
|
||||||
|
|
||||||
|
The following guide is intended to make sure your contribution can get merged as
|
||||||
|
soon as possible. First, make sure you have the following prerequisites
|
||||||
|
configured:
|
||||||
|
|
||||||
|
- [Rust](https://www.rust-lang.org/) at
|
||||||
|
[1.56+](https://www.rust-lang.org/tools/install) with the `wasm32-wasi` and
|
||||||
|
`wasm32-unknown-unknown` targets configured
|
||||||
|
(`rustup target add wasm32-wasi && rustup target add wasm32-unknown-unknown`)
|
||||||
|
- [`rustfmt`](https://github.com/rust-lang/rustfmt) and
|
||||||
|
[`clippy`](https://github.com/rust-lang/rust-clippy) configured for your Rust
|
||||||
|
installation
|
||||||
|
- `make`
|
||||||
|
- [Bindle server v0.8.0](https://github.com/deislabs/bindle/releases/tag/v0.8.0)
|
||||||
|
in your system path.
|
||||||
|
- if you are a VS Code user, we recommend the
|
||||||
|
[`rust-analyzer`](https://rust-analyzer.github.io/) and
|
||||||
|
[`autobindle`](https://github.com/fermyon/autobindle) extensions.
|
||||||
|
- please ensure you
|
||||||
|
[configure adding a GPG signature to your commits](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification)
|
||||||
|
as well as appending a sign-off message (`git commit -S -s`)
|
||||||
|
|
||||||
|
Once you have set up the prerequisites and identified the contribution you want
|
||||||
|
to make to Spin, make sure you can correctly build the project:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# clone the repository
|
||||||
|
$ git clone https://github.com/fermyon/spin && cd spin
|
||||||
|
# add a new remote pointing to your fork of the project
|
||||||
|
$ git remote add fork https://github.com/<your-username>/spin
|
||||||
|
# create a new branch for your work
|
||||||
|
$ git checkout -b <your-branch>
|
||||||
|
|
||||||
|
# if you are making a documentation contribution,
|
||||||
|
# you can skip compiling and running the tests.
|
||||||
|
|
||||||
|
# build a release version of the Spin CLI
|
||||||
|
$ cargo build --release
|
||||||
|
# make sure compilation is successful
|
||||||
|
$ ./target/release/spin --help
|
||||||
|
|
||||||
|
# run the tests and make sure they pass
|
||||||
|
$ make test
|
||||||
|
```
|
||||||
|
|
||||||
|
Now you should be ready to start making your contribution. To familiarize
|
||||||
|
yourself with the Spin project, please read the
|
||||||
|
[architecture document](./architecture.md). Since most of Spin is implemented in
|
||||||
|
Rust, we try to follow the common Rust coding conventions (keep an eye on the
|
||||||
|
recommendations from Clippy!) If applicable, add units or integration tests to
|
||||||
|
ensure your contribution is correct.
|
||||||
|
|
||||||
|
Build the project and run the tests (`make build test`), and if everything is
|
||||||
|
successful, you should be ready to commit your changes. We try to follow the
|
||||||
|
[Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
|
||||||
|
guidelines for writing commit messages:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ git commit -S -s -m "<your commit message that follows https://www.conventionalcommits.org/en/v1.0.0/>"
|
||||||
|
```
|
||||||
|
|
||||||
|
We try to only keep useful changes as separate commits — if you prefer to commit
|
||||||
|
often, please
|
||||||
|
[cleanup the commit history](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History)
|
||||||
|
before opening a pull request. Once you are happy with your changes you can push
|
||||||
|
the branch to your fork:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# "fork" is the name of the git remote pointing to your fork
|
||||||
|
$ git push fork
|
||||||
|
```
|
||||||
|
|
||||||
|
Now you are ready to create a pull request. Thank you for your contribution!
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Index
|
||||||
|
|
||||||
|
1. [Introduction](./intro.md)
|
||||||
|
1. [Quickstart](./quickstart.md)
|
||||||
|
1. [Configuration for Spin applications](./configuration.md)
|
||||||
|
1. [Writing HTTP applications with Spin](./writing-http-apps.md)
|
||||||
|
1. [Architecture](./architecture.md)
|
||||||
|
1. [Contributing to Spin](./contributing.md)
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Introducing Spin
|
||||||
|
|
||||||
|
Spin is an open source framework for building and running fast, secure, and
|
||||||
|
composable cloud microservices with WebAssembly. It aims to be the easiest way
|
||||||
|
to get started with WebAssembly microservices, and takes advantage of the latest
|
||||||
|
developments in the
|
||||||
|
[WebAssembly component model](https://github.com/WebAssembly/component-model)
|
||||||
|
and [Wasmtime](https://wasmtime.dev/) runtime.
|
||||||
|
|
||||||
|
Spin offers a simple CLI that helps you create, distribute, and execute
|
||||||
|
applications, and in the next sections we will learn more about Spin
|
||||||
|
applications and how to get started.
|
||||||
|
|
||||||
|
## Spin applications
|
||||||
|
|
||||||
|
Spin applications are comprised of one or more _components_, and follow the
|
||||||
|
event-driven model — they are executed as the result of events being generated
|
||||||
|
by _triggers_ (for example an HTTP server receiving requests, or a queue
|
||||||
|
subscription receiving messages). On each new event, _the entrypoint_ of a
|
||||||
|
component is executed by Spin. The entrypoints to components are _functions_.
|
||||||
|
This, together with the fact that they are invoked in response to events, brings
|
||||||
|
the Spin application model closer to the Function-as-a-Service model.
|
||||||
|
|
||||||
|
In the next section, we will [take Spin for a spin](./quickstart.md).
|
|
@ -0,0 +1,163 @@
|
||||||
|
# Taking Spin for a spin
|
||||||
|
|
||||||
|
## Getting the `spin` binary
|
||||||
|
|
||||||
|
You can download the [latest release](https://github.com/fermyon/spin/releases).
|
||||||
|
For example, for an M1 macOS machine:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ wget https://github.com/fermyon/spin/releases/download/canary/spin-canary-macos-aarch64.tar.gz
|
||||||
|
$ tar xfv spin-canary-macos-aarch64.tar.gz
|
||||||
|
$ ./spin --help
|
||||||
|
```
|
||||||
|
|
||||||
|
> On an M1 macOS machine you might need to install / configure OpenSSL@1.1 by
|
||||||
|
> running
|
||||||
|
> `brew install openssl@1.1 && sudo ln -s /opt/homebrew/Cellar/openssl@1.1/1.1.1m /usr/local/openssl-aarch64`
|
||||||
|
|
||||||
|
Alternatively, if you want to build Spin from source,
|
||||||
|
[follow the contribution guide](./contributing.md) for a detailed guide on
|
||||||
|
getting started:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ git clone https://github.com/fermyon/spin
|
||||||
|
$ cd spin && cargo build --release
|
||||||
|
$ ./target/release/spin --help
|
||||||
|
```
|
||||||
|
|
||||||
|
At this point, move the `spin` binary somewhere in your path, so it can be
|
||||||
|
accessed from any directory.
|
||||||
|
|
||||||
|
## Creating a new Spin HTTP application in Rust
|
||||||
|
|
||||||
|
First, we need to add the official Spin templates from the repository:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ spin templates add --git https://github.com/fermyon/spin --name fermyon
|
||||||
|
$ spin templates list
|
||||||
|
+-----------------------------------------------------------------------------------+
|
||||||
|
| Name Repository URL Branch |
|
||||||
|
+===================================================================================+
|
||||||
|
| spin-http fermyon https://github.com/fermyon/bartholomew refs/heads/main |
|
||||||
|
+-----------------------------------------------------------------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we can create a new application from the template:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ spin new --repo fermyon --template spin-http --path spin-hello-world
|
||||||
|
$ cd spin-hello-world
|
||||||
|
```
|
||||||
|
|
||||||
|
This generated all we need to build and run our very first Spin application.
|
||||||
|
Let's have a look at `spin.toml`:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
apiVersion = "0.1.0"
|
||||||
|
name = "spin-hello-world"
|
||||||
|
description = "A simple application that returns hello world."
|
||||||
|
trigger = { type = "http", base = "/" }
|
||||||
|
version = "1.0.0"
|
||||||
|
|
||||||
|
[[component]]
|
||||||
|
id = "hello"
|
||||||
|
source = "target/wasm32-wasi/release/spinhelloworld.wasm"
|
||||||
|
[component.trigger]
|
||||||
|
route = "/hello"
|
||||||
|
```
|
||||||
|
|
||||||
|
Since this is an HTTP application, the application trigger is of `type = http`,
|
||||||
|
and there is one component that responds to requests on route `/hello` using the
|
||||||
|
`spinhelloworld.wasm` WebAssembly module. (See the
|
||||||
|
[configuration document](./configuration.md) for a detailed guide on the Spin
|
||||||
|
application configuration.)
|
||||||
|
|
||||||
|
Now let's have a look at the `hello` component — below is the complete source
|
||||||
|
code for a Spin HTTP component written in Rust. It is a regular Rust function
|
||||||
|
that takes an HTTP request and returns an HTTP response, annotated with the
|
||||||
|
`http_component` macro:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use anyhow::Result;
|
||||||
|
use spin_sdk::{
|
||||||
|
http::{Request, Response},
|
||||||
|
http_component,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A simple Spin HTTP component.
|
||||||
|
#[http_component]
|
||||||
|
fn hello_world(req: Request) -> Result<Response> {
|
||||||
|
println!("{:?}", req.headers());
|
||||||
|
Ok(http::Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.header("foo", "bar")
|
||||||
|
.body(Some("Hello, Fermyon!".into()))?)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> See
|
||||||
|
> [the section on building HTTP applications with Spin for a detailed guide](./writing-http-apps.md).
|
||||||
|
|
||||||
|
We can build this component using the regular Rust toolchain, targeting
|
||||||
|
`wasm32-wasi`, which will produce the WebAssembly module referenced in
|
||||||
|
`spin.toml`:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cargo build --target wasm32-wasi --release
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running the application with `spin up`
|
||||||
|
|
||||||
|
Now that we configured the application and built our component, we can _spin up_
|
||||||
|
the application (pun intended):
|
||||||
|
|
||||||
|
```shell
|
||||||
|
# optionally, use RUST_LOG=spin=trace to see detailed logs
|
||||||
|
$ spin up --file spin.toml
|
||||||
|
INFO spin_http_engine: Serving HTTP on address 127.0.0.1:3000
|
||||||
|
```
|
||||||
|
|
||||||
|
Spin will instantiate all components from the application configuration, and
|
||||||
|
will crate the router configuration for the HTTP trigger accordingly. The
|
||||||
|
component can now be invoked by making requests to `http://localhost:3000/hello`
|
||||||
|
(see route field in the configuration):
|
||||||
|
|
||||||
|
```
|
||||||
|
$ curl -i localhost:3000/hello
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
foo: bar
|
||||||
|
content-length: 15
|
||||||
|
|
||||||
|
Hello, Fermyon!
|
||||||
|
```
|
||||||
|
|
||||||
|
You can add as many components as needed in `spin.toml`, mount files and
|
||||||
|
directories, allow granular outbound HTTP connections, or environment variables.
|
||||||
|
(see the [configuration document](./configuration.md) for a detailed guide on
|
||||||
|
the Spin application configuration) and iterate locally with
|
||||||
|
`spin up --file spin.toml` until you are ready to distribute the application.
|
||||||
|
|
||||||
|
## Distributing the application
|
||||||
|
|
||||||
|
First, we need to start the registry. You can
|
||||||
|
[install the latest Bindle release](https://github.com/deislabs/bindle/tree/main/docs#from-the-binary-releases),
|
||||||
|
or use the
|
||||||
|
[`autobindle`](https://marketplace.visualstudio.com/items?itemName=fermyon.autobindle)
|
||||||
|
VS Code extension, which automatically downloads and starts Bindle on
|
||||||
|
`http://localhost:8080/v1`. Now we can package the entire application, the
|
||||||
|
components, and all the referenced files and publishes them to the registry:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ export BINDLE_URL=http://localhost:8080/v1
|
||||||
|
$ spin bindle push --file spin.toml
|
||||||
|
pushed: spin-hello-world/1.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we can run the application using `spin up` directly from the registry:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ spin up --bindle spin-hello-world/1.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Congratulations! You just completed writing, building, publishing, and running
|
||||||
|
your first Spin application.
|
|
@ -1,17 +1,26 @@
|
||||||
# Cutting a Spin Release
|
# Creating a new Spin release
|
||||||
|
|
||||||
To cut a release of Spin, you will need to do the following:
|
To cut a release of Spin, you will need to do the following:
|
||||||
|
|
||||||
1. Create a pull request that changes the version number for your new version (e.g. 0.1.0 becomes 0.1.1)
|
1. Create a pull request that changes the version number for your new version
|
||||||
- `Cargo.toml` is the most important place to make this change
|
(e.g. 0.1.0 becomes 0.1.1)
|
||||||
- Check the docs for hard-coded version strings
|
- `Cargo.toml` is the most important place to make this change
|
||||||
1. Merge the PR created in #1 (Such PRs are still required to get approvals, so make sure you get signoff on the PR)
|
- Check the docs for hard-coded version strings
|
||||||
1. Before proceeding, verify that the merge commit on `main` intended to be tagged is green, i.e. CI is successful
|
1. Merge the PR created in #1 (Such PRs are still required to get approvals, so
|
||||||
|
make sure you get signoff on the PR)
|
||||||
|
1. Before proceeding, verify that the merge commit on `main` intended to be
|
||||||
|
tagged is green, i.e. CI is successful
|
||||||
1. Create a new tag with a `v` and then the version number (`v0.1.1`)
|
1. Create a new tag with a `v` and then the version number (`v0.1.1`)
|
||||||
1. Push the tag up to `main` on GitHub
|
1. Push the tag up to `main` on GitHub
|
||||||
- This will trigger a release build
|
- This will trigger a release build
|
||||||
1. Wait for the `release` [action](https://github.com/fermyon/spin/actions/workflows/release.yaml) to complete, and download the binary artifacts that are generated by that action.
|
1. Wait for the `release`
|
||||||
1. Generate SHAs of the Windows, Mac (`amd64` and `aarch64`), and Linux (`amd64` and `aarch64`) binaries with `shasum -a 256` or a similar command
|
[action](https://github.com/fermyon/spin/actions/workflows/release.yaml) to
|
||||||
1. Go to the GitHub [tags page](https://github.com/fermyon/spin/releases) and create a release, adding release notes, and uploading the binaries you downloaded above. The SHAs should go in the release notes.
|
complete, and download the binary artifacts that are generated by that
|
||||||
|
action.
|
||||||
|
1. Generate SHAs of the Windows, Mac (`amd64` and `aarch64`), and Linux (`amd64`
|
||||||
|
and `aarch64`) binaries with `shasum -a 256` or a similar command
|
||||||
|
1. Go to the GitHub [tags page](https://github.com/fermyon/spin/releases) and
|
||||||
|
create a release, adding release notes, and uploading the binaries you
|
||||||
|
downloaded above. The SHAs should go in the release notes.
|
||||||
|
|
||||||
At this point, you can just verify that all things are good.
|
At this point, you can verify in the GitHub UI that the release was successful.
|
||||||
|
|
|
@ -1,154 +1,184 @@
|
||||||
# Writing HTTP applications using Spin
|
# Building HTTP applications using Spin
|
||||||
|
|
||||||
// TODO
|
Currently, the only applications that can be built with Spin are web based, or
|
||||||
|
applications that are invoked as the result of an HTTP request, and which return
|
||||||
|
an HTTP response. This is because HTTP workloads appear to be the most important
|
||||||
|
for event-driven Functions-as-a-Service workloads, and we think initially serve
|
||||||
|
the most popular use cases.
|
||||||
|
|
||||||
Let's take the following Spin application. It sets a base path, `/test`, and
|
> The extensible nature of Spin allows anyone to extend it by building more
|
||||||
there are two components, each serving requests for `/test/hello/...` and
|
> triggers (see the [architecture](./architecture.md) and
|
||||||
`/test/wagi/...` respectively:
|
> [contributing](./contributing.md) documents), and we are experimenting with a
|
||||||
|
> new trigger that invokes components for new payloads on a Redis message queue
|
||||||
|
> (see [#59](https://github.com/fermyon/spin/issues/59)).
|
||||||
|
|
||||||
```toml
|
Spin is built on top of the
|
||||||
name = "spin-hello-world"
|
[WebAssembly component model](https://github.com/WebAssembly/component-model).
|
||||||
trigger = { type = "http", base = "/test" }
|
We _strongly_ believe it represents the future of WebAssembly, and that it will
|
||||||
|
enable scenarios that are simply not possible today (for example dynamic linking
|
||||||
|
and transitive dependencies). As a result, the Spin HTTP trigger (and executor)
|
||||||
|
is defined using [WebAssembly interfaces](../wit/ephemeral), and the
|
||||||
|
[SDK for building Rust components](../sdk/rust) is built on top of the Rust
|
||||||
|
implementation and bindings generator for WebAssembly components.
|
||||||
|
|
||||||
[[component]]
|
But the WebAssembly component model is currently in its early stages. This means
|
||||||
source = "spin-module-that-prints-requests.wasm"
|
only a few languages fully implement it. While language communities implement
|
||||||
id = "hello"
|
the component model, we want to allow developers to use
|
||||||
[component.trigger]
|
[any language that compiles to WASI](https://www.fermyon.com/wasm-languages/webassembly-language-support)
|
||||||
route = "/hello/..."
|
to build Spin HTTP applications. This is why we currently implement a Wagi
|
||||||
|
executor which supports [Wagi](https://github.com/deislabs/wagi)-based
|
||||||
|
components that expect the HTTP request using the module's standard input, and
|
||||||
|
return the HTTP response using the module's standard output, following
|
||||||
|
[the CGI specification](https://tools.ietf.org/html/rfc3875). As a programming
|
||||||
|
language adds support for the component model, we plan to enable better support
|
||||||
|
for it in Spin, and eventually only support Spin applications that implement the
|
||||||
|
WebAssembly component model.
|
||||||
|
|
||||||
[[component]]
|
## Building HTTP components in Rust
|
||||||
source = "env_wagi.wasm"
|
|
||||||
id = "wagi"
|
|
||||||
[component.trigger]
|
|
||||||
route = "/wagi/..."
|
|
||||||
executor = "wagi"
|
|
||||||
```
|
|
||||||
|
|
||||||
Let's see how the application configuration above gets turned into the headers
|
We believe the Rust SDK offers the best experience for building Spin HTTP
|
||||||
by starting the application on `localhost:3000`.
|
components, and this is the recommended way of writing Spin components in Rust.
|
||||||
|
|
||||||
First, let's send a request to the `hello` component.
|
Building such a component in Rust requires writing a function that takes an HTTP
|
||||||
|
`Request` and returns an HTTP `Response`, annotated with a special Spin
|
||||||
|
procedural macro. Below is a complete component implementation:
|
||||||
|
|
||||||
```js
|
```rust
|
||||||
➜ curl 'localhost:3000/test/hello/abc/def?foo=bar' -d "abc"
|
use anyhow::Result;
|
||||||
Request {
|
use spin_sdk::{
|
||||||
method: Method::Post,
|
http::{Request, Response},
|
||||||
uri: "/test/hello/abc/def",
|
http_component,
|
||||||
headers: [
|
};
|
||||||
(
|
|
||||||
"host",
|
/// A simple Spin HTTP component.
|
||||||
"localhost:3000",
|
#[http_component]
|
||||||
),
|
fn hello_world(req: Request) -> Result<Response> {
|
||||||
(
|
println!("{:?}", req.headers());
|
||||||
"user-agent",
|
Ok(http::Response::builder()
|
||||||
"curl/7.77.0",
|
.status(200)
|
||||||
),
|
.header("foo", "bar")
|
||||||
(
|
.body(Some("Hello, Fermyon!".into()))?)
|
||||||
"accept",
|
|
||||||
"*/*",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"content-length",
|
|
||||||
"3",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"content-type",
|
|
||||||
"application/x-www-form-urlencoded",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"PATH_INFO",
|
|
||||||
"/abc/def",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"X_FULL_URL",
|
|
||||||
"http://localhost:3000/test/hello/abc/def?foo=bar",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"X_MATCHED_ROUTE",
|
|
||||||
"/test/hello/...",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"X_BASE_PATH",
|
|
||||||
"/test",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"X_RAW_COMPONENT_ROUTE",
|
|
||||||
"/hello/...",
|
|
||||||
),
|
|
||||||
(
|
|
||||||
"X_COMPONENT_ROUTE",
|
|
||||||
"/hello",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
params: [
|
|
||||||
(
|
|
||||||
"foo",
|
|
||||||
"bar",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
body: Some(
|
|
||||||
[
|
|
||||||
97,
|
|
||||||
98,
|
|
||||||
99,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Available in the request object are the following fields:
|
The important things to note in the function above:
|
||||||
|
|
||||||
- `method` — the HTTP method of the request — in this case, GET
|
- the `spin_sdk::http_component` macro — this marks the function as the
|
||||||
- `uri` — the absolute path of the URI, _without_ the query parameters
|
entrypoint for the Spin component
|
||||||
- `params` — list of `(key, value)` pairs with the query parameters
|
- the function signature — `fn hello_world(req: Request) -> Result<Response>` —
|
||||||
- `headers` — list of `(key, value)` pairs with the headers (see the default
|
the Spin HTTP component uses the HTTP objects from the popular Rust crate
|
||||||
headers for a list of default headers and their meaning)
|
[`http`](https://crates.io/crates/http), and the request and response bodies
|
||||||
- body — optional byte array containing the request body
|
are optionally using [`bytes::Bytes`](https://crates.io/crates/bytes)
|
||||||
|
|
||||||
Now let's send a request to the Wagi component and inspect the environment
|
### Making outbound HTTP requests
|
||||||
variables:
|
|
||||||
|
|
||||||
```
|
This SDK includes the ability to send outbound HTTP requests using the
|
||||||
➜ curl 'localhost:3000/test/wagi/abc/def?foo=bar' -d "abc"
|
[DeisLabs WASI experimental HTTP library](https://github.com/deislabs/wasi-experimental-http).
|
||||||
### Arguments ###
|
Let's see an example where the component makes an outbound HTTP request to a
|
||||||
|
server, modifies the result, then returns it:
|
||||||
|
|
||||||
### Env Vars ###
|
```rust
|
||||||
QUERY_STRING = foo=bar
|
#[http_component]
|
||||||
REMOTE_HOST = 127.0.0.1
|
fn hello_world(_req: Request) -> Result<Response> {
|
||||||
AUTH_TYPE =
|
let mut res = spin_sdk::http::send(
|
||||||
X_FULL_URL = http://localhost:3000/test/wagi/abc/def?foo=bar
|
http::Request::builder()
|
||||||
PATH_TRANSLATED = /abc/def
|
.method("GET")
|
||||||
SERVER_PORT = 3000
|
.uri("https://fermyon.com")
|
||||||
X_MATCHED_ROUTE = /test/wagi/...
|
.body(None)?,
|
||||||
SERVER_PROTOCOL = HTTP/1.1
|
)?;
|
||||||
CONTENT_TYPE =
|
|
||||||
SERVER_SOFTWARE = WAGI/1
|
|
||||||
HTTP_HOST = localhost:3000
|
|
||||||
HTTP_ACCEPT = */*
|
|
||||||
REMOTE_ADDR = 127.0.0.1
|
|
||||||
X_RAW_COMPONENT_ROUTE = /wagi/...
|
|
||||||
CONTENT_LENGTH = 3
|
|
||||||
SERVER_NAME = localhost
|
|
||||||
GATEWAY_INTERFACE = CGI/1.1
|
|
||||||
HTTP_CONTENT_LENGTH = 3
|
|
||||||
HTTP_CONTENT_TYPE = application/x-www-form-urlencoded
|
|
||||||
X_BASE_PATH = /test
|
|
||||||
HTTP_USER_AGENT = curl/7.77.0
|
|
||||||
X_COMPONENT_ROUTE = /wagi
|
|
||||||
REMOTE_USER =
|
|
||||||
PATH_INFO = /abc/def
|
|
||||||
REQUEST_METHOD = POST
|
|
||||||
X_RAW_PATH_INFO = /abc/def
|
|
||||||
SCRIPT_NAME = /test/wagi
|
|
||||||
|
|
||||||
### STDIN ###
|
res.headers_mut()
|
||||||
abc%
|
.insert(http::header::SERVER, "spin/0.1.0".try_into()?);
|
||||||
|
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### The default headers
|
In order for the component above to be allowed to make the outbound HTTP
|
||||||
|
request, the destination host must be declared in the Spin application
|
||||||
|
configuration:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[[component]]
|
||||||
|
id = "hello"
|
||||||
|
source = "target/wasm32-wasi/release/spinhelloworld.wasm"
|
||||||
|
allowedHttpHosts = [ "https://fermyon.com" ]
|
||||||
|
[component.trigger]
|
||||||
|
route = "/hello"
|
||||||
|
```
|
||||||
|
|
||||||
|
Making a request to this component, we can see the appended header, and that the
|
||||||
|
response contains the expected body:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
$ curl -I localhost:3000/hello
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
content-length: 29350
|
||||||
|
content-type: text/html; charset=utf-8
|
||||||
|
server: spin/0.1.0 # the header added by our component
|
||||||
|
```
|
||||||
|
|
||||||
|
Any Rust crate that compiles to `wasm32-wasi` can be used as dependency in Rust
|
||||||
|
components.
|
||||||
|
|
||||||
|
As the Spin framework evolves, the Spin SDK will continue adding functionality
|
||||||
|
that improves the experience for building Spin components (such as implementing
|
||||||
|
interfaces for popular functionality such as
|
||||||
|
[object storage](https://github.com/fermyon/spin/issues/48),
|
||||||
|
[key/value stores](https://github.com/fermyon/spin/issues/47), or
|
||||||
|
[neural networks](https://github.com/fermyon/spin/issues/50)).
|
||||||
|
|
||||||
|
As more languages support the WebAssembly component model, our goal is to
|
||||||
|
develop language SDKs for such popular languages.
|
||||||
|
|
||||||
|
## Building HTTP components using the Wagi executor
|
||||||
|
|
||||||
|
You can use any language that compiles to WASI to build an HTTP component using
|
||||||
|
the [Wagi](https://github.com/deislabs/wagi) executor.
|
||||||
|
|
||||||
|
Wagi is a project that lets you write HTTP handlers using nothing but a
|
||||||
|
language's standard library, following
|
||||||
|
[the CGI specification](https://tools.ietf.org/html/rfc3875).
|
||||||
|
|
||||||
|
For example, here is a complete Wagi component written in Swift:
|
||||||
|
|
||||||
|
```swift
|
||||||
|
print("content-type: text/html; charset=UTF-8\n\n");
|
||||||
|
print("hello world\n");
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is another example, this time written in [Grain](https://grain-lang.org/),
|
||||||
|
a new programming language that natively targets WebAssembly:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import Process from "sys/process";
|
||||||
|
import Array from "array";
|
||||||
|
|
||||||
|
print("content-type: text/plain\n");
|
||||||
|
|
||||||
|
// This will print all the Wagi env variable
|
||||||
|
print("==== Environment: ====");
|
||||||
|
Array.forEach(print, Process.env());
|
||||||
|
|
||||||
|
// This will print the route path followed by each query
|
||||||
|
// param. So /foo?bar=baz will be ["/foo", "bar=baz"].
|
||||||
|
print("==== Args: ====");
|
||||||
|
Array.forEach(print, Process.argv());
|
||||||
|
```
|
||||||
|
|
||||||
|
> You can find examples on how to build Wagi applications in
|
||||||
|
> [the DeisLabs GitHub organization](https://github.com/deislabs?q=wagi&type=public&language=&sort=).
|
||||||
|
|
||||||
|
In short, read HTTP headers from environment variables and the HTTP body from
|
||||||
|
standard input, and return the response to standard output. You can follow the
|
||||||
|
[Wagi guide](https://github.com/deislabs/wagi/blob/main/docs/writing_modules.md)
|
||||||
|
on writing modules (note that a module declaring its subroutes will not be
|
||||||
|
implemented in Spin).
|
||||||
|
|
||||||
|
## The default headers set in Spin HTTP components
|
||||||
|
|
||||||
Spin sets a few default headers on the request based on the base path, component
|
Spin sets a few default headers on the request based on the base path, component
|
||||||
route, and request URI, which should always be available when writing a module:
|
route, and request URI, which will always be available when writing a module:
|
||||||
|
|
||||||
- `X_FULL_URL` - the full URL of the request —
|
- `X_FULL_URL` - the full URL of the request —
|
||||||
`http://localhost:3000/test/wagi/abc/def?foo=bar`
|
`http://localhost:3000/test/wagi/abc/def?foo=bar`
|
||||||
|
@ -167,5 +197,3 @@ route, and request URI, which should always be available when writing a module:
|
||||||
Besides the headers above, components that use the Wagi executor also have
|
Besides the headers above, components that use the Wagi executor also have
|
||||||
available
|
available
|
||||||
[all headers set by Wagi, following the CGI spec](https://github.com/deislabs/wagi/blob/main/docs/environment_variables.md).
|
[all headers set by Wagi, following the CGI spec](https://github.com/deislabs/wagi/blob/main/docs/environment_variables.md).
|
||||||
|
|
||||||
### The HTTP headers
|
|
||||||
|
|
180
readme.md
180
readme.md
|
@ -1,165 +1,45 @@
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<h1>Project Spin</h1>
|
<h1>Spin</h1>
|
||||||
<img src="./docs/images/spin.png" width="300"/>
|
<img src="./docs/images/spin.png" width="300"/>
|
||||||
<p>Spin is a tool that allows developers to build, publish, and deploy WebAssembly workloads. It is the next version of the Fermyon runtime.</p>
|
<p>Spin is a framework for building, deploying, and running fast, secure, and composable cloud microservices with WebAssembly.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## Take Spin for a spin
|
## What is Spin?
|
||||||
|
|
||||||
* [Take Spin for a spin](#take-spin-for-a-spin)
|
Spin is an open source framework for building and running fast, secure, and
|
||||||
* [Build Spin CLI](#build-spin-cli)
|
composable cloud microservices with WebAssembly. It aims to be the easiest way
|
||||||
* [Build and Run an HTTP Application with Spin](#build-and-run-an-http-application-with-spin)
|
to get started with WebAssembly microservices, and takes advantage of the latest
|
||||||
* [Generate an HTTP Application Using a Spin Template](#generate-an-http-application-using-a-spin-template)
|
developments in the
|
||||||
* [Build the Application](#build-the-application)
|
[WebAssembly component model](https://github.com/WebAssembly/component-model)
|
||||||
* [Run the Application Locally](#run-the-application-locally)
|
and [Wasmtime](https://wasmtime.dev/) runtime.
|
||||||
* [Publishing Interfaces](#publishing-interfaces)
|
|
||||||
* [Publish the Spin HTTP Interface](#publish-the-spin-http-interface)
|
|
||||||
* [Use Interface in HTTP Application](#use-interface-in-http-application)
|
|
||||||
|
|
||||||
## Build Spin CLI
|
Spin offers a simple CLI that helps you create, distribute, and execute
|
||||||
|
applications, and in the next sections we will learn more about Spin
|
||||||
|
applications and how to get started.
|
||||||
|
|
||||||
Clone this repository and build the Spin CLI:
|
## Getting started
|
||||||
|
|
||||||
```shell
|
See the [quickstart document](./docs/quickstart.md) for a detailed guide on
|
||||||
$ git clone https://github.com/fermyon/spin
|
configuring Spin and writing your first Spin application, but in short:
|
||||||
$ cd spin && cargo build --release
|
|
||||||
|
```
|
||||||
|
$ wget https://github.com/fermyon/spin/releases/download/canary/spin-canary-<os-arch>.tar.gz
|
||||||
|
$ tar xfv spin-canary-<os-arch>.tar.gz
|
||||||
|
$ ./spin --help
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build and Run an HTTP Application with Spin
|
After you follow the [quickstart document](./docs/quickstart.md), you can follow
|
||||||
|
the [guide on writing HTTP applications with Spin](./docs/writing-http-apps.md)
|
||||||
|
and the [guide on configuring Spin applications](./docs/configuration.md).
|
||||||
|
|
||||||
### Generate an HTTP Application Using a Spin Template
|
After you built your application, run it using Spin, pointing to the Spin
|
||||||
|
application configuration file:
|
||||||
|
|
||||||
Add a new Spin template based on the `templates/spin-http` directory from this
|
```
|
||||||
repo:
|
$ spin up --file spin.toml
|
||||||
|
|
||||||
```shell
|
|
||||||
$ spin templates add --local templates/spin-http --name spin-http
|
|
||||||
$ spin templates list
|
|
||||||
+---------------------------------------+
|
|
||||||
| Name Repository URL Branch |
|
|
||||||
+=======================================+
|
|
||||||
| spin-http local |
|
|
||||||
+---------------------------------------+
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Create the application:
|
## Contributing
|
||||||
|
|
||||||
```shell
|
We are delighted that you are interested in making Spin better! Thank you!
|
||||||
$ mkdir helloworld
|
Please follow the [contributing guide](./docs/contributing.md).
|
||||||
# TODO: the name and path where the app is generated is wrong.
|
|
||||||
$ spin new --repo local --template spin-http --path .
|
|
||||||
```
|
|
||||||
|
|
||||||
### Build the Application
|
|
||||||
|
|
||||||
In the application directory:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ cargo build --release
|
|
||||||
```
|
|
||||||
|
|
||||||
### Run the Application Locally
|
|
||||||
|
|
||||||
The configuration file `spin.toml` contains the information required for Spin to
|
|
||||||
run the application locally:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ export RUST_LOG=spin_engine=info,spin_http,wact=info
|
|
||||||
$ spin up --app spin.toml
|
|
||||||
|
|
||||||
2022-02-06T02:44:08.810806Z INFO spin_http_engine: Processing request for application spin-hello-world on path /hello
|
|
||||||
2022-02-06T02:44:08.810897Z INFO execute{component="hello"}: spin_http_engine: Executing request for component hello
|
|
||||||
2022-02-06T02:44:08.810918Z INFO execute{component="hello"}: prepare_component{component="hello"}: spin_engine: Preparing component hello
|
|
||||||
2022-02-06T02:44:08.810936Z INFO execute{component="hello"}: prepare_component{component="hello"}: store: spin_engine: Creating store.
|
|
||||||
2022-02-06T02:44:08.811318Z INFO execute{component="hello"}: spin_http_engine: Request URI: "/hello"
|
|
||||||
2022-02-06T02:44:08.811553Z INFO execute{component="hello"}: spin_http_engine: Response status code: 200
|
|
||||||
2022-02-06T02:44:08.811715Z INFO execute{component="hello"}: spin_http_engine: Request finished, sending response.
|
|
||||||
```
|
|
||||||
|
|
||||||
The application is now ready, after starting, send a request using
|
|
||||||
`curl -i localhost:3000/hello`:
|
|
||||||
|
|
||||||
```console
|
|
||||||
$ curl -i localhost:3000/hello
|
|
||||||
HTTP/1.1 200 OK
|
|
||||||
content-length: 12
|
|
||||||
date: Sun, 06 Feb 2022 02:44:08 GMT
|
|
||||||
|
|
||||||
I'm a teapot
|
|
||||||
```
|
|
||||||
|
|
||||||
## Publishing Interfaces
|
|
||||||
|
|
||||||
In the example above, the interface (`.wit` file) was copied over to the local
|
|
||||||
HTTP application directory. You can also publish interfaces to a bindle registry
|
|
||||||
for others to consume as well as pull interfaces from a bindle registry to use.
|
|
||||||
The example below creates and publishes the spin http interface and then walks
|
|
||||||
through how to consume it in the HTTP application from the previous example.
|
|
||||||
|
|
||||||
### Publish the Spin HTTP Interface
|
|
||||||
|
|
||||||
Push the Spin HTTP interface to the registry (from the root of this repository).
|
|
||||||
This step, together with starting the registry, will not be required once we set
|
|
||||||
up a canonical registry instance:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ wact interface publish --name fermyon/http --version 0.1.0 wit/ephemeral/spin-http.wit
|
|
||||||
```
|
|
||||||
|
|
||||||
### Use Interface in HTTP Application
|
|
||||||
|
|
||||||
1. Update `Cargo.toml` to include the following dependency, component and
|
|
||||||
interface information:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
[...]
|
|
||||||
[dependencies]
|
|
||||||
# The Wact dependency generates bindings that simplify working with interfaces.
|
|
||||||
wact = { git = "https://github.com/fermyon/wact", rev = "93a9eaeba9205918dc214a6310c0bb6e33c0e3c8" }
|
|
||||||
|
|
||||||
[workspace]
|
|
||||||
|
|
||||||
# Metadata about this component.
|
|
||||||
[package.metadata.component]
|
|
||||||
name = "spinhelloworld"
|
|
||||||
|
|
||||||
# This component implements the fermyon/http interface.
|
|
||||||
[package.metadata.component.exports]
|
|
||||||
fermyon-http = { name = "fermyon/http", version = "0.1.0" }
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Update the application to use wact to generate and use rust bindings. In
|
|
||||||
`src/lib.rs`:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
// Import the HTTP objects from the generated bindings.
|
|
||||||
use fermyon_http::{Request, Response};
|
|
||||||
|
|
||||||
// Generate Rust bindings for all interfaces in Cargo.toml.
|
|
||||||
wact::component!();
|
|
||||||
|
|
||||||
struct FermyonHttp {}
|
|
||||||
impl fermyon_http::FermyonHttp for FermyonHttp {
|
|
||||||
// Implement the `handler` entrypoint for Spin HTTP components.
|
|
||||||
fn handler(req: Request) -> Response {
|
|
||||||
println!("Request: {:?}", req);
|
|
||||||
Response {
|
|
||||||
status: 418,
|
|
||||||
headers: None,
|
|
||||||
body: Some("I'm a teapot".as_bytes().to_vec()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Remove `*.wit` files from local HTTP application directory
|
|
||||||
|
|
||||||
4. In the application directory, build the component:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ cargo build --target wasm32-wasi --release
|
|
||||||
# OR
|
|
||||||
$ cargo component build --release
|
|
||||||
```
|
|
||||||
|
|
||||||
[Run the application locally](#run-the-application-locally) to test.
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ fn hello_world(req: Request) -> Result<Response> {
|
||||||
Ok(http::Response::builder()
|
Ok(http::Response::builder()
|
||||||
.status(200)
|
.status(200)
|
||||||
.header("foo", "bar")
|
.header("foo", "bar")
|
||||||
.body(Some("Hello, Fermyon".into()))?)
|
.body(Some("Hello, Fermyon!".into()))?)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ server, modifies the result, then returns it:
|
||||||
```rust
|
```rust
|
||||||
#[http_component]
|
#[http_component]
|
||||||
fn hello_world(_req: Request) -> Result<Response> {
|
fn hello_world(_req: Request) -> Result<Response> {
|
||||||
let mut res = spin_sdk::outbound_http::send_request(
|
let mut res = spin_sdk::http::send(
|
||||||
http::Request::builder()
|
http::Request::builder()
|
||||||
.method("GET")
|
.method("GET")
|
||||||
.uri("https://fermyon.com")
|
.uri("https://fermyon.com")
|
||||||
|
@ -54,10 +54,11 @@ fn hello_world(_req: Request) -> Result<Response> {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
res.headers_mut()
|
res.headers_mut()
|
||||||
.insert(header::SERVER, "spin/0.1.0".try_into()?);
|
.insert(http::header::SERVER, "spin/0.1.0".try_into()?);
|
||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
In order for the component above to be allowed to make the outbound HTTP
|
In order for the component above to be allowed to make the outbound HTTP
|
||||||
|
@ -81,6 +82,5 @@ $ curl -I localhost:3000/hello
|
||||||
HTTP/1.1 200 OK
|
HTTP/1.1 200 OK
|
||||||
content-length: 29350
|
content-length: 29350
|
||||||
content-type: text/html; charset=utf-8
|
content-type: text/html; charset=utf-8
|
||||||
date: Fri, 04 Mar 2022 23:06:43 GMT
|
|
||||||
server: spin/0.1.0
|
server: spin/0.1.0
|
||||||
```
|
```
|
||||||
|
|
|
@ -20,6 +20,9 @@ pub mod http {
|
||||||
/// The Spin HTTP response.
|
/// The Spin HTTP response.
|
||||||
pub type Response = http::Response<Option<bytes::Bytes>>;
|
pub type Response = http::Response<Option<bytes::Bytes>>;
|
||||||
|
|
||||||
|
/// Directly expose the ability to send an HTTP request.
|
||||||
|
pub use crate::outbound_http::send_request as send;
|
||||||
|
|
||||||
/// Helper function to return a 404 Not Found response.
|
/// Helper function to return a 404 Not Found response.
|
||||||
pub fn not_found() -> Result<Response> {
|
pub fn not_found() -> Result<Response> {
|
||||||
Ok(http::Response::builder()
|
Ok(http::Response::builder()
|
||||||
|
|
|
@ -2,12 +2,11 @@ apiVersion = "0.1.0"
|
||||||
authors = ["Fermyon Engineering <engineering@fermyon.com>"]
|
authors = ["Fermyon Engineering <engineering@fermyon.com>"]
|
||||||
description = "A simple application that returns hello."
|
description = "A simple application that returns hello."
|
||||||
name = "spin-hello-world"
|
name = "spin-hello-world"
|
||||||
trigger = { type = "http", base = "/" }
|
trigger = { type = "http" }
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
|
||||||
[[component]]
|
[[component]]
|
||||||
id = "hello"
|
id = "hello"
|
||||||
source = "target/wasm32-wasi/release/spinhelloworld.wasm"
|
source = "target/wasm32-wasi/release/spinhelloworld.wasm"
|
||||||
# allowedHttpHosts = [ "https://fermyon.com" ]
|
|
||||||
[component.trigger]
|
[component.trigger]
|
||||||
route = "/hello"
|
route = "/hello"
|
||||||
|
|
Loading…
Reference in New Issue