diff --git a/content/spin/v3/ai-sentiment-analysis-api-tutorial.md b/content/spin/v3/ai-sentiment-analysis-api-tutorial.md index 94d56d37a..16504dbbe 100644 --- a/content/spin/v3/ai-sentiment-analysis-api-tutorial.md +++ b/content/spin/v3/ai-sentiment-analysis-api-tutorial.md @@ -451,16 +451,8 @@ impl FromStr for Sentiment { {{ startTab "TypeScript"}} ```typescript -import { - HandleRequest, - HttpRequest, - HttpResponse, - Llm, - InferencingModels, - InferencingOptions, - Router, - Kv, -} from "@fermyon/spin-sdk"; +import { Llm, Kv } from "@fermyon/spin-sdk"; +import { AutoRouter } from 'itty-router'; interface SentimentAnalysisRequest { sentence: string; @@ -492,9 +484,9 @@ negative `; -async function performSentimentAnalysis(request: HttpRequest) { +async function performSentimentAnalysis(request: Request) { // Parse sentence out of request - let data = request.json() as SentimentAnalysisRequest; + let data = await request.json() as SentimentAnalysisRequest; let sentence = data.sentence; console.log("Performing sentiment analysis on: " + sentence); @@ -515,9 +507,9 @@ async function performSentimentAnalysis(request: HttpRequest) { // Otherwise, perform sentiment analysis console.log("Running inference"); - let options: InferencingOptions = { maxTokens: 6 }; + let options: Llm.InferencingOptions = { maxTokens: 6 }; let inferenceResult = Llm.infer( - InferencingModels.Llama2Chat, + Llm.InferencingModels.Llama2Chat, PROMPT.replace("", sentence), options ); @@ -539,36 +531,23 @@ async function performSentimentAnalysis(request: HttpRequest) { console.log("Caching sentiment in KV store"); kv.set(sentence, sentiment); - return { - status: 200, - body: JSON.stringify({ + return new Response(JSON.stringify({ sentiment, - } as SentimentAnalysisResponse), - }; + } as SentimentAnalysisResponse), { headers: { "Content-Type": "application/json" }}); } -let router = Router(); +let router = AutoRouter(); // Map the route to the handler -router.post("/api/sentiment-analysis", async (_, req) => { +router.post("/api/sentiment-analysis", async (req) => { console.log(`${new Date().toISOString()} POST /sentiment-analysis`); return await performSentimentAnalysis(req); }); -// Catch all 404 handler -router.all("/api/*", async (_, req) => { - return { - status: 404, - body: "Not found", - }; +//@ts-ignore +addEventListener('fetch', async (event: FetchEvent) => { + event.respondWith(router.fetch(event.request)); }); - -// Entry point to the Spin handler -export const handleRequest: HandleRequest = async function ( - request: HttpRequest -): Promise { - return await router.handleRequest(request, request); -}; ``` {{ blockEnd }} diff --git a/content/spin/v3/build.md b/content/spin/v3/build.md index 750f505e9..4057ec32c 100644 --- a/content/spin/v3/build.md +++ b/content/spin/v3/build.md @@ -78,12 +78,12 @@ It's normally convenient to put the detailed build instructions in `package.json ```json { "scripts": { - "build": "npx webpack --mode=production && npx mkdirp target && npx j2w -i dist.js -d combined-wit -n combined -o target/spin-http-js.wasm" + "build": "knitwit --out-dir build/wit/knitwit --out-world combined && npx webpack --mode=production && npx mkdirp target && npx j2w -i dist.js -d combined-wit -n combined -o target/spin-http-js.wasm" } } ``` -{{ details "Parts of the build script" "The build script calls out to [`webpack`](https://webpack.js.org/) and `j2w` which is a script provided by the `@fermyon/spin-sdk` package that utilizes [`ComponentizeJS`](https://github.com/bytecodealliance/ComponentizeJS)."}} +{{ details "Parts of the build script" "The build script calls out to [`webpack`](https://webpack.js.org/) and `j2w` which is a script provided by the `@fermyon/spin-sdk` package that utilizes [`ComponentizeJS`](https://github.com/bytecodealliance/ComponentizeJS). [`knitwit`](https://github.com/fermyon/knitwit) is a utility that helps combine `wit` worlds "}} The build command can then call the NPM script: diff --git a/content/spin/v3/javascript-components.md b/content/spin/v3/javascript-components.md index a48e95b6f..433a59630 100644 --- a/content/spin/v3/javascript-components.md +++ b/content/spin/v3/javascript-components.md @@ -12,7 +12,6 @@ url = "https://github.com/fermyon/developer/blob/main/content/spin/v3/javascript - [HTTP Components](#http-components) - [Sending Outbound HTTP Requests](#sending-outbound-http-requests) - [Storing Data in Redis From JS/TS Components](#storing-data-in-redis-from-jsts-components) -- [Routing in a Component](#routing-in-a-component) - [Storing Data in the Spin Key-Value Store](#storing-data-in-the-spin-key-value-store) - [Storing Data in SQLite](#storing-data-in-sqlite) - [Storing Data in MySQL and PostgreSQL Relational Databases](#storing-data-in-mysql-and-postgresql-relational-databases) @@ -76,13 +75,13 @@ This creates a directory of the following structure: ```text -hello-world/ -├── knitwit.json +hello-world +├── config +│ └── knitwit.json ├── package.json ├── spin.toml ├── src -│   ├── index.ts -│   └── spin.ts +│ └── index.ts ├── tsconfig.json └── webpack.config.js ``` @@ -134,24 +133,25 @@ for writing Spin components with the Spin JS/TS SDK. > Make sure to read [the page describing the HTTP trigger](./http-trigger.md) for more > details about building HTTP applications. -Building a Spin HTTP component using the JS/TS SDK means writing a single function -that takes an HTTP request and a Response Builder which can be used to return an HTTP response as a parameter. +Building a Spin HTTP component with the JavaScript/TypeScript SDK now involves adding an event listener for the `fetch` event. This event listener handles incoming HTTP requests and allows you to construct and return HTTP responses. Below is a complete implementation for such a component in TypeScript: ```javascript -import { ResponseBuilder } from "@fermyon/spin-sdk"; +import { AutoRouter } from 'itty-router'; -export async function handler(req: Request, res: ResponseBuilder) { - console.log(req); - res.send("hello universe"); -} -``` +let router = AutoRouter(); + +router + .get("/", () => new Response("hello universe")) + .get('/hello/:name', ({ name }) => `Hello, ${name}!`) -The important things to note in the implementation above: +//@ts-ignore +addEventListener('fetch', async (event: FetchEvent) => { + event.respondWith(router.fetch(event.request)); +}); -- The `handler` function is the entry point for the Spin component. -- The execution of the function terminates once `res.send` or `res.end` is called. +``` ## Sending Outbound HTTP Requests @@ -159,22 +159,27 @@ If allowed, Spin components can send outbound HTTP requests. Let's see an example of a component that makes a request to [an API that returns random animal facts](https://random-data-api.fermyon.app/animals/json) ```javascript -import { ResponseBuilder } from "@fermyon/spin-sdk"; - -interface AnimalFact { - timestamp: number; - fact: string; -} +import { AutoRouter } from 'itty-router'; -export async function handler(req: Request, res: ResponseBuilder) { - const animalFactResponse = await fetch("https://random-data-api.fermyon.app/animals/json") - const animalFact = await animalFactResponse.json() as AnimalFact +let router = AutoRouter(); - const body = `Here's an animal fact: ${animalFact.fact}\n` +router + .get("*", getDataFromAPI) - res.set({"content-type": "text/plain"}) - res.send(body) +async function getDataFromAPI(_request: Request) { + let response = await fetch( + 'https://random-data-api.fermyon.app/physics/json', + ); + let data = await response.json(); + let fact = `Here is a fact: ${data.fact}`; + return new Response(fact); } + +//@ts-ignore +addEventListener('fetch', async (event: FetchEvent) => { + event.respondWith(router.fetch(event.request)); +}); + ``` Before we can execute this component, we need to add the `random-data-api.fermyon.app` @@ -216,7 +221,7 @@ content-type: application/json; charset=utf-8 content-length: 185 server: spin/0.1.0 -Here's an animal fact: Reindeer grow new antlers every year +Here is a fact: Reindeer grow new antlers every year ``` > Without the `allowed_outbound_hosts` field populated properly in `spin.toml`, @@ -245,31 +250,35 @@ Using the Spin's JS SDK, you can use the Redis key/value store and to publish me Let's see how we can use the JS/TS SDK to connect to Redis: ```javascript -import { ResponseBuilder, Redis } from '@fermyon/spin-sdk'; +import { AutoRouter } from 'itty-router'; +import { Redis } from '@fermyon/spin-sdk'; const encoder = new TextEncoder(); -const decoder = new TextDecoder(); const redisAddress = 'redis://localhost:6379/'; -export async function handler(_req: Request, res: ResponseBuilder) { - try { - let db = Redis.open(redisAddress); - db.set('test', encoder.encode('Hello world')); - let val = db.get('test'); - - if (!val) { - res.status(404); - res.send(); - return; - } - // publish to a channel names "message" - db.publish("message", val) - res.send(val); - } catch (e: any) { - res.status(500); - res.send(`Error: ${JSON.stringify(e.payload)}`); - } -} +let router = AutoRouter(); + +router + .get("/", () => { + try { + let db = Redis.open(redisAddress); + db.set('test', encoder.encode('Hello world')); + let val = db.get('test'); + + if (!val) { + return new Response(null, { status: 404 }); + } + return new Response(val); + } catch (e: any) { + return new Response(`Error: ${JSON.stringify(e.payload)}`, { status: 500 }); + } + }) + +//@ts-ignore +addEventListener('fetch', async (event: FetchEvent) => { + event.respondWith(router.fetch(event.request)); +}); + ``` This HTTP component demonstrates fetching a value from Redis by key, setting a key with a value, and publishing a message to a Redis channel. @@ -285,33 +294,6 @@ As with all networking APIs, you must grant access to Redis hosts via the `allow allowed_outbound_hosts = ["redis://localhost:6379"] ``` -## Routing in a Component - -The JavaScript/TypeScript SDK provides a router that makes it easier to handle routing within a component. The router is based on [`itty-router`](https://www.npmjs.com/package/itty-router). An additional function `handleRequest` has been implemented in the router to allow passing in the Spin HTTP request directly. An example usage of the router is given below: - -```javascript -import { ResponseBuilder, Router } from '@fermyon/spin-sdk'; - -let router = Router(); - -router.get("/", (_, req, res) => { handleDefaultRoute(req, res) }) -router.get("/home/:id", (metadata, req, res) => { handleHomeRoute(req, res, metadata.params.id) }) - -async function handleDefaultRoute(_req: Request, res: ResponseBuilder) { - res.set({ "content-type": "text/plain" }); - res.send("Hello from default route"); -} - -async function handleHomeRoute(_req: Request, res: ResponseBuilder, id: string) { - res.set({ "content-type": "text/plain" }); - res.send(`Hello from home route with id: ${id}`); -} - -export async function handler(req: Request, res: ResponseBuilder) { - await router.handleRequest(req, res); -} -``` - ## Storing Data in the Spin Key-Value Store Spin has a key-value store built in. For information about using it from TypeScript/JavaScript, see [the key-value store tutorial](key-value-store-tutorial). @@ -381,5 +363,5 @@ These are some of the suggested libraries that have been tested and confirmed to ## Caveats -- All `spin-sdk` related functions and methods (like `Variables`, `Redis`, `Mysql`, `Pg`, `Kv` and `Sqlite`) can be called only inside the `handler` function. This includes `fetch`. Any attempts to use it outside the function will lead to an error. This is due to Wizer using only Wasmtime to execute the script at build time, which does not include any Spin SDK support. +- All `spin-sdk` related functions and methods (like `Variables`, `Redis`, `Mysql`, `Pg`, `Kv` and `Sqlite`) can be called only inside the fetch event handler. This includes `fetch`. Any attempts to use it outside the function will lead to an error. This is due to Wizer using only Wasmtime to execute the script at build time, which does not include any Spin SDK support. - No crypto operation that involve handling private keys are supported. diff --git a/content/spin/v3/key-value-store-tutorial.md b/content/spin/v3/key-value-store-tutorial.md index 0c8fa9be4..2cfb5e4ec 100644 --- a/content/spin/v3/key-value-store-tutorial.md +++ b/content/spin/v3/key-value-store-tutorial.md @@ -233,50 +233,51 @@ fn handle_request(req: Request) -> anyhow::Result { {{ startTab "TypeScript"}} ```typescript -import { ResponseBuilder, Kv } from "@fermyon/spin-sdk"; - -const encoder = new TextEncoder() -const decoder = new TextDecoder() - -export async function handler(req: Request, res: ResponseBuilder) { - - let store = Kv.openDefault() - let status = 200 - let body - - switch (req.method) { - case "POST": - store.set(req.uri, await req.text() || (new Uint8Array()).buffer) - console.log(`Storing value in the KV store with ${req.uri} as the key`); - break; - case "GET": - let val - try { - val = store.get(req.uri) - body = decoder.decode(val) - console.log(`Found value for the key ${req.uri}`); - } catch (error) { - console.log(`Key ${req.uri} not found`); - status = 404 - } - break; - case "DELETE": - store.delete(req.uri) - console.log(`Deleted Key ${req.uri}`); - break; - case "HEAD": - if (!store.exists(req.uri)) { - console.log(`Key ${req.uri} not found`); - status = 404 - } else { - console.log(`Found Key ${req.uri}`); - } - break; - default: - } - res.status(status) - res.send(body) -} +import { AutoRouter } from 'itty-router'; +import { Kv } from '@fermyon/spin-sdk'; + +const decoder = new TextDecoder(); + +let router = AutoRouter(); + +router + .all("*", async (req: Request) => { + let store = Kv.openDefault(); + let status = 200; + let body; + + switch (req.method) { + case 'POST': + store.set(req.url, (await req.bytes()) || new Uint8Array().buffer); + break; + case 'GET': + let val; + val = store.get(req.url); + if (!val) { + status = 404; + } else { + body = decoder.decode(val); + } + break; + case 'DELETE': + store.delete(req.url); + break; + case 'HEAD': + if (!store.exists(req.url)) { + status = 404; + } + break; + default: + } + + return new Response(body, { status }); + }) + +//@ts-ignore +addEventListener('fetch', async (event: FetchEvent) => { + event.respondWith(router.fetch(event.request)); +}); + ``` {{ blockEnd }} diff --git a/content/spin/v3/kv-store-api-guide.md b/content/spin/v3/kv-store-api-guide.md index 6f4d47e96..237d03dc7 100644 --- a/content/spin/v3/kv-store-api-guide.md +++ b/content/spin/v3/kv-store-api-guide.md @@ -88,15 +88,22 @@ fn handle_request(_req: Request) -> Result { The key value functions can be accessed after opening a store using either [the `Kv.open` or the `Kv.openDefault` methods](https://fermyon.github.io/spin-js-sdk/modules/Kv.html) which returns a [handle to the store](https://fermyon.github.io/spin-js-sdk/interfaces/Kv.Store.html). For example: ```ts -import { ResponseBuilder , Kv} from "@fermyon/spin-sdk"; - -export async function handler(req: Request, res: ResponseBuilder) { - let store = Kv.openDefault() - store.set("mykey", "myvalue") - res.status(200) - res.set({"content-type":"text/plain"}) - res.send(store.get("mykey") ?? "Key not found") -} +import { AutoRouter } from 'itty-router'; +import { Kv } from '@fermyon/spin-sdk'; + +let router = AutoRouter(); + +router + .get("/", () => { + let store = Kv.openDefault() + store.set("mykey", "myvalue") + return new Response(store.get("mykey") ?? "Key not found"); + }) + +//@ts-ignore +addEventListener('fetch', async (event: FetchEvent) => { + event.respondWith(router.fetch(event.request)); +}); ``` **General Notes** diff --git a/content/spin/v3/quickstart.md b/content/spin/v3/quickstart.md index e1ef6a05c..a40208e28 100644 --- a/content/spin/v3/quickstart.md +++ b/content/spin/v3/quickstart.md @@ -357,11 +357,12 @@ This command created a directory with the necessary files needed to build and ru $ cd hello_typescript $ tree . +├── config +│ └── knitwit.json ├── package.json -├── README.md ├── spin.toml ├── src -│   └── index.ts +│ └── index.ts ├── tsconfig.json └── webpack.config.js ``` @@ -384,7 +385,7 @@ route = "/..." component = "hello-typescript" [component.hello-typescript] -source = "target/hello-typescript.wasm" +source = "dist/hello-typescript.wasm" exclude_files = ["**/node_modules"] [component.hello-typescript.build] command = "npm run build" @@ -398,19 +399,22 @@ This represents a simple Spin HTTP application (triggered by an HTTP request). [Learn more about the manifest here.](./writing-apps) Now let's have a look at the code. Below is the complete source -code for a Spin HTTP component written in TypeScript — a regular function named `handleRequest` that -takes an HTTP request as a parameter and returns an HTTP response. (The -JavaScript version looks slightly different, but is still a function with -the same signature.) The Spin integration looks for the `handler` function -by name when building your application into a Wasm module: +code for a Spin HTTP component written in TypeScript — A function is attached to the fetch event listener which receives and responds to the HTTP request. ```javascript -import { ResponseBuilder } from "@fermyon/spin-sdk"; +❯ cat hello-world/src/index.ts +import { AutoRouter } from 'itty-router'; -export async function handler(req: Request, res: ResponseBuilder) { - console.log(req); - res.send("hello universe"); -} +let router = AutoRouter(); + +router + .get("/", () => new Response("hello universe")) + .get('/hello/:name', ({ name }) => `Hello, ${name}!`) + +//@ts-ignore +addEventListener('fetch', async (event: FetchEvent) => { + event.respondWith(router.fetch(event.request)); +}); ``` {{ blockEnd }} @@ -733,30 +737,21 @@ $ spin build Executing the build command for component hello-typescript: npm run build > hello-typescript@1.0.0 build -> npx webpack --mode=production && npx mkdirp target && npx j2w -i dist.js -d combined-wit -n combined -o target/hello-typescript.wasm +> knitwit --out-dir build/wit/knitwit --out-world combined && npx webpack --mode=production && npx mkdirp target && npx j2w -i dist.js -d combined-wit -n combined -o target/hello-typescript.wasm asset spin.js 4.57 KiB [emitted] (name: main) runtime modules 670 bytes 3 modules ./src/index.ts 2.85 KiB [built] [code generated] webpack 5.75.0 compiled successfully in 1026 ms -Starting to build Spin compatible module -Preinitiating using Wizer -Optimizing wasm binary using wasm-opt -Spin compatible module built successfully Finished building all Spin components ``` -If the build fails, check: - -* Are you in the `hello_typescript` directory? -* Did you run `npm install` before building`? - If you would like to know what build command Spin runs for a component, you can find it in the manifest, in the `component.(id).build` section: ```toml [component.hello-typescript.build] -command = "npm run build" +command = ["npm install", "npm run build"] ``` You can always run this command manually; `spin build` is a shortcut. diff --git a/content/spin/v3/rdbms-storage.md b/content/spin/v3/rdbms-storage.md index 6bb8ef5bd..6b55b3af3 100644 --- a/content/spin/v3/rdbms-storage.md +++ b/content/spin/v3/rdbms-storage.md @@ -78,7 +78,9 @@ For full information about the MySQL and PostgreSQL APIs, see [the Spin SDK refe The code below is an [Outbound MySQL example](https://github.com/fermyon/spin-js-sdk/tree/main/examples/spin-host-apis/spin-mysql). There is also an outbound [PostgreSQL example](https://github.com/fermyon/spin-js-sdk/tree/main/examples/spin-host-apis/spin-postgres) available. ```ts -import { ResponseBuilder, Mysql } from '@fermyon/spin-sdk'; +// https://itty.dev/itty-router/routers/autorouter +import { AutoRouter } from 'itty-router'; +import { Mysql } from '@fermyon/spin-sdk'; // Connects as the root user without a password const DB_URL = "mysql://root:@127.0.0.1/spin_dev" @@ -91,17 +93,22 @@ const DB_URL = "mysql://root:@127.0.0.1/spin_dev" insert into test values (4,4); */ -export async function handler(_req: Request, res: ResponseBuilder) { - // For PostgreSQL, use `Postgres.open` - let conn = Mysql.open(DB_URL); - // For PostgreSQL, use `$1` placeholder syntax - conn.execute('delete from test where id=?', [4]); - conn.execute('insert into test values (4,5)', []); - let ret = conn.query('select * from test', []); - // return a object that looks like - // { "columns": [{name: "id", dataType: "int32"}], "rows": [{ "id": 4, "val": 5 }] } - res.send(JSON.stringify(ret, null, 2)); -} +let router = AutoRouter(); + +router + .get("/", () => { + let conn = Mysql.open(DB_URL); + conn.execute('delete from test where id=?', [4]); + conn.execute('insert into test values (4,5)', []); + let ret = conn.query('select * from test', []); + + return new Response(JSON.stringify(ret, null, 2)); + }) + +//@ts-ignore +addEventListener('fetch', async (event: FetchEvent) => { + event.respondWith(router.fetch(event.request)); +}); ``` {{ blockEnd }} diff --git a/content/spin/v3/serverless-ai-api-guide.md b/content/spin/v3/serverless-ai-api-guide.md index 62a9f56b5..e5d3c336b 100644 --- a/content/spin/v3/serverless-ai-api-guide.md +++ b/content/spin/v3/serverless-ai-api-guide.md @@ -121,16 +121,24 @@ The `infer_with_options` examples, operation: To use Serverless AI functions, [the `Llm` module](https://fermyon.github.io/spin-js-sdk/modules/Llm.html) from the Spin SDK provides two methods: `infer` and `generateEmbeddings`. For example: ```javascript -import { ResponseBuilder, Llm} from "@fermyon/spin-sdk" +import { AutoRouter } from 'itty-router'; +import { Llm } from '@fermyon/spin-sdk'; -export async function handler(req: Request, res: ResponseBuilder) { - let embeddings = Llm.generateEmbeddings(Llm.EmbeddingModels.AllMiniLmL6V2, ["someString"]) - console.log(embeddings.embeddings) - let result = Llm.infer(Llm.InferencingModels.Llama2Chat, prompt) +let router = AutoRouter(); - res.set({"content-type":"text/plain"}) - res.send(result.text) -} +router + .get("/", () => { + let embeddings = Llm.generateEmbeddings(Llm.EmbeddingModels.AllMiniLmL6V2, ["someString"]) + console.log(embeddings.embeddings) + let result = Llm.infer(Llm.InferencingModels.Llama2Chat, prompt) + + return new Response(result.text); + }) + +//@ts-ignore +addEventListener('fetch', async (event: FetchEvent) => { + event.respondWith(router.fetch(event.request)); +}); ``` **General Notes** diff --git a/content/spin/v3/serverless-ai-hello-world.md b/content/spin/v3/serverless-ai-hello-world.md index c104fa7c4..02acbe14c 100644 --- a/content/spin/v3/serverless-ai-hello-world.md +++ b/content/spin/v3/serverless-ai-hello-world.md @@ -305,17 +305,27 @@ fn hello_world(_req: Request) -> anyhow::Result { {{ startTab "TypeScript"}} -```tsx -import { Llm, InferencingModels, HandleRequest, HttpRequest, HttpResponse } from "@fermyon/spin-sdk" +```typescript + +import { AutoRouter } from 'itty-router'; +import { Llm } from '@fermyon/spin-sdk'; + const model = InferencingModels.Llama2Chat -export const handleRequest: HandleRequest = async function (request: HttpRequest): Promise { -const prompt = "Can you tell me a joke about cats" -const out = Llm.infer(model, prompt) -return { - status: 200, - body: out.text - } -} + +let router = AutoRouter(); + +router + .get("/", () => { + const out = Llm.infer(model, prompt) + + return new Response(out.text); + }) + +//@ts-ignore +addEventListener('fetch', async (event: FetchEvent) => { + event.respondWith(router.fetch(event.request)); +}); + ``` {{ blockEnd }} diff --git a/content/spin/v3/sqlite-api-guide.md b/content/spin/v3/sqlite-api-guide.md index 3641edee4..3928fd0a1 100644 --- a/content/spin/v3/sqlite-api-guide.md +++ b/content/spin/v3/sqlite-api-guide.md @@ -125,14 +125,23 @@ struct ToDo { To use SQLite functions, use [the `Sqlite.open` or `Sqlite.openDefault` function](https://fermyon.github.io/spin-js-sdk/modules/Sqlite.html) to obtain [a `SqliteConnection` object](https://fermyon.github.io/spin-js-sdk/interfaces/Sqlite.SqliteConnection.html). `SqliteConnection` provides the `execute` method as described above. For example: ```javascript -import { ResponseBuilder, Sqlite } from "@fermyon/spin-sdk"; +import { AutoRouter } from 'itty-router'; +import { Sqlite } from '@fermyon/spin-sdk'; -export async function handler(req: Request, res: ResponseBuilder) { - let conn = Sqlite.openDefault(); - let result = conn.execute("SELECT * FROM todos WHERE id > (?);", [1]); +let router = AutoRouter(); +router + .get("/", () => { + let conn = Sqlite.openDefault(); + let result = conn.execute("SELECT * FROM todos WHERE id > (?);", [1]); + + return new Response(JSON.stringify(result, null, 2)); + }) + +//@ts-ignore +addEventListener('fetch', async (event: FetchEvent) => { + event.respondWith(router.fetch(event.request)); +}); - res.send(JSON.stringify(result)); -} ``` **General Notes** diff --git a/content/spin/v3/variables.md b/content/spin/v3/variables.md index c0ec066ef..d1429c6c6 100644 --- a/content/spin/v3/variables.md +++ b/content/spin/v3/variables.md @@ -137,25 +137,34 @@ async fn handle_api_call_with_token(_req: Request) -> anyhow::Result [**Want to go straight to the reference documentation?** Find it here.](https://fermyon.github.io/spin-js-sdk/modules/Variables.html) ```ts -import { ResponseBuilder, Variables } from "@fermyon/spin-sdk"; - -export async function handler(req: Request, res: ResponseBuilder) { - let token = Variables.get("token") - let apiUri = Variables.get("api_uri") - let version = Variables.get("version") - let versionedAPIUri = `${apiUri}/${version}` - let response = await fetch( - versionedAPIUri, - { - headers: { - 'Authorization': 'Bearer ' + token - } - } - ); - // Do something with the response ... - res.set({ "Content-Type": "text/plain" }) - res.send("Used an API") -} +import { AutoRouter } from 'itty-router'; +import { Variables } from '@fermyon/spin-sdk'; + +let router = AutoRouter(); + +router + .get("/", () => { + let token = Variables.get("token") + let apiUri = Variables.get("api_uri") + let version = Variables.get("version") + let versionedAPIUri = `${apiUri}/${version}` + let response = await fetch( + versionedAPIUri, + { + headers: { + 'Authorization': 'Bearer ' + token + } + } + ); + + return new Response("Used an API"); + }) + +//@ts-ignore +addEventListener('fetch', async (event: FetchEvent) => { + event.respondWith(router.fetch(event.request)); +}); + ``` {{ blockEnd }}