APIs with Dart Frog
Build professional RESTful APIs with Dart's minimalist framework
Download Complete ExamplesWhat is Dart Frog?
Dart Frog is a minimalist framework for building backends in Dart. It's fast, efficient, and follows best practices for building modern RESTful APIs. Perfect for microservices and applications that need a lightweight yet powerful backend.
Fast and Lightweight
Minimalist and optimized for maximum performance
API First
Specifically designed for building RESTful APIs
Routing System
File-based structure for defining routes
File Structure
How the routing system works:
Folders = Routes
Each folder inside routes/ becomes an API route.
Files = Endpoints
The index.dart files handle requests to that route.
[parameter].dart
Files with brackets capture dynamic parameters in the URL.
_middleware.dart
Middleware that runs before the routes in that folder.
Examples of generated routes:
Middleware: Authentication and Validation
Middleware in Dart Frog lets you intercept and modify requests before they reach the handlers. It's ideal for:
Authentication
Validating API keys, JWT tokens, etc.
Validation
Verifying input data
Logging
Logging requests and responses
Transformation
Modifying requests/responses
Authentication Middleware:
import 'dart:json';
import 'package:dart_frog/dart_frog.dart';
Handler middleware(Handler next) {
return (context) async {
final apikey = context.request.headers['apikey'];
if (apikey == null || apikey != '123456') {
return Response(body: jsonEncode({'error': 'Apikey no válida'}));
}
return await next(context);
};
}
Middleware Flow:
HTTP Request Arrives
Client sends a request with/without an API key
Middleware Intercepts
Verifies headers and API key
Validation
If valid → passes to the handler
If invalid → error response
Main Handler: HTTP Method Handling
The file index.dart file in each route contains the onRequest function that handles all HTTP requests to that route.
GET
Retrieve resources
ReadingPOST
Create resources
CreationPUT
Update resources
ActualizaciónDELETE
Delete resources
EliminaciónHandler for the root route:
import 'dart:json';
import 'package:dart_frog/dart_frog.dart';
Future<Response> onRequest(RequestContext context) async {
switch (context.request.method) {
case HttpMethod.get:
return Response(body: jsonEncode({
'método': 'GET',
'ruta': '/',
'mensaje': 'Bienvenido a la API'
}));
case HttpMethod.post:
final body = await context.request.json();
return Response(body: jsonEncode({
'método': 'POST',
'datos_recibidos': body,
'estado': 'creado'
}));
case HttpMethod.put:
return Response(body: jsonEncode({
'método': 'PUT',
'mensaje': 'Recurso actualizado'
}));
case HttpMethod.delete:
return Response(body: jsonEncode({
'método': 'DELETE',
'mensaje': 'Recurso eliminado'
}));
default:
return Response(
statusCode: 405,
body: 'Método no permitido'
);
}
}
Interactive API Tester
API Response
{
"status": "esperando solicitud..."
}
Content-Type: application/json
Server: Dart Frog
// El código Dart se generará aquí// basado en tu solicitud
# El comando cURL se generará aquí
Complete Example: API expression in Products
Complete CRUD for Products:
Handler Code:
import 'dart:json';
import 'package:dart_frog/dart_frog.dart';
Future<Response> onRequest(RequestContext context) async {
// Obtener parámetros de ruta
final id = context.params['id'];
switch (context.request.method) {
case HttpMethod.get:
if (id != null) {
// GET /products/123
return Response(body: jsonEncode({
'id': id,
'nombre': 'Producto ' + id,
'precio': 99.99
}));
} else {
// GET /products
return Response(body: jsonEncode([
{'id': 1, 'nombre': 'Camisa', 'precio': 29.99},
{'id': 2, 'nombre': 'Pantalón', 'precio': 49.99}
]));
}
case HttpMethod.post:
final body = await context.request.json();
return Response(
statusCode: 201,
body: jsonEncode({
'id': 3,
'producto': body,
'estado': 'creado'
})
);
case HttpMethod.put:
final body = await context.request.json();
return Response(body: jsonEncode({
'id': id,
'producto': body,
'estado': 'actualizado'
}));
case HttpMethod.delete:
return Response(body: jsonEncode({
'id': id,
'estado': 'eliminado'
}));
default:
return Response(statusCode: 405);
}
}
Parameters and Queries
Route Parameters
Capture values directly from the URL
/products/[id].dart
→
context.params['id']
Query Parameters
Optional values after the ? in the URL
/products?categoria=shirts&orden=precio
→
context.request.uri.queryParameters
Request Body
Data sent in POST/PUT
{ "nombre": "Producto", "precio": 100 }
→
await context.request.json()
Handling all parameter types:
import 'dart:json';
import 'package:dart_frog/dart_frog.dart';
Future onRequest(RequestContext context) async {
// Parámetro de ruta final productId = context.params['id'];
// Parámetros de consulta final queryParams = context.request.uri.queryParameters;
final categoria = queryParams['categoria'];
final orden = queryParams['orden'] ?? 'nombre';
// Cuerpo de la solicitud (para POST/PUT) Map? body;
if (context.request.method == HttpMethod.post ||
context.request.method == HttpMethod.put) {
body = await context.request.json();
}
// Headers
final authHeader = context.request.headers['authorization'];
return Response(body: jsonEncode({
'id': productId,
'categoria': categoria,
'orden': orden,
'body': body,
'autenticado': authHeader != null
}));
}
Best Practices
Input Validation
Always validate and sanitize the received data before processing it.
Error Handling
Use appropriate HTTP status codes and clear error messages.
Documentation
Document your API with OpenAPI/Swagger to make it easier to use.
Separation of Concerns
Separate business logic, data access and handlers.
Exercises to Practice
Exercise 1: API for a Blog
Create an API for a blog with posts, comments and authors.
Requirements:
- GET /posts - List all posts
- GET /posts/{id} - Get a specific post
- POST /posts - Create a new post (with authentication middleware)
- GET /posts/{id}/comments - Comments on a post
Exercise 2: Shopping Cart
Implement a shopping cart with products and users.
Requisitos:
- Middleware to identify users by token
- GET /cart - View the user's cart
- POST /cart/items - Add product to the cart
- DELETE /cart/items/{id} - Remove product
- POST /cart/checkout - Complete purchase
Exercise 3: API with Advanced Search
Create an API with filters, sorting and pagination.
Requisitos:
- GET /products?categoria=ropa&minPrecio=10&maxPrecio=100
- Parameters: page, limit, sort, order
- Response with metadata: total, page, totalPages
- Cache with ETag and Last-Modified headers