Skip to content

Commit 3fc9e74

Browse files
committed
Add Dockerfiles, API, and frontend for TODO application with shared layers
1 parent eaf01f3 commit 3fc9e74

File tree

12 files changed

+699
-0
lines changed

12 files changed

+699
-0
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#Imagen que voy a utilizar como base
2+
FROM nginx:bookworm
3+
4+
# #Etiquetado
5+
LABEL maintainer="gisela.torres@returngis.net"
6+
LABEL project="lemoncode"
7+
8+
# #Como metadato, indicamos que el contenedor utiliza el puerto 80
9+
EXPOSE 80
10+
11+
#Modificaciones sobre la imagen que he utilizado como base, en este caso alpine
12+
COPY web/ /usr/share/nginx/html/
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
En este ejemplo tenemos dos aplicaciones que comparten varias instrucciones/capas de sus Dockerfile, lo cual optimiza el tamaño de las imágenes y el tiempo de construcción.
2+
3+
## Comprobar qué capas se comparten
4+
5+
Puedes usar el comando `docker image inspect` para ver las capas de cada imagen y comprobar cuáles se comparten.
6+
7+
```bash
8+
docker image inspect 0gis0/frontend --format='{{json .RootFS.Layers}}' | jq
9+
docker image inspect 0gis0/backend --format='{{json .RootFS.Layers}}' | jq
10+
```
11+
12+
Con jq puedes formatear la salida para que sea más legible y también que de solo las capas que son iguales entre ambas imágenes:
13+
14+
```bash
15+
docker image inspect 0gis0/frontend --format='{{json .RootFS.Layers}}' | jq '.[ ]' > frontend_layers.txt
16+
docker image inspect 0gis0/backend --format='{{json .RootFS.Layers}}' | jq '.[ ]' > backend_layers.txt
17+
comm -12 <(sort frontend_layers.txt) <(sort backend_layers.txt)
18+
```
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Usar imagen base oficial de PHP con Apache
2+
FROM php:8.2-apache
3+
4+
# Establecer el directorio de trabajo
5+
WORKDIR /var/www/html
6+
7+
# Instalar extensiones PHP necesarias
8+
RUN apt-get update && apt-get install -y \
9+
curl \
10+
git \
11+
&& rm -rf /var/lib/apt/lists/*
12+
13+
# Habilitar módulo de reescritura (mod_rewrite) de Apache
14+
RUN a2enmod rewrite
15+
16+
# Copiar archivos de la API
17+
COPY api.php .
18+
19+
# Configurar Apache para servir desde el directorio correcto
20+
RUN echo '<Directory /var/www/html>\n\
21+
AllowOverride All\n\
22+
Require all granted\n\
23+
</Directory>' > /etc/apache2/conf-available/html.conf && \
24+
a2enconf html
25+
26+
# Exponer puerto 80
27+
EXPOSE 80
28+
29+
# Comando por defecto
30+
CMD ["apache2-foreground"]
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Backend - API REST en PHP
2+
3+
Servidor PHP super básico que expone una API REST con datos de ejemplo.
4+
5+
## 📋 Descripción
6+
7+
Este backend proporciona un único endpoint GET que retorna una lista de TODOs en formato JSON.
8+
9+
## 🔧 Configuración
10+
11+
- **Lenguaje:** PHP
12+
- **Tipo:** API REST
13+
- **Formato:** JSON
14+
- **CORS:** Habilitado
15+
16+
## 📡 Endpoints
17+
18+
### GET /backend/api.php
19+
20+
Retorna todos los TODOs disponibles.
21+
22+
**Ejemplo de solicitud:**
23+
```bash
24+
curl http://localhost:8000/backend/api.php
25+
```
26+
27+
**Respuesta exitosa (200):**
28+
```json
29+
{
30+
"exito": true,
31+
"mensaje": "Todos obtenidos correctamente",
32+
"datos": [
33+
{
34+
"id": 1,
35+
"titulo": "Aprender PHP",
36+
"completado": false,
37+
"fecha": "2025-10-23"
38+
},
39+
{
40+
"id": 2,
41+
"titulo": "Crear una API REST",
42+
"completado": true,
43+
"fecha": "2025-10-22"
44+
}
45+
],
46+
"cantidad": 4
47+
}
48+
```
49+
50+
**Respuesta de error (404):**
51+
```json
52+
{
53+
"exito": false,
54+
"mensaje": "Endpoint no encontrado"
55+
}
56+
```
57+
58+
## 🚀 Requisitos
59+
60+
- PHP 7.0 o superior
61+
62+
## 🎯 Características
63+
64+
- ✅ Retorna todos los TODOs
65+
- ✅ CORS habilitado
66+
- ✅ Respuestas en formato JSON
67+
- ✅ Datos de ejemplo incluidos
68+
- ✅ Manejo de preflight requests (OPTIONS)
69+
70+
## 📝 Datos de ejemplo
71+
72+
El backend viene con 4 TODOs de ejemplo:
73+
1. Aprender PHP
74+
2. Crear una API REST (completado)
75+
3. Conectar frontend con backend
76+
4. Deployar la aplicación
77+
78+
---
79+
80+
Para iniciar el servidor, ver el README principal.
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
// Habilitar CORS para que el frontend pueda acceder al backend
3+
header('Access-Control-Allow-Origin: *');
4+
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
5+
header('Access-Control-Allow-Headers: Content-Type');
6+
header('Content-Type: application/json; charset=utf-8');
7+
8+
// Manejo de preflight requests
9+
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
10+
http_response_code(200);
11+
exit();
12+
}
13+
14+
// Datos de ejemplo
15+
$todos = [
16+
[
17+
'id' => 1,
18+
'titulo' => 'Aprender PHP',
19+
'completado' => false,
20+
'fecha' => '2025-10-23'
21+
],
22+
[
23+
'id' => 2,
24+
'titulo' => 'Crear una API REST',
25+
'completado' => true,
26+
'fecha' => '2025-10-22'
27+
],
28+
[
29+
'id' => 3,
30+
'titulo' => 'Conectar frontend con backend',
31+
'completado' => false,
32+
'fecha' => '2025-10-24'
33+
],
34+
[
35+
'id' => 4,
36+
'titulo' => 'Deployar la aplicación',
37+
'completado' => false,
38+
'fecha' => '2025-10-25'
39+
]
40+
];
41+
42+
// Obtener la ruta solicitada
43+
$metodo = $_SERVER['REQUEST_METHOD'];
44+
$ruta = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
45+
46+
// Limpiar la ruta de posibles prefijos
47+
$ruta = str_replace('/backend/api.php', '', $ruta);
48+
$ruta = str_replace('/api.php', '', $ruta);
49+
50+
// Endpoint: GET / - Obtener todos los todos
51+
if ($metodo === 'GET' && ($ruta === '' || $ruta === '/')) {
52+
http_response_code(200);
53+
echo json_encode([
54+
'exito' => true,
55+
'mensaje' => 'Todos obtenidos correctamente',
56+
'datos' => $todos,
57+
'cantidad' => count($todos)
58+
]);
59+
exit();
60+
}
61+
62+
// Si no coincide con ninguna ruta
63+
http_response_code(404);
64+
echo json_encode([
65+
'exito' => false,
66+
'mensaje' => 'Endpoint no encontrado'
67+
]);
68+
?>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
"sha256:d7c97cb6f1fe7cae982649e9f55efe201212e8acaa64bd668c083b204e4efd4c"
2+
"sha256:ae5f201183dbad64f6cc302e4f3cbe1631529e75bbd3438b29004197698eed73"
3+
"sha256:6152641e004d65c844fe296b05f65b27674a8db647503875ed8b6151383941f3"
4+
"sha256:7992b7545938df04cf15070f4364ca01cd141a7df80522e08d2e6ca58755c6d6"
5+
"sha256:b4cec1dfa57267f059bfa56e30782e04358cfe2562cb9e2b47886f685f0c4a28"
6+
"sha256:c96a1dc6a21ae8191a98077130d6bf77f66be1db61db13b8031c79aa91f97bc8"
7+
"sha256:fd1bbe7544297db8429c71ba0661a60f5148b242fab42847956b1521bc8d53ce"
8+
"sha256:742ee7baa3671863ee06fefce6c23e3b7128666c507f9e4f270fda07e20b48e0"
9+
"sha256:4acaad2ebdc4df6d02e6216a2991d6482560a3d2c1ad7b541e02dcd4466542a9"
10+
"sha256:67f46396f19fec7213b6497523b0b48f9d68687eebfe2aa427153579e23a1dbc"
11+
"sha256:38c58821ee91f68cc07284631208aa5c09d7c71709e26a67dc817b59a350e09c"
12+
"sha256:54df1209902298870ffde1016be6fd297795b187ea5e9519f083e92c1bbae8d3"
13+
"sha256:20c2bc43f2409a629660811f3bb2140017ce22aa5c40cb3a56903ec05a757565"
14+
"sha256:eb2dd4f2bdd8dccdb8deab2fbc8326dd44bf89f0a756a10c574026158038b4f3"
15+
"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef"
16+
"sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef"
17+
"sha256:2ee9c2f89241538d18c1966d8cd41101704bfe73a56bb94b1e0d43647b1d3242"
18+
"sha256:e539ce9085dabd953af44fa2f5872afdf07e547e92fc02de69421c6816c2fc4a"
19+
"sha256:9e021caad588a31f0afa1bd07a369cab4c1d47b7645dfc688f6c88bcd531cc3f"
20+
"sha256:ccde09e382c023c6d0ec196fee306b57cf39f4b6fef4eb13373102ccbfabf8c2"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<IfModule mod_rewrite.c>
2+
RewriteEngine On
3+
RewriteBase /
4+
5+
# Redirigir / a index.php
6+
RewriteCond %{REQUEST_FILENAME} !-f
7+
RewriteCond %{REQUEST_FILENAME} !-d
8+
RewriteRule ^(.*)$ index.php [QSA,L]
9+
</IfModule>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Usar imagen base oficial de PHP con Apache
2+
FROM php:8.2-apache
3+
4+
# Establecer el directorio de trabajo
5+
WORKDIR /var/www/html
6+
7+
# Instalar extensiones PHP necesarias
8+
RUN apt-get update && apt-get install -y \
9+
curl \
10+
git \
11+
&& rm -rf /var/lib/apt/lists/*
12+
13+
# Habilitar módulo de reescritura (mod_rewrite) de Apache
14+
RUN a2enmod rewrite
15+
16+
# Copiar archivos del frontend
17+
COPY index.php .
18+
COPY styles.css .
19+
COPY app.js .
20+
21+
# Configurar Apache para servir desde el directorio correcto
22+
RUN echo '<Directory /var/www/html>\n\
23+
AllowOverride All\n\
24+
Require all granted\n\
25+
</Directory>' > /etc/apache2/conf-available/html.conf && \
26+
a2enconf html
27+
28+
# Exponer puerto 80
29+
EXPOSE 80
30+
31+
# Comando por defecto
32+
CMD ["apache2-foreground"]
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Frontend - Aplicación de TODOs en PHP
2+
3+
Interfaz web en PHP que consume la API REST del backend.
4+
5+
## 📋 Descripción
6+
7+
Frontend construido con **PHP + HTML5 + CSS3** que consume la API del backend para mostrar una lista de TODOs.
8+
9+
## 📁 Estructura
10+
11+
- **index.php** - Código PHP principal que renderiza el HTML y consume la API
12+
- **styles.css** - Estilos CSS (diseño responsivo)
13+
- **app.js** - JavaScript adicional (si es necesario, puede ser opcional)
14+
15+
## 🎨 Características
16+
17+
- 📊 Mostrar estadísticas (total, completadas, pendientes)
18+
- 🔄 Botón para actualizar la lista (recarga la página)
19+
- 📱 Diseño responsivo (mobile-friendly)
20+
- 🎯 Interfaz moderna con gradientes
21+
- ⚠️ Manejo de errores visual
22+
- 💫 Animaciones suaves
23+
- **✅ Renderizado en servidor (PHP)**
24+
25+
## 🚀 Requisitos
26+
27+
- PHP 7.0 o superior
28+
- Backend accesible en `http://localhost:8001/api.php` (host)
29+
- Frontend expuesto en `http://localhost:8000`
30+
31+
## 🔧 Configuración
32+
33+
La URL de la API está configurada y autodetecta entorno en `index.php`:
34+
35+
```php
36+
// Por defecto dentro de Docker:
37+
$api_url = 'http://host.docker.internal:8001/api.php';
38+
39+
// Si corre fuera de Docker (PHP built-in server):
40+
if (php_sapi_name() === 'cli-server' || strpos($_SERVER['HTTP_HOST'], 'localhost') === 0) {
41+
$api_url = 'http://localhost:8001/api.php';
42+
}
43+
```
44+
45+
`host.docker.internal` permite que el contenedor acceda al backend expuesto por el host en macOS y Windows. En Linux puede requerir configuración adicional.
46+
47+
## 📝 Flujo de la aplicación
48+
49+
1. Al acceder a `index.php`, PHP realiza una petición GET al backend
50+
2. Se procesan los datos recibidos en servidor
51+
3. Se renderiza el HTML con los datos
52+
4. El usuario ve la lista de TODOs
53+
5. Al hacer clic en "Actualizar", se recarga la página y se repite el proceso
54+
55+
## 🎯 Ventajas de usar PHP para el frontend
56+
57+
- ✅ Renderizado en servidor (SSR)
58+
- ✅ No requiere JavaScript en cliente
59+
- ✅ SEO friendly (contenido generado en servidor)
60+
- ✅ Comparte la imagen base `php:8.2-apache` con el backend
61+
- ✅ Reutiliza las mismas capas de Docker
62+
63+
## 📱 Responsive Design
64+
65+
La aplicación se adapta a diferentes tamaños de pantalla:
66+
- Desktop: Grid de 3 columnas para estadísticas
67+
- Mobile: Grid de 1 columna para mejor legibilidad
68+
69+
## 🐛 Debugging
70+
71+
Para ver información de depuración, añade esto en PHP:
72+
```php
73+
ini_set('display_errors', 1);
74+
error_reporting(E_ALL);
75+
```
76+
77+
---
78+
79+
Para iniciar la aplicación, ver el README principal.

0 commit comments

Comments
 (0)