Pipedown as a Server

Every Pipedown script written to the ./.pd directory of your project also has a corresponding server file.

For example, given the helloWorld pipe. You will also find the following file:

./.pd/helloWorld/server.ts

We piggyback on Deno.serve to do the heavy lifting. Deno.serve can be used in a traditional sense, deployed on your own infrastructure, behind a reverse proxy of some kind. It is also compatible with Deno Deploy! Which makes it trivial to serve up your pipes, and any associated static files, with a single command. Checkout Deno Deploy:

https://deno.com/deploy

Note: this website is hosted on Deno Deploy. A single command, deployctl deploy serves up a fresh version of the site. See the Repo

Just a wrapper

The server.ts is a very simple wrapper to pass requests to your pipeline.

const server = Deno.serve(async (request: Request) => {
  const output = await pipe.process({
        request, 
        body: {}, 
        responseOptions: {
        headers: {
            "content-type": "application/json"
        },
        status: 200,
    }
  });
  
  return new Response(output.body, output.responseOptions);
});

Requests

When working with Deno, you get the pleasure of working with Web Standard Request and Response objects - on the server!

We pass this request to your pipeline. You can access it in any pipe codeblock with input.request.

Routing

When Pipedown finds a request in an input object, it will check to see if your function is behind a route: condition.

For instance, a function like this:

- route: /hello
    ```ts
    console.log("Hello there!");
    ```

Will only be executed when the request.pathname is /hello. Pipedown leverages URLPatterns to provide simple and effective routing - it even supports route params!

If a pattern is matched, Pipedown will inject input.route to the function which gives you access to the URLPattern return object, e.g:

- route: /hello/:name
    ```ts
    const match = $p.get(input, '/route/pathname/groups/name')
    console.log(`Hello, ${match}!`);
    ```

Response

The server wrapper provides a simple response setup. If you return input.body from your pipe, we assume it is JSON friendly and respond to the client appropriately:

{
    headers: {
        "content-type": "application/json"
    },
    status: 200,
}

You have complete control over this object, just add your response options to input.responseOptions and pass any data to input.body if desired. Alternatively you can pass a full new Response() object to input.response.

Concrete Example

To round things off, let's turn this Markdown file itself into a server!

Let's create a small set of routes that will return random placeholder images from some fun placeholder image providers.

placeBear

loremflickr

Lorem Picsum

Root

If no route is matched, we will return a simple text response. We use the not: condition here to ensure this is only executed when no route is matched.

RIP

A very sad discovery is that both placekitten and placecage are no longer available. RIP. 🫡

Running the server

To run the server, execute the following commands:

git clone https://github.com/aaronmyatt/pdwebsite
cd pdwebsite
# assuming you have Pipedown installed 😉

pd build
deno run --allow-net ./.pd/examples/useCases/server/server.ts

You can now access your server at http://localhost:8000 and see random pictures at these routes:

Toot toot

Horn tooting time! Writing and hosting servers has never been easier. Writing them with Pipedown has made it easy and delightful AND educational 👆! Try it for yourself and reach out if you have ideas about how to make this cooler.