APIs con Dart Frog

Crea APIs RESTful profesionales con el framework minimalista de Dart

Descargar Ejemplos Completos

¿Qué es Dart Frog?

Dart Frog es un framework minimalista para construir backends en Dart. Es rápido, eficiente y sigue las mejores prácticas para crear APIs RESTful modernas. Perfecto para microservicios y aplicaciones que necesitan un backend ligero pero potente.

Rápido y Ligero

Minimalista y optimizado para máximo rendimiento

API First

Diseñado específicamente para crear APIs RESTful

Sistema de Rutas

Estructura basada en archivos para definir rutas

Estructura de Archivos

routes/
products/
shirts/
index.dart
shoes/
index.dart
[id].dart Parámetro
index.dart
users/
admin/
[id].dart
_middleware.dart Middleware
index.dart

Cómo funciona el sistema de rutas:

Carpetas = Rutas

Cada carpeta dentro de routes/ se convierte en una ruta de la API.

Archivos = Endpoints

Los archivos index.dart manejan las solicitudes a esa ruta.

[parámetro].dart

Archivos con corchetes capturan parámetros dinámicos en la URL.

_middleware.dart

Middleware que se ejecuta antes de las rutas en esa carpeta.

Ejemplos de rutas generadas:

GET /products → routes/products/index.dart
GET /products/123 → routes/products/[id].dart
GET /products/shirts → routes/products/shirts/index.dart
POST /users → routes/users/index.dart
GET /users/admin/456 → routes/users/admin/[id].dart

Middleware: Autenticación y Validación

Los middleware en Dart Frog permiten interceptar y modificar solicitudes antes de que lleguen a los handlers. Son ideales para:

Autenticación

Validar API keys, tokens JWT, etc.

Validación

Verificar datos de entrada

Logging

Registrar solicitudes y respuestas

Transformación

Modificar solicitudes/respuestas

Middleware de Autenticación:

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);
  };
}

Flujo del Middleware:

1
Solicitud HTTP llega

Cliente envía solicitud con/sin API key

2
Middleware intercepta

Verifica headers y API key

3
Validación

Si es válida → pasa al handler

Si no es válida → respuesta de error

Handler Principal: Manejo de Métodos HTTP

El archivo index.dart en cada ruta contiene la función onRequest que maneja todas las solicitudes HTTP a esa ruta.

GET

Obtener recursos

Lectura

POST

Crear recursos

Creación

PUT

Actualizar recursos

Actualización

DELETE

Eliminar recursos

Eliminación

Handler para la ruta raíz:

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'
      );
  }
}

Probador de API Interactivo

JSON válido

Respuesta de la API

Estado: 200 OK Tiempo: 0ms
{
  "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í

Ejemplo Completo: API de Productos

CRUD Completo para Productos:

GET /products Listar todos los productos
GET /products/{id} Obtener un producto específico
POST /products Crear un nuevo producto
PUT /products/{id} Actualizar un producto
DELETE /products/{id} Eliminar un producto

Código del Handler:

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);
  }
}

Parámetros y Consultas

Parámetros de Ruta

Capturan valores directamente de la URL

/products/[id].dart context.params['id']

Parámetros de Consulta

Valores opcionales después del ? en la URL

/products?categoria=shirts&orden=precio context.request.uri.queryParameters

Cuerpo de la Solicitud

Datos enviados en POST/PUT

{ "nombre": "Producto", "precio": 100 } await context.request.json()

Manejando todos los tipos de parámetros:

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
  }));
}

Buenas Prácticas

Validación de Entrada

Siempre valida y sanitiza los datos recibidos antes de procesarlos.

Manejo de Errores

Usa códigos HTTP apropiados y mensajes de error claros.

Documentación

Documenta tu API con OpenAPI/Swagger para facilitar su uso.

Separación de Responsabilidades

Separa lógica de negocio, acceso a datos y handlers.

Ejercicios para Practicar

Ejercicio 1: API de Blog

Crea una API para un blog con posts, comentarios y autores.

Requisitos:

  • GET /posts - Listar todos los posts
  • GET /posts/{id} - Obtener un post específico
  • POST /posts - Crear un nuevo post (con middleware de autenticación)
  • GET /posts/{id}/comments - Comentarios de un post

Ejercicio 2: Carrito de Compras

Implementa un carrito de compras con productos y usuarios.

Requisitos:

  • Middleware para identificar usuarios por token
  • GET /cart - Ver carrito del usuario
  • POST /cart/items - Añadir producto al carrito
  • DELETE /cart/items/{id} - Remover producto
  • POST /cart/checkout - Finalizar compra

Ejercicio 3: API con Búsqueda Avanzada

Crea una API con filtros, ordenación y paginación.

Requisitos:

  • GET /products?categoria=ropa&minPrecio=10&maxPrecio=100
  • Parámetros: page, limit, sort, order
  • Respuesta con metadata: total, page, totalPages
  • Cache con headers ETag y Last-Modified

Recursos Adicionales

Documentación Oficial

Dart Frog Documentation

Repositorio GitHub

VeryGoodOpenSource/dart_frog

Tutoriales en Video

YouTube Tutorials

Ejemplos Completos

Ejemplos oficiales