Skip to content

Cross-Platform Server

Spry server provides a unified Server-API to create cross-platform servers. Including Dart, Bun, Node and Deno

Why Spry server?

When you want to create an HTTP server with Dart, you must use dart:io.

Example: dart:io HTTP server (learn more):

dart
void main() async {
  final requests = await HttpServer.bind('localhost', 8888);
  await for (final request in requests) {
    processRequest(request);
  }
}

void processRequest(HttpRequest request) {
  print('Got request for ${request.uri.path}');
  final response = request.response;
  if (request.uri.path == '/dart') {
    response
      ..headers.contentType = ContentType(
        'text',
        'plain',
      )
      ..write('Hello from the server');
  } else {
    response.statusCode = HttpStatus.notFound;
  }
  response.close();
}

But when you want to run on Node/Bun/Deno runtime, you can't use Dart language but only JS/TS (Node needs additional translation to use TS):

Example: Node.js HTTP server (learn more):

typescript
import { createServer } from "node:http";

const server = createServer((req, res) => {
  res.end("Hello, Node.js!");
});

server.listen(3000, () => {
  console.log(`Server running at http://localhost:3000/`);
});

Example: Bun HTTP server (learn more):

typescript
Bun.serve({ port: 3000, fetch: (req) => new Response("Hello, Bun!") });

Example: Deno HTTP server (learn more):

typescript
Deno.serve({ port: 3000 }, (_req, info) => new Response("Hello, Deno!"));

You should note that each runtime is different. In particular, you can't make your Dart code universal.

Therefore, Spry server hopes to serve as a cross-platform standard server layer, rather than relying on a single runtime API. Let your Dart code move forward in the Dart and JavaScript ecosystem with ease!

Getting started

A server can be started using serve function from package:spry/server.dart.

dart
import 'package:spry/server.dart';

Future<void> main() async {
  final server = serve(
    hostname: 'localhost',
    port: 3000,
    fetch: (request, _) {
      return Response.fromString("Hey, I'm Spry cross server!");
    },
  );
  await server.ready();
  print('🎉 Server listen on ${server.url}');
}

Fetch handler

Request handler is defined via fetch key since it is similar to fetch API. The input is a Request object and handler should return a Response or a Future if the server handler is async.

Example:

dart
import 'package:spry/server.dart';

void main() {
  serve(
    fetch: (request, _) {
      return Response.fromString('''
          <h1>👋 Hello there</h1>
          <p>You are visiting ${request.url} from ${request.address}</p>
        ''',
        headers: Headers({
          'Content-Type': 'text/html',
        }),
      );
    }
  );
}

Server instance

When calling serve to start a server, a server instance will be immediately returned in order to control the server instance.

dart
import 'package:spry/server.dart';

Future<void> main() async {
  final server = serve(fetch: (request, server) {
    return Response.fromString('🔥 Server is powered by ${server.runtime.runtimeType}');
  });
  await server.ready();

  print('🚀 Server is ready at ${server.url}');

  // When server is no longer needed
  // server.close();
}

Server Properties

  • server.options: Access to the sever options set during initialization.
  • server.url: Get the computed server listening URL.
  • server.hostname: Listening address (hostname or ipv4/ipv6).
  • server.port: Listening port number.

Server methods

  • server.ready(): Returns a promise that will be resolved when server is listening to the port and ready to accept connections.
  • server.close([bool force = true]): Stop listening to prevent new connections from being accepted.

Server options

When starting a new server, in addition to main fetch handler, you can provide additional options to customize listening server.

dart
serve(
  // Generic options
  port: 3000,
  hostname: "localhost",

  // Enabling this option allows multiple processes to bind to the same port, which is useful for load balancing.
  reusePort: true,

  // Main server handler
  fetch: (request, server) => new Response.formString("👋 Hello there!"),
);

Deploy

To deploy your cross-platform HTTP server, please refer to the Deploy guide.

API Reference

See the API documentation for detailed information about all available APIs.

Released under the MIT License.