dropserver

Github

Building A Dropserver App

Applicable Versions:

This page is valid for version 0.13.1 and above.

This page gives a high level overview of how a Dropserver app is built. See the tutorial for a hands-on example.

A Dropserver app is made up of:

Directory structure

You’re free to arrange your app’s code directory structure anyway you like, however there should be a directory that you can point the packaging system to that satisfies the following requirements:

While a trivial app may have the package directory at the root of the code repository, like the tutorial does. A more typical application will have an app subdirectory in the repo that is the root of the package. It includes app/dropapp.json and any backend code and assets that do not need to be built. (Any other assets that need to be built have their sources outside the app/ dir and the build process puts the built assets in app/.)

The entrypoint file is usually app/app.ts or app/app.js. If you use a different file name or if it’s not in the root directory of your package, then you must declare it in the entrypoint field of your dropapp.json.

If there is frontend that must be built, the source might be in frontend/, and the build target might be app/frontend/.

The Backend code

This “entrypoint” file should import createApp from a pinned version of the dropserver_app library. It should call the createApp function with appropriate parameters to create the app. The value returned from createApp can be exported and used to interact with the app elsewhere.

Note:

The dropserver_app library makes it convenient to write a Dropserver app without knowing its ever-changing internals.

Deno 2 Support

Dropserver can work with Deno 1 or Deno 2. To support Deno 2:

Naturally your own code must run under Deno 2.

Backend Basics

Below are some aspects of writing a Dropserver application that differ from other code you may have written before. It’s a high level overview. For specifics refer to the tutorial and the dropserver_app docs.

No server

You do not create a server in a Dropserver app. The server is run by Dropserver. You just declare routes with callbacks (or other parameters, see below) in createApp.

Note:

In the current version of Dropserver, app routes can only be created by using createApp. This means you can not create or remove routes of a running app. Use wildcard routes to serve generated assets.

Different route types

When declaring routes, you can specify a route type. Currently there are just two route types:

Local file access

Your app will always run in a sandbox therefore it will not have access to just any part of the file system. In fact it is strictly restricted to the following subdirectories:

The “current working directory” of the sandbox is the appspace files directory. To access a file in the appspace directory simply refer to it with a relative path: somePath/someFile.txt.

To operate in any of the other areas, you must first get the actual directory path by calling the appropriate method on your app instance, such as app.appPath(). You should call this every time you need it because it may change if the app gets upgraded or appspace gets moved around.

Users

User management is handled by Dropserver. Your app should not have any code to handle new user registration, passwords or any other auth, etc… You can get a full list of users from your app instance using app.getUsers() or get a specific user with app.getUser(<proxyID>).

A “proxy-id” is a string that uniquely identifies a user in your appspace. Your app does not have access to private identifiers such as email, etc…

Backend Code Caveats

localStorage ⚠️

Data stored in localStorage from the backend code may disappear. Deno stores that data at a location that is different from the appspace data files, as a result it will not be in appspace backups. The data may also disappear if the directory structure of the instance changes, or if bubblewrap is enabled or disabled. See this issue.

Note:

This is strictly about backend code. Feel free to use localStorage in your frontend.

Specify a file for Deno Key-Value DB

Similarly to the above, do not use Deno KV store without specifying a file path. When used in that manner, Deno stashes the data in the same obscure location as session and local storage, and it may be lost.

Open a KV by specifying a path in your appspace data directory, like this:

const kv = await Deno.openKv(app.appspacePath("kv.db"));

No Deno.json and import map 🚫

Do not use a deno.jsonfile. or an import map. For now Dropserver uses import maps internally, and does not currently attempt to merge any other import maps.

Note:

Proper handling for import maps and deno.json by Dropserver is on the roadmap.

Keep it lean

If no sandbox is running when a request is received, ds-host must start one and then forward the request. Sandbox start time can become long if the app code imports large number of libraries. For this reason use good judgement when adding code dependencies.

If you do need to depend on a large library for some operations, consider loading asynchronously on an as-needed basis.

Your app code will exit

Assume your code will exit between requests. Any data not stored in the appspace directory may be lost as soon as you are done sending a response to a request.

No outbound requests 🚫

Dropserver apps can not make outbound requests (meaning they can not initiate contact with other servers).

Note:

This is a temporary restriction that will be lifted as soon as an adequate permission model is written. See this blog post for the gory details.

Frontend and clients

You are free to build any frontend you like for your Dropserver app. From server-side HTML to PWA SPA to a native app, anything is possible so long as it makes HTTP requests to the backend.

Strict Content Security Policy

One caveat to keep in mind is that all responses from a Dropserver appspace have a strict Content Security Policy! The policy in the current version of Dropserver is: default-src: 'self'.

Note:

This strict CSP even prevents inline styles and a <style> tags from working in your HTML. I’m contemplating loosening the CSP to allow this. Please comment if you feel strongly one way or another.

Example frontend and clients:

Generate HTML server-side

Generate HTML server-side using a template language of your choice and serve CSS as static files. See the Secret Santa app code for an example using Mustache and one static CSS file.

Progressive Web App

Create a PWA Single-Page Application that is built when packaging the app and served statically. See the Leftovers code for an example PWA SPA using Vue.

This is a great way of providing near-native app experience without dealing with app stores.

Native app

Create a native app for your target environment (smartphone, desktop OS, or CLI) and interact with your app via a JSON API. Your native app would be packaged and distributed separately and should include a way to specify the appspace domain.

Note: authentication of appspace users from a native app has not been developed yet.

Server-Side Rendered 🤔

An SSR app may work as a Dropserver application, but it’s untested. First your SSR code has to run in Deno, while most assume Node. Second, routing may be an issue.