LogoJaspr

Custom Backend

In the standard configuration, jaspr creates its own http server to handle incoming requests and render your components. For this it uses the popular shelf package.

If you want, you can customize the server implementation or completely replace it with your own. This allows also the use of your favorite dart backend framework.

Custom Shelf Middleware#

You can add custom shelf middleware to jasprs http server, for example to log requests or add additional api endpoints.

First replace your runApp method with the runServer method. This will return an instance of the ServerApp class that allows you to customize certain aspects of the http server.

void main() {
  // Similar to [runApp], but returns an instance of [ServerApp]
  var serverApp = runServer(App());
  
  // Attach a listener that is called when the server was started successfully
  serverApp.setListener((server) {
    // [server] is the [HttpServer] used to serve your app
    print('Serving at http://${server.address.host}:${server.port}');
  });
  
  // Adds the [logRequests] middleware to log all incoming requests
  serverApp.addMiddleware(logRequests);
  
  // Adds another shelf middleware. It takes a shelf handler and can modify,
  // redirect or intercept incoming requests.
  serverApp.addMiddleware((handler) {
    return (request) {
      // inspect or modify [request]
      
      // e.g. reroute to a custom handler
      if (request.url.path.startsWith('api')) {
        return handleApi(request.change(path: 'api'));
      }
      
      // this will continue with normal server side rendering
      return handler(request);
    };
  });
}

FutureOr<Response> handleApi(Request request) {
  return Response.ok('FROM API');
}

This code will respond FROM API to all requests under the /api endpoint, and render the App() component for all other requests.

For a complete app check out the custom_middleware example

Custom Backend#

If this is not enough, you can go one step further and spin up your own server or use a custom backend framework.

Since jaspr is built with shelf, this works best when the backend framework is also compatible with shelf. However you can work around this if that is not the case.

There are two main functions, that enable this:

  • Handler serveApp(AppHandler handler) bundles everything jaspr does on the server into a custom shelf handler. The handler can then be passed to your backend or server implementation.
  • String renderComponent(Component app) directly renders the provided component into a html string.

When using your own backend setup, you can still do jaspr serve, however auto-reload won't work on the server automatically.

Example: Shelf#

shelf is a widely-used package for building server apps with dart that is maintained by the Dart team.

Shelf makes it easy to create and compose web servers and parts of web servers.

Since jaspr used shelf internally, it is pretty straightforward to built a custom backend for jaspr using shelf.

void main() async {
  var handler = serveApp((request, render) {
    // Optionally do something with `request`
    print("Request uri is ${request.requestedUri}");
    // Return a server-rendered response by calling `render()` with your root component
    return render(App());
  });

  // provide `handler` to your app, e.g.
  await shelf_io.serve(handler, InternetAddress.anyIPv4, 8080);
}

Check out our shelf_backend example to see this in action.

Make sure that you set the base path of your app when mounting the serveApp handler to any other route prefix than /, otherwise your static resources like styles.css or main.dart.js can't be loaded correctly. Add the <base href="/<route_prefix>/"> tag to the head of your index.html, as demonstrated in the example.

Example: Dart Frog#

dart_frog is a new backend framework built by Very Good Ventures. You can combine it with jaspr to build powerful fullstack web applications that use dart_frog for managing the backend api and jaspr for rendering the frontend app.

Check out our dart_frog_backend example to see this in action.

With this, a dart_frog route that renders a jaspr component can be as simple as:

// routes/[my_component_path]/index.dart
Future<Response> onRequest(RequestContext context) {
  return renderJasprComponent(context, MyComponent());
}