h4 0.4.2
h4: ^0.4.2 copied to clipboard
A ligthweight, loosely opinionated http framework for dart.
[og]
A lightweight web framework for dart
Heavily inspired by unjs H(3)'s' API. Composable utilities, functional styles and simple interface.
This is a new project under active development, there are tests, but it could break in unexpected ways.
Feedback is welcome.
The official documentation is a WIP - link
Getting Started #
Add H4 to your pubspec.yaml:
dependencies:
h4: 0.4.1
Or install with dart pub get
dart pub add h4
Import the library and start building your server:
import 'package:h4/create.dart';
void main() {
var app = createApp();
var router = createRouter();
app.use(router);
router.get("/", (event) => "Hello world!");
}
Examples #
Hello world #
void main() {
var app = createApp(port: 4000);
var router = createRouter();
app.use(router);
router.get("/", (event) => "Hello world")
}
Global Hooks #
Register application-wide hooks:
onRequestonErrorafterResponse
These hooks are called for every request and can be used to add global logic to your app such as logging, error handling, etc.
var app = createApp(
port: 5173,
onRequest: (event) => {},
onError: (error, stacktrace, event) => {},
afterResponse: (event) => {},
);
var router = createRouter();
app.use(router);
Param Routing #
You can define parameters in your routes using : prefix:
router.get('/users/:id', (event) {
final userId = event.params['id'];
return 'User with id: $userId'
});
Wildcard Routing #
// Matches 'articles/page' and '/articles/otherPage' but not 'articles/page/subPage'
router.get('/articles/*', (event) {
final path = event.path;
return 'The tea is teaing!!'
});
// Matches 'articles/foo/bar' and 'articles/page/subPage/subSubPage'
router.get('/articles/**', (event) {
final path = event.path;
return 'The tea is teaing!!'
});
Error Handling #
A special CreateError exception can be called that will terminate the request and send a 400 - Bad
Request response
Advanced Examples #
Here's an enhanced examples section for the README.md:
Advanced Examples #
Multiple Routers with Base Paths #
Organize your routes by creating multiple routers with different base paths:
void main() {
var app = createApp(port: 3000);
var mainRouter = createRouter();
var apiRouter = createRouter();
// Mount routers with different base paths
app.use(mainRouter, basePath: '/');
app.use(apiRouter, basePath: '/api');
// Main routes
mainRouter.get('/hello', (event) => {'message': 'Hello World'});
// API routes
apiRouter.get('/users', (event) => ['user1', 'user2']);
apiRouter.post('/auth', (event) async {
var body = await readRequestBody(event);
return body;
});
}
Request Context & Headers #
Store request-specific data and handle headers:
void main() {
var app = createApp(
port: 3000,
onRequest: (event) {
// Store data in request context
event.context["userId"] = "123";
// Set CORS headers
handleCors(event, origin: "https://myapp.com", methods: "GET,POST");
},
afterResponse: (event) {
print("Response sent with status: ${event.statusCode}");
}
);
}
File Uploads #
Handle file uploads:
void main() {
var app = createApp(port: 3000);
var router = createRouter();
app.use(router);
router.post("/upload", (event) async {
var files = await readFiles(
event,
// Formdata field where your files are stored
fieldName: 'file',
// Optional: Set custom directory for uploaded files. (defaults to temp dir)
customFilePath: 'uploads',
// Optional: Hash filenames for security (defaults to false)
// When false, files are prefixed with a naive hash.
hashFileName: true,
// Optional: Set max file size in MB (defaults to 10MB)
maxFileSize: 5
);
// Returned File obj contains: path, size, originalname, mimeType
return {
'message': 'Upload complete',
'files': files
};
});
}
Form Data Processing #
Handle multipart form data with ease:
void main() {
var app = createApp(port: 3000);
var router = createRouter();
app.use(router);
router.post("/signup", (event) async {
var formData = await readFormData(event);
// Access form fields
var username = formData.get('username');
var password = formData.get('password');
// Get multiple values
var interests = formData.getAll('interests');
return {
'user': username,
'interests': interests
};
});
}
Error Handling with Custom Responses #
Implement robust error handling:
void main() {
var app = createApp(
port: 3000,
onError: (error, stacktrace, event) {
print("Error occurred: $error");
}
);
var router = createRouter();
app.use(router);
router.get("/risky-operation", (event) async {
try {
// Potentially failing operation
throw Exception("Something went wrong");
} catch (e) {
throw CreateError(
message: "Operation failed: $e",
errorCode: 400
);
}
});
}
The client will recieve a JSON payload -
{
"status": 400,
"message": "Operation failed {error Message}"
}
For more detailed implementations and utilities, check out the official documentation.
Contributing #
A great first PR would be improve the test coverage of this library, or adding a helpful util, for inspiration see here.
Running tests #
In the root directory run
dart test
Code of Conduct. #
Be cool and calm.