Skip to content

Add Shelf Framework #10025

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions frameworks/Dart/shelf/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# From https://hub.docker.com/_/dart
.dockerignore
Dockerfile
build/
.dart_tool/
.git/
.github/
.gitignore
.packages
5 changes: 5 additions & 0 deletions frameworks/Dart/shelf/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# https://dart.dev/guides/libraries/private-files
# Created by `dart pub`
.dart_tool/
*.lock
!bin
23 changes: 23 additions & 0 deletions frameworks/Dart/shelf/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Shelf Benchmarking Test

### Test Type Implementation Source Code

- [JSON](server.dart)
- [PLAINTEXT](server.dart)

## Important Libraries

The tests were run with:

- [pkg:shelf](https://pub.dev/packages/shelf)
- [Dart](https://dart.dev/)

## Test URLs

### JSON

http://localhost:8080/json

### PLAINTEXT

http://localhost:8080/plaintext
26 changes: 26 additions & 0 deletions frameworks/Dart/shelf/benchmark_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"framework": "shelf",
"tests": [
{
"default": {
"json_url": "/json",
"plaintext_url": "/plaintext",
"port": 8080,
"approach": "Realistic",
"classification": "Micro",
"database": "None",
"framework": "shelf",
"language": "Dart",
"flavor": "None",
"orm": "None",
"platform": "shelf",
"webserver": "None",
"os": "Linux",
"database_os": "Linux",
"display_name": "shelf",
"notes": "",
"versus": "None"
}
}
]
}
84 changes: 84 additions & 0 deletions frameworks/Dart/shelf/bin/server.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import 'dart:convert';
import 'dart:io';
import 'dart:isolate';

import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart' as shelf_io;

void main(List<String> args) async {
/// Create an [Isolate] containing an [HttpServer]
/// for each processor after the first
for (var i = 1; i < Platform.numberOfProcessors; i++) {
await Isolate.spawn(_startServer, args);
}

/// Create a [HttpServer] for the first processor
await _startServer(args);
}

/// Create a request handler
Response _handler(Request request) {
switch (request.url.path) {
case 'json':
return _jsonTest();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Do we prefer to inline the logic over private functions? From some benchmarks I did ages ago, calling a function over inlining introduces a very minimal delay (when done a lot of times). It was quite minuscule though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to maintain the same structure as in the pure Dart examples. I wouldn’t expect it to matter since the compiler would likely decide to inline (we can always annotate with @pragma(vm:prefer-inline) if needed).

case 'plaintext':
return _plaintextTest();
default:
return _sendResponse(HttpStatus.notFound);
}
}

/// Creates and setup a [HttpServer].
Future<void> _startServer(List<String> _) async {
final server = await shelf_io.serve(
_handler,
InternetAddress.anyIPv4,
8080,
shared: true,
);

/// Sets [HttpServer]'s [serverHeader].
server
..defaultResponseHeaders.clear()
..serverHeader = 'shelf';
}

/// Completes the given [request] by writing the [bytes] with the given
/// [statusCode] and [type].
Response _sendResponse(
int statusCode, {
ContentType? type,
List<int> bytes = const [],
}) {
return Response(
statusCode,
headers: {
HttpHeaders.contentLengthHeader: '${bytes.length}',
HttpHeaders.dateHeader: '${HttpDate.format(DateTime.now())}',
if (type != null) HttpHeaders.contentTypeHeader: type.mimeType,
},
body: bytes,
);
}

/// Completes the given [request] by writing the [response] as JSON.
Response _sendJson(Object response) => _sendResponse(
HttpStatus.ok,
type: ContentType.json,
bytes: _jsonEncoder.convert(response),
);

/// Completes the given [request] by writing the [response] as plain text.
Response _sendText(String response) => _sendResponse(
HttpStatus.ok,
type: ContentType.text,
bytes: utf8.encode(response),
);

/// Responds with the JSON test to the [request].
Response _jsonTest() => _sendJson(const {'message': 'Hello, World!'});

/// Responds with the plaintext test to the [request].
Response _plaintextTest() => _sendText('Hello, World!');

final _jsonEncoder = JsonUtf8Encoder();
7 changes: 7 additions & 0 deletions frameworks/Dart/shelf/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
name: shelfbenchmark
description: A benchmark of pkg:shelf
environment:
sdk: ^3.8.0

dependencies:
shelf: ^1.0.0
14 changes: 14 additions & 0 deletions frameworks/Dart/shelf/shelf.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

FROM dart:3.8 AS builder

COPY . /app
WORKDIR /app
RUN mkdir build
RUN dart compile exe ./bin/server.dart -o build/server

FROM scratch
COPY --from=builder /runtime/ /
COPY --from=builder /app/build /bin

EXPOSE 8080
CMD ["server"]
Loading