---
# System prepended metadata

title: Documentación Marvel API

---

# Documentación Marvel API

Puntos principales:

## IndexController:
```php=
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class IndexController extends Controller
{
/* Alojamos los datos de la conexión fuera de las funciones.*/
        var $url = 'https://gateway.marvel.com:443/v1/public/';
        public function index($offset=0) {
            $url = $this->url .'characters?offset='. $offset.'&';
            $result = json_decode($this->makeRequest($url));
            if(!isset($result->data)) {
                abort(404);
            }
            $total = $result->data->total;
            $result = $result->data->results;
            return view('index', ['result'=>$result, 'offset'=>$offset, 'total'=>$total]);
        }

    Credenciales de acceso a la API de marvel
    public function generateURL($url) {
        $public_key = 'ec8a1fb650d39076b1e3ce57e88fe2a9';
        $private_key = 'fe05b324befc6b4d39b5611424a45581295269d6';

        $ts= time();
        $hash = md5($ts.$private_key.$public_key);

        return $url . 'apikey='. $public_key. '&ts='.$ts.'&hash='.$hash;
    }
    Request a la api de marvel
    public function makeRequest($url) {
        $curl = curl_init();

        $data_url = $this->generateURL($url);

        curl_setopt_array($curl, [
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_URL => $data_url
        ]);

        $response = curl_exec($curl);
        curl_close($curl);

        return $response;
    }
    /*Función que muestra un personaje individual*/
    public function show($id)
    {
        $url = $this->url . 'characters/' . $id . '?'; // URL para obtener detalles de un personaje específico
        $characterData = json_decode($this->makeRequest($url));

        // Verifica si se obtuvo la información del personaje
        if (!isset($characterData->data) || !isset($characterData->data->results[0])) {
            return redirect()->route('index')->with('error', 'Detalles del personaje no encontrados');
        }

        $character = $characterData->data->results[0];

        return view('show', compact('character'));
    }
    /*Función que se encarga de la búsqueda y filtrado de personajes*/
    public function filterCharacters(Request $request)
    {
        $nameFilter = $request->input('name');
        $letterFilter = $request->input('filter');
    
        $url = $this->url . 'characters?';
        
        if ($nameFilter) {
            $url .= 'nameStartsWith=' . $nameFilter . '&';
        }
    
        if ($letterFilter) {
            $url .= 'nameStartsWith=' . $letterFilter . '&';
        }
    
        $result = json_decode($this->makeRequest($url));
    
        if (!isset($result->data)) {
            abort(404);
        }
    
        $characters = $result->data->results;
    
        return view('filtered-characters', compact('characters'));
    }
    
}

```
## Plantilla del header
```php=
<!DOCTYPE html>
<html lang="en">
<style>
.header-container {
    background-color: rgba(255, 255, 255, 0.5);
    
}

</style>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
    <link href="https://fonts.googleapis.com/css2?family=Rajdhani&display=swap" rel="stylesheet">
    <link rel="stylesheet" href="{{asset('css/index.css')}}">

    <title>ChupiMarvel</title>
</head>
<body>
    <div class="container header-container">
        <div class="show">
            <a href="{{route('index')}}">
                <img 
                src="https://designconceitual.com.br/wp-content/uploads/2016/07/Marvel_Studios_logo.svg_.png" 
                style="width: 250px;margin:0 auto;padding: 10px 10px 10px 10px"
                alt="">
            </a>
        </div>
```

## Index (página principal)

```php=
@include('layouts.header')

<style>
    body {
      /*  La imagen del background viene dada por una URL porque soy un mal programador.*/
        background-image: url('https://external-preview.redd.it/x_BaPYAxk2f_G9g52hcWIThT0hoanye9zcjJJweFZkg.jpg?width=640&crop=smart&auto=webp&s=849263ee6ecbc498e87da055cad359206cc77190');
        background-size: cover;
        background-repeat: no-repeat;
        background-attachment: fixed;
        color: #fff;
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }

    .main-container {
        margin: 2%;
    }

    .card {
        background-color: rgba(0, 0, 0, 0.7);
        color: #fff;
        margin-bottom: 15px;
    }
    form {
        color:black;
    }
</style>

<div class="main-container">
    <div class="show">
        <h1 style="color:black;"> LISTA DE PERSONAJES </h1>
        
          /*  El form es la parte con más chicha del index, ya que se encarga de la búsqueda de personajes haciendo consultas a la Api porque, de nuevo, soy mal programador.*/
    </div>
    
 
    <form action="{{ route('filterCharacters') }}" method="GET" class="form-group" style="width: 80%; margin: 0 auto;">
        <label for="name">Buscar por nombre:</label>
        <input type="text" name="name" class="form-control" style="width: 80%;" placeholder="Busca tu personaje..." value="{{ request('name') }}">
        
        <label for="filter">Filtrar por letra:</label>
        <select name="filter" class="form-control">
            <option value="" {{ request('filter') === '' ? 'selected' : '' }}>Sin filtro</option>
            @foreach(range('A', 'Z') as $letter)
                <option value="{{ $letter }}" {{ request('filter') === $letter ? 'selected' : '' }}>{{ $letter }}</option>
            @endforeach
        </select>
    ¿Sabes por qué he puesto el botón de búsqueda y filtrado en el mismo? Exacto.
        <button type="submit" class="btn btn-light btn-sm" style="margin: 5px;">Filtrar y buscar</button>
    </form>
    
    <div class="show"> 

        <div class="row">
            @foreach ($result as $r)
                <div class='col-md-3'>
                    <div class='card d-flex flex-column'>
                        <img src="{{ $r->thumbnail->path.'.'.$r->thumbnail->extension }}" class="card-img-top" alt="{{ $r->name }}">
                        <div class='card-body'>
                            <h4 class='card-title'>{{ $r->name }}</h4>
                            <a href="{{ route('character.show', $r->id) }}" class="btn btn-danger btn-sm">Ver más</a>
                        </div>
                    </div>
                </div>
            @endforeach  
        </div>
    </div>
    Botones de paginación. No funcionan muy bien, no sé si por el código en sí o porque la API no me da suficiente recursos para paginar. Avisado estás.
    <div class="buttons">
        @if($offset != 0)
            <a href="{{ route('index', $offset - 20) }}" class="btn btn-light">Anterior</a>
        @endif

        @if($total >= $offset + 20)
            <a href="{{ route('index', $offset + 20) }}" class="btn btn-light" style="margin:2%;">Próximo</a>
        @endif
    </div>
</div>

</body>
</html>

```

## Show (página de personajes individuales)

```php=
@include('layouts.header')

<style>
    body {
        margin: 2%;
        position: relative;
    }

    .background-container::before {
        content: "";
        background: url('https://external-preview.redd.it/x_BaPYAxk2f_G9g52hcWIThT0hoanye9zcjJJweFZkg.jpg?width=640&crop=smart&auto=webp&s=849263ee6ecbc498e87da055cad359206cc77190') center center;
        background-size: cover;
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        z-index: -1;
        opacity: 0.5;
    }

    .main-container {
        height: 100vh; /* Ajustar la altura al 100% de la ventana */
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .show {
        color: #fff;
        margin-bottom: 2%;
    }

    .card {
        background-color: rgba(0, 0, 0, 0.7);
        color: #fff;
        height: 100%; /* Ocupar el 100% de la altura del contenedor */
        display: flex;
        flex-direction: column;
        justify-content: space-between; /* Ajustar el espacio entre elementos */
    }

    .comic-list {
        list-style-type: none;
        padding: 0;
    }
</style>

<div class="background-container">
    <div class="main-container">
        <div class='col-md-6'>
            <div class='card'>
                <img src="{{ $character->thumbnail->path.'.'.$character->thumbnail->extension }}" class="card-img-top" alt="{{ $character->name }}">
                <div class='card-body'>
                    <h4 class='card-title'>{{ $character->name }}</h4>                   /* Simplemente consultamos los datos de la API. */
                    <p class="card-text">{{ $character->description }}</p>
                    <p class="card-text"><strong>Número de cómics:</strong> {{ $character->comics->available }}</p>

                    <strong>Cómics:</strong>
                    <ul class="comic-list">
                        @foreach ($character->comics->items as $comic)
                            <li>{{ $comic->name }}</li>
                        @endforeach
                    </ul>

                    <a href="{{ route('index') }}" class="btn btn-danger btn-sm">Volver a la Lista</a>
                </div>
            </div>
        </div>
    </div>
</div>

</body>
</html>

```
## Vista de filtrado: 
```php=
@include('layouts.header')

<style>
    body {
        background-image: url('https://external-preview.redd.it/x_BaPYAxk2f_G9g52hcWIThT0hoanye9zcjJJweFZkg.jpg?width=640&crop=smart&auto=webp&s=849263ee6ecbc498e87da055cad359206cc77190');
        background-size: cover;
        background-repeat: no-repeat;
        background-attachment: fixed;
        color: #fff;
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }

    .main-container {
        margin: 2%;
    }

    .card {
        background-color: rgba(0, 0, 0, 0.7);
        color: #fff;
        height: 100%;
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        margin-bottom: 15px;
        padding: 15px;
    }

    .filtered-cards-container {
        display: flex;
        flex-wrap: wrap;
        justify-content: space-between;
    }

    .filtered-card-wrapper {
        width: 23%;
        margin-bottom: 20px;
    }

    .btn-ver-mas {
        margin-top: 10px;
    }
</style>

<div class="background-container">
    <div class="main-container">
        <h1 class="show">Resultados del Filtro</h1>

        <div class="filtered-cards-container">
            @foreach ($characters as $character)
                <div class='filtered-card-wrapper'>
                    <div class='card'>
                        <img src="{{ $character->thumbnail->path.'.'.$character->thumbnail->extension }}" class="card-img-top" alt="{{ $character->name }}">
                        <div class='card-body'>
                            <h4 class='card-title'>{{ $character->name }}</h4>
                        </div>
                        <a href="{{ route('character.show', $character->id) }}" class="btn btn-danger btn-sm btn-ver-mas">Ver más</a>
                    </div>
                </div>
            @endforeach
        </div>
    </div>
</div>

</body>
</html>

```


## WEB (rutas)

```php=
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\IndexController;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/

/* Solo hay 3 rutas, la del index, la del show y la de filtrado. */
Route::get('/index', [IndexController::class, 'index'])->name('index');
Route::get('/filter-characters', [IndexController::class, 'filterCharacters'])->name('filterCharacters');
Route::get('/personajes/{id}', [IndexController::class, 'show'])->name('character.show');
```