Skip to content

Commit

Permalink
Merge pull request #1265 from fermyon/tpmccallum-patch-1
Browse files Browse the repository at this point in the history
Granular routing in Spin 2.5
  • Loading branch information
Timothy McCallum authored May 8, 2024
2 parents 8027c90 + e1d6a74 commit fbb1ffc
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 10 deletions.
38 changes: 29 additions & 9 deletions content/spin/v2/http-trigger.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ url = "https://github.com/fermyon/developer/blob/main/content/spin/v2/http-trigg
- [HTTP Trigger Routes](#http-trigger-routes)
- [Routing with an Application `base`](#routing-with-an-application-base)
- [Resolving Overlapping Routes](#resolving-overlapping-routes)
- [Private Endpoints](#private-endpoints)
- [Health Check Route](#health-check-route)
- [Authoring HTTP Components](#authoring-http-components)
- [The Request Handler](#the-request-handler)
Expand Down Expand Up @@ -64,7 +65,11 @@ route = "/cart/checkout"
component = "checkout"
```

A _wildcard_ route matches the given route and any route under it. A route is a wildcard if it ends in `/...`. For example, `/users/...` matches `/users`, `/users/1`, `/users/1/edit`, and so on. Any of these routes will run the mapped component.
You can use wildcards to match 'patterns' of routes. Spin supports two kinds of wildcards: single-segment wildcards and trailing wildcards.

A single-segment wildcard uses the syntax `:name`, where `name` is a name that identifies the wildcard. Such a wildcard will match only a single segment of a path, and allows further matching on segments beyond it. For example, `/users/:userid/edit` matches `/users/1/edit` and `/users/alice/edit`, but does not match `/users`, `/users/1`, or `/users/1/edit/cart`.

A trailing wildcard uses the syntax `/...` and matches the given route and any route under it. For example, `/users/...` matches `/users`, `/users/1`, `/users/1/edit`, and so on. Any of these routes will run the mapped component.

> In particular, the route `/...` matches all routes.
Expand Down Expand Up @@ -122,6 +127,20 @@ route = "/..."
component = "shop"
```

### Private Endpoints

Private endpoints are where an internal microservice is not exposed to the network (does not have an HTTP route) and so is accessible only from within the application.

<!-- @nocpy -->

```toml
[[trigger.http]]
route = { private = true }
component = "internal"
```

To access a private endpoint, use [local service chaining](./http-outbound#local-service-chaining) (where the request is passed in memory without ever leaving the Spin host process). Such calls still require the internal endpoint to be included in `allowed_outbound_hosts`.

### Health Check Route

Every HTTP application automatically has a special route always configured at `/.well-known/spin/health`, which
Expand Down Expand Up @@ -335,7 +354,7 @@ func main() {}

Exactly how the Spin SDK surfaces the request and response types varies from language to language; this section calls out general features.

* In the request record, the URL contains the path and query, but not the scheme and host. For example, in a request to `https://example.com/shop/users/1?theme=pink`, the URL contains `/shop/users/1?theme=pink`. If you need the full URL, you can get it from the `spin-full-url` header - see the table below.
* In the request record, the URL contains the path and query, but not the scheme and host. For example, in a request to `https://example.com/shop/users/1/cart/items/3/edit?theme=pink`, the URL contains `/shop/users/1/cart/items/3/edit?theme=pink`. If you need the full URL, you can get it from the `spin-full-url` header - see the table below.

### Additional Request Information

Expand All @@ -344,16 +363,17 @@ As well as any headers passed by the client, Spin sets several headers on the re
> In the following table, the examples suppose that:
> * Spin is listening on `example.com:8080`
> * The application `base` is `/shop`
> * The trigger `route` is `/users/...`
> * The request is to `https://example.com:8080/shop/users/1/edit?theme=pink`
> * The trigger `route` is `/users/:userid/cart/...`
> * The request is to `https://example.com:8080/shop/users/1/cart/items/3/edit?theme=pink`
| Header Name | Value | Example |
|------------------------------|----------------------|---------|
| `spin-full-url` | The full URL of the request. This includes full host and scheme information. | `https://example.com:8080/shop/users/1/edit?theme=pink` |
| `spin-path-info` | The request path relative to the component route (including any base) | `/1/edit` |
| `spin-matched-route` | The part of the request path that was matched by the route (including the base and wildcard indicator if present) | `/shop/users/...` |
| `spin-raw-component-route` | The component route pattern matched, as written in the component manifest (that is, _excluding_ the base, but including the wildcard indicator if present) | `/users/...` |
| `spin-component-route` | The component route pattern matched, _excluding_ any wildcard indicator | `/users` |
| `spin-full-url` | The full URL of the request. This includes full host and scheme information. | `https://example.com:8080/shop/users/1/cart/items/3/edit?theme=pink` |
| `spin-path-info` | The request path relative to the component route (including any base) | `/items/3` |
| `spin-path-match-n` | Where `n` is the pattern for our single-segment wildcard value (e.g. `spin-path-match-userid` will access the value in the URL that represents `:userid`) | `1` |
| `spin-matched-route` | The part of the trigger route that was matched by the route (including the base and wildcard indicator if present) | `/shop/users/:userid/cart/...` |
| `spin-raw-component-route` | The component route pattern matched, as written in the component manifest (that is, _excluding_ the base, but including the wildcard indicator if present) | `/users/:userid/cart/...` |
| `spin-component-route` | The component route pattern matched, _excluding_ any wildcard indicator | `/users/:userid/cart` |
| `spin-base-path` | The application base path | `/shop` |
| `spin-client-addr` | The IP address and port of the client | `127.0.0.1:53152` |

Expand Down
4 changes: 3 additions & 1 deletion content/spin/v2/manifest-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,9 @@ Each array entry contains a mix of common fields and trigger-specific fields.

| Name | Required? | Type | Value | Example |
|-------------------------|------------|-------------|----------|-----------|
| `route` | Required | String | The route which this component handles. Requests to the route will cause the component to execute. This may be an exact route (`/example`), which matches on the given path, or a wildcard route indicated by the suffix `/...` (`/example/...`), which matches any route under this prefix. If two routes overlap, requests are directed to the matching route with the longest prefix - see [the HTTP trigger documentation](http-trigger) for details and examples. | `"/api/cart/..."` |
| `route` | Required | String or table | The route which this component handles. Requests to the route will cause the component to execute. | |
| | | String | This may be an exact route (`/example`), which matches only the given path, or may include wildcards (`/example/:id` or `/example/...`). If two routes overlap, requests are directed to the matching route with the longest prefix. See [the HTTP trigger documentation](http-trigger) for details and examples. | `"/api/cart/..."` |
| | | Table | If the component is a private endpoint used for [local service chaining](http-outbound#local-service-chaining) then use the table value shown here. | `{ private = true }`|
| `executor` | Optional | Table | How Spin should invoke the component. If present, this is a table. The `type` key is required and may have the values `"spin"` or `"wagi"`. If omitted. the default is `{ type = "spin"}`. See [the HTTP trigger documentation](http-trigger) for details. | `{ type = "wagi" }` |
| | | | If `type = "spin"` there are no other keys defined. In this case, Spin calls the component using a standard Wasm component interface. Components built using Spin SDKs or Spin interface files use this convention. | `{ type = "spin" }` |
| | | | If `type = "wagi"`, Spin calls the component's "main" (`_start`) function using [a CGI-like interface](https://github.com/deislabs/wagi). Components built using languages or toolchains that do not support Wasm interfaces will need to be called in this way. In this case, the following additional keys may be set:<br/><br/>* `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}`<br/><br/>* `entrypoint` (optional): The name of the function to call as the entry point to this handler. By default, it is `_start` (which in most languages translates to `main` in the source code).<br/><br/>See [the HTTP trigger documentation](http-trigger) for details. | `{ type = "wagi" }` |
Expand Down

0 comments on commit fbb1ffc

Please sign in to comment.