diff --git a/design/open-api.yaml b/design/open-api.yaml
index 36c39d39133fb954e3ad6f9934a409b68ace2179..c07a91a2e7b522b99778b1f3e63d9ac730d5b1f3 100644
--- a/design/open-api.yaml
+++ b/design/open-api.yaml
@@ -2,32 +2,43 @@ openapi: "3.0.3"
 externalDocs:
   url: https://gitlab.utwente.nl/claudenirmf/mod4-wp-2023-2024-pokemon
 info:
-  title: Pokémon Trainer Database API
+  title: PokeApp API
   version: "1.0"
   license:
     name: Creative Commons Attribution 4.0 International (CC-BY-4.0)
     url: https://creativecommons.org/licenses/by/4.0/deed.en
-  description: The [Pokémon Trainer Database API](https://gitlab.utwente.nl/claudenirmf/mod4-wp-2023-2024-pokemon) is a REST API part of a sample web application designed to teach web development concepts at the [Data & Information module](https://www.utwente.nl/en/education/bachelor/programmes/technical-computer-science/study-programme/#modules-technical-computer-science) of the [Technical Computer Science](https://www.utwente.nl/en/education/bachelor/programmes/technical-computer-science/) program of the [University of Twente](https://utwente.nl/en).
+  description: The [PokeApp API](https://gitlab.utwente.nl/claudenirmf/mod4-wp-2023-2024-pokemon) is a REST API part of a sample web application designed to teach web development concepts at the [Data & Information module](https://www.utwente.nl/en/education/bachelor/programmes/technical-computer-science/study-programme/#modules-technical-computer-science) of the [Technical Computer Science](https://www.utwente.nl/en/education/bachelor/programmes/technical-computer-science/) program of the [University of Twente](https://utwente.nl/en).
   contact:
     name: Claudenir M. Fonseca
     url: https://gitlab.utwente.nl/claudenirmf/mod4-wp-2023-2024-pokemon/issues
     email: c.moraisfonseca@utwente.nl
 servers:
   - description: Local Deployment
-    url: http://localhost:8080/pokemon_war_exploded
+    url: http://localhost:8080/pokemon/api
 tags:
   - name: Trainer
     description: Routes for managing data about trainers.
   - name: Pokémon
     description: Routes for managing data about pokémon.
-  - name: Pokémon Type
-    description: Routes for managing data about pokémon types.
+#  - name: Pokémon Type
+#    description: Routes for managing data about pokémon types.
 paths:
   /trainers:
     get:
       description: Retrieves a collection of resources.
       tags:
         - Trainer
+      parameters:
+        - name: pageNumber
+          description: Returns the desired page.
+          in: query
+          schema:
+            type: number
+        - name: pageSize
+          description: Returns the desired number of resources.
+          in: query
+          schema:
+            type: number
       responses:
         200:
           description: OK
@@ -114,102 +125,122 @@ paths:
         405:
           description: Server error
 
-  /pokemon:
+#  /pokemon:
+#    get:
+#      description: Retrieves a collection of resources.
+#      tags:
+#        - Pokémon
+#      responses:
+#        200:
+#          description: OK
+#    post:
+#      description: Creates a resource on the route's collection.
+#      tags:
+#        - Pokémon
+#      requestBody:
+#        content:
+#          'application/json':
+#            schema:
+#              type: object
+#      responses:
+#        200:
+#          description: OK
+#        400:
+#          description: Bad request
+#        405:
+#          description: Server error
+#  /pokemon/{id}:
+#    get:
+#      description: Retrieves a resource with matching a {id}.
+#      tags:
+#        - Pokémon
+#      parameters:
+#        - name: id
+#          description: The {id} of the desired resource.
+#          in: path
+#          schema:
+#            type: string
+#            minLength: 1
+#          required: true
+#      responses:
+#        200:
+#          description: OK
+#        404:
+#          description: Not found
+#    put:
+#      description: Replaces the resource {id} with the provided one.
+#      tags:
+#        - Pokémon
+#      parameters:
+#        - name: id
+#          description: The {id} of the desired resource.
+#          in: path
+#          schema:
+#            type: string
+#            minLength: 1
+#          required: true
+#
+#      requestBody:
+#        content:
+#          'application/json':
+#            schema:
+#              type: object
+#      responses:
+#        200:
+#          description: OK
+#        400:
+#          description: Bad request
+#        404:
+#          description: Not found
+#        405:
+#          description: Server error
+#    delete:
+#      description: Deletes the resource identified as {id}.
+#      tags:
+#        - Pokémon
+#      parameters:
+#        - name: id
+#          description: The {id} of the desired resource.
+#          in: path
+#          schema:
+#            type: string
+#            minLength: 1
+#          required: true
+#      responses:
+#        204:
+#          description: No content
+#        400:
+#          description: Bad request
+#        404:
+#          description: Not found
+#        405:
+#          description: Server error
+
+  /pokemonTypes:
     get:
       description: Retrieves a collection of resources.
       tags:
-        - Pokémon
-      responses:
-        200:
-          description: OK
-    post:
-      description: Creates a resource on the route's collection.
-      tags:
-        - Pokémon
-      requestBody:
-        content:
-          'application/json':
-            schema:
-              type: object
-      responses:
-        200:
-          description: OK
-        400:
-          description: Bad request
-        405:
-          description: Server error
-  /pokemon/{id}:
-    get:
-      description: Retrieves a resource with matching a {id}.
-      tags:
-        - Pokémon
+        - Pokémon Type
       parameters:
-        - name: id
-          description: The {id} of the desired resource.
-          in: path
+        - name: pageNumber
+          description: Returns the desired page.
+          in: query
           schema:
-            type: string
-            minLength: 1
-          required: true
-      responses:
-        200:
-          description: OK
-        404:
-          description: Not found
-    put:
-      description: Replaces the resource {id} with the provided one.
-      tags:
-        - Pokémon
-      parameters:
-        - name: id
-          description: The {id} of the desired resource.
-          in: path
+            type: number
+        - name: pageSize
+          description: Returns the desired number of resources.
+          in: query
           schema:
-            type: string
-            minLength: 1
-          required: true
-      
-      requestBody:
-        content:
-          'application/json':
-            schema:
-              type: object
-      responses:
-        200:
-          description: OK
-        400:
-          description: Bad request
-        404:
-          description: Not found
-        405:
-          description: Server error
-    delete:
-      description: Deletes the resource identified as {id}.
-      tags:
-        - Pokémon
-      parameters:
-        - name: id
-          description: The {id} of the desired resource.
-          in: path
+            type: number
+        - name: sortBy
+          description: Returns resources sorted according the desired attribute.
+          in: query
           schema:
             type: string
-            minLength: 1
-          required: true
-      responses:
-        204:
-          description: No content
-        400:
-          description: Bad request
-        404:
-          description: Not found
-        405:
-          description: Server error
-
-  /pokemonTypes:
-    get:
-      description: Retrieves a collection of resources.
-      tags:
-        - Pokémon Type
+            enum:
+              - id
+              - pokedexNumber
+              - lastUpDate
       responses:
         200:
           description: OK
@@ -305,95 +336,65 @@ components:
         id:
           type: string
           minLength: 1
-        type:
+        created:
           type: string
-          enum:
-            - trainer
-        meta:
-          type: object
-          properties:
-            creation:
-              type: string
-              format: date-time
-            lastUpdate:
-              type: string
-              format: date-time
-        data:
-          type: object
-          properties:
-            name:
-              type: string
-              minLength: 1
-            profileUrl:
-              type: string
-              format: uri
-            pokemon:
-              type: array
-              items:
-                type: string
-                minLength: 1
-            party:
-              type: array
-              items:
-                type: string
-                minLength: 1
-        links:
-          additionalProperties:
-            type: array
-            items:
-              type: string
-              format: uri
-    Pokemon:
-      description: Schema describing the overall shape of pokemon resources.
-      type: object
-      properties:
-        id:
+          format: date-time
+        lastUpdate:
+          type: string
+          format: date-time
+        name:
           type: string
           minLength: 1
-        type:
+        profileUrl:
           type: string
-          enum:
-            - pokemon
-        meta:
-          type: object
-          properties:
-            creation:
-              type: string
-              format: date-time
-            lastUpdate:
-              type: string
-              format: date-time
-        data:
-          type: object
-          properties:
-            name:
-              type: string
-              minLength: 1
-            height:
-              type: number
-            weight:
-              type: number
-            hp:
-              type: number
-            attack:
-              type: number
-            spAttack:
-              type: number
-            defense:
-              type: number
-            spDefense:
-              type: number
-            speed:
-              type: number
-            pokemonType:
-              type: string
-              minLength: 1
-        links:
-          additionalProperties:
-            type: array
-            items:
-              type: string
-              format: uri
+          format: uri
+        pokemon:
+          type: array
+          items:
+            type: string
+            minLength: 1
+        party:
+          type: array
+          items:
+            type: string
+            minLength: 1
+
+#    Pokemon:
+#      description: Schema describing the overall shape of pokemon resources.
+#      type: object
+#      properties:
+#        id:
+#          type: string
+#          minLength: 1
+#        created:
+#          type: string
+#          format: date-time
+#        lastUpdate:
+#          type: string
+#          format: date-time
+#        name:
+#          type: string
+#          minLength: 1
+#        height:
+#          type: number
+#        weight:
+#          type: number
+#        hp:
+#          type: number
+#        attack:
+#          type: number
+#        spAttack:
+#          type: number
+#        defense:
+#          type: number
+#        spDefense:
+#          type: number
+#        speed:
+#          type: number
+#        pokemonType:
+#          type: string
+#          minLength: 1
+
     PokemonType:
       description: Schema describing the overall shape of pokemon type resources.
       type: object
@@ -401,96 +402,101 @@ components:
         id:
           type: string
           minLength: 1
-        type:
+        created:
+          type: string
+          format: date-time
+        lastUpdate:
+          type: string
+          format: date-time
+        name:
+          type: string
+          minLength: 1
+        pokedexNumber:
+          type: number
+          minimum: 0
+        generation:
+          type: number
+          minimum: 0
+        japaneseName:
+          type: string
+        classification:
+          type: string
+        abilities:
+          type: array
+          items:
+            type: string
+            minLength: 1
+        baseHeight:
+          type: number
+          minimum: 0
+        baseWeight:
+          type: number
+          minimum: 0
+        baseHp:
+          type: number
+          minimum: 0
+        baseAttack:
+          type: number
+          minimum: 0
+        baseSpAttack:
+          type: number
+          minimum: 0
+        baseDefense:
+          type: number
+          minimum: 0
+        baseSpDefense:
+          type: number
+          minimum: 0
+        baseSpeed:
+          type: number
+          minimum: 0
+        captureRate:
+          type: number
+          minimum: 0
+        isLegendary:
+          type: boolean
+        imgUrl:
+          type: string
+          format: uri
+        primaryType:
+          type: string
+          enum:
+            - bug
+            - dark
+            - dragon
+            - electric
+            - fairy
+            - fighting
+            - fire
+            - flying
+            - ghost
+            - grass
+            - ground
+            - ice
+            - normal
+            - poison
+            - psychic
+            - rock
+            - steel
+            - water
+        secondaryType:
           type: string
           enum:
-            - pokemonType
-        meta:
-          type: object
-          properties:
-            creation:
-              type: string
-              format: date-time
-            lastUpdate:
-              type: string
-              format: date-time
-        data:
-          type: object
-          properties:
-            name:
-              type: string
-              minLength: 1
-            pokedexNumber:
-              type: number
-              minimum: 0
-            generation:
-              type: number
-              minimum: 0
-            japaneseName:
-              type: string
-            classification:
-              type: string
-            abilities:
-              type: array
-              items:
-                type: string
-                minLength: 1
-            baseHeight:
-              type: number
-              minimum: 0
-            baseWeight:
-              type: number
-              minimum: 0
-            baseHp:
-              type: number
-              minimum: 0
-            baseAttack:
-              type: number
-              minimum: 0
-            baseSpAttack:
-              type: number
-              minimum: 0
-            baseDefense:
-              type: number
-              minimum: 0
-            baseSpDefense:
-              type: number
-              minimum: 0
-            baseSpeed:
-              type: number
-              minimum: 0
-            captureRate:
-              type: number
-              minimum: 0
-            isLegendary:
-              type: boolean
-            imgUrl:
-              type: string
-              format: uri
-            primaryType:
-              type: string
-              enum:
-                - BUG
-                - DARK
-                - DRAGON
-                - ELECTRIC
-                - FAIRY
-                - FIGHTING
-                - FIRE
-                - FLYING
-                - GHOST
-                - GRASS
-                - GROUND
-                - ICE
-                - NORMAL
-                - POISON
-                - PSYCHIC
-                - ROCK
-                - STEEL
-                - WATER
-        links:
-          additionalProperties:
-            type: array
-            items:
-              type: string
-              format: uri
+            - bug
+            - dark
+            - dragon
+            - electric
+            - fairy
+            - fighting
+            - fire
+            - flying
+            - ghost
+            - grass
+            - ground
+            - ice
+            - normal
+            - poison
+            - psychic
+            - rock
+            - steel
+            - water
diff --git a/src/main/java/nl/utwente/mod4/pokemon/Listenner.java b/src/main/java/nl/utwente/mod4/pokemon/Listenner.java
index 2581a77196345e1a13b31a4f5b9051250638b5dc..a2de4bbc08ee12c2ca95ef2802f3a7265150d4b6 100644
--- a/src/main/java/nl/utwente/mod4/pokemon/Listenner.java
+++ b/src/main/java/nl/utwente/mod4/pokemon/Listenner.java
@@ -4,6 +4,7 @@ import jakarta.servlet.ServletContextEvent;
 import jakarta.servlet.ServletContextListener;
 import jakarta.servlet.annotation.WebListener;
 import nl.utwente.mod4.pokemon.dao.PokemonTypeDao;
+import nl.utwente.mod4.pokemon.dao.TrainerDao;
 
 import java.io.IOException;
 
@@ -14,6 +15,7 @@ public class Listenner implements ServletContextListener {
         System.out.println("Initializing PokeApp...");
         try {
             PokemonTypeDao.INSTANCE.load();
+            TrainerDao.INSTANCE.load();
         } catch (IOException e) {
             System.err.println("Error while loading data.");
             e.printStackTrace();
@@ -26,6 +28,7 @@ public class Listenner implements ServletContextListener {
         System.out.println("Shutting down PokeApp...");
         try {
             PokemonTypeDao.INSTANCE.save();
+            TrainerDao.INSTANCE.save();
         } catch (IOException e) {
             System.err.println("Error while saving data.");
             e.printStackTrace();
diff --git a/src/main/java/nl/utwente/mod4/pokemon/Utils.java b/src/main/java/nl/utwente/mod4/pokemon/Utils.java
index 1d2dce1e568186606c796b8af6f264dec966efd5..01bc8da9bc03d5faeb6250e9d935ef16eb2dec38 100644
--- a/src/main/java/nl/utwente/mod4/pokemon/Utils.java
+++ b/src/main/java/nl/utwente/mod4/pokemon/Utils.java
@@ -1,10 +1,29 @@
 package nl.utwente.mod4.pokemon;
 
 import java.nio.file.Path;
+import java.util.List;
 
 public class Utils {
 
     public static String getAbsolutePathToResources() {
         return Utils.class.getClassLoader().getResource("").getPath();
     }
+
+    public static <T extends Comparable<T>> int compare(T o1, T o2) {
+        if (o1 == null && o2 == null)
+            return 0;
+        if (o1 == null)
+            return -1;
+        if (o2 == null)
+            return 1;
+        return o1.compareTo(o2);
+    }
+
+    public static List<?> pageSlice(List<?> list, int pageSize, int pageNumber) {
+        int total = list.size();
+        int firstIndex = (pageNumber - 1) * pageSize;
+        int lastIndex = Math.min(pageNumber * pageSize, total);
+        return list.subList(firstIndex,lastIndex);
+    }
+
 }
diff --git a/src/main/java/nl/utwente/mod4/pokemon/dao/PokemonTypeDao.java b/src/main/java/nl/utwente/mod4/pokemon/dao/PokemonTypeDao.java
index 119568f3a2401dc07400011221332649ccb7931b..a5d37fa878d513513b7a6461da5418366a6139d7 100644
--- a/src/main/java/nl/utwente/mod4/pokemon/dao/PokemonTypeDao.java
+++ b/src/main/java/nl/utwente/mod4/pokemon/dao/PokemonTypeDao.java
@@ -5,8 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.ObjectWriter;
 import jakarta.ws.rs.BadRequestException;
 import jakarta.ws.rs.NotFoundException;
-import jakarta.ws.rs.WebApplicationException;
-import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.NotSupportedException;
 import nl.utwente.mod4.pokemon.Utils;
 import nl.utwente.mod4.pokemon.model.PokemonType;
 
@@ -32,8 +31,19 @@ public enum PokemonTypeDao {
         }
     }
 
-    public List<PokemonType> getPokemonTypes() {
-        return new ArrayList<>(pokemonTypes.values());
+    public List<PokemonType> getPokemonTypes(int pageSize, int pageNumber, String sortBy) {
+        List<PokemonType> list = new ArrayList<>(pokemonTypes.values());
+
+        if (sortBy == null || sortBy.isEmpty() || "id".equals(sortBy))
+            list.sort((pt1, pt2) -> Utils.compare(Integer.parseInt(pt1.id), Integer.parseInt(pt2.id)));
+        else if ("pokedexNumber".equals(sortBy))
+            list.sort((pt1, pt2) -> Utils.compare(pt1.pokedexNumber, pt2.pokedexNumber));
+        else if ("lastUpDate".equals(sortBy))
+            list.sort((pt1, pt2) -> Utils.compare(pt1.lastUpDate, pt2.lastUpDate));
+        else
+            throw new NotSupportedException("Sort field not supported");
+
+        return (List<PokemonType>) Utils.pageSlice(list,pageSize,pageNumber);
     }
 
     public PokemonType getPokemonType(String id) {
@@ -56,6 +66,11 @@ public enum PokemonTypeDao {
         Arrays.stream(arr).forEach(pt -> pokemonTypes.put(pt.id, pt));
     }
 
+    private boolean existsPokemonTypes() {
+        File f = new File(POKEMON_TYPES);
+        return f.exists() && !f.isDirectory();
+    }
+
     public void save() throws IOException {
         ObjectMapper mapper = new ObjectMapper();
         ObjectWriter writer = mapper.writer(new DefaultPrettyPrinter());
@@ -64,20 +79,6 @@ public enum PokemonTypeDao {
         writer.writeValue(destination, pokemonTypes.values());
     }
 
-    private boolean existsPokemonTypes() {
-        File f = new File(POKEMON_TYPES);
-        return f.exists() && !f.isDirectory();
-    }
-
-    private int getMaxId() {
-        Set<String> ids = pokemonTypes.keySet();
-        return ids.isEmpty() ? 0 : ids.stream()
-                .map(Integer::parseInt)
-                .max(Integer::compareTo)
-                .get();
-    }
-
-
     public PokemonType create(PokemonType newPokemonType) {
         String nextId = "" + (getMaxId() + 1);
 
@@ -89,6 +90,14 @@ public enum PokemonTypeDao {
         return newPokemonType;
     }
 
+    private int getMaxId() {
+        Set<String> ids = pokemonTypes.keySet();
+        return ids.isEmpty() ? 0 : ids.stream()
+                .map(Integer::parseInt)
+                .max(Integer::compareTo)
+                .get();
+    }
+
     public PokemonType update(PokemonType updated) {
         if(!updated.isValid())
             throw new BadRequestException("Invalid pokemon type.");
@@ -100,4 +109,8 @@ public enum PokemonTypeDao {
 
         return updated;
     }
+
+    public int getTotalPokemonTypes() {
+        return pokemonTypes.keySet().size();
+    }
 }
diff --git a/src/main/java/nl/utwente/mod4/pokemon/dao/TrainerDao.java b/src/main/java/nl/utwente/mod4/pokemon/dao/TrainerDao.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd8a9151d099b18d2fa73ccc8c87e250e85498cd
--- /dev/null
+++ b/src/main/java/nl/utwente/mod4/pokemon/dao/TrainerDao.java
@@ -0,0 +1,106 @@
+package nl.utwente.mod4.pokemon.dao;
+
+import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectWriter;
+import jakarta.ws.rs.BadRequestException;
+import jakarta.ws.rs.NotFoundException;
+import nl.utwente.mod4.pokemon.Utils;
+import nl.utwente.mod4.pokemon.model.Trainer;
+
+import java.io.File;
+import java.io.IOException;
+import java.time.Instant;
+import java.util.*;
+
+public enum TrainerDao {
+
+    INSTANCE;
+
+    private static final String ORIGINAL_TRAINERS = Utils.getAbsolutePathToResources() + "/default-trainers-dataset.json";
+    private static final String TRAINERS = Utils.getAbsolutePathToResources() + "/trainers.json";
+
+    private HashMap<String, Trainer> trainers = new HashMap<>();
+
+    public void delete(String id) {
+        if(trainers.containsKey(id)) {
+            trainers.remove(id);
+        } else {
+            throw new NotFoundException("Trainer '" + id + "' not found.");
+        }
+    }
+
+    public List<Trainer> getTrainers(int pageSize, int pageNumber) {
+        var list = new ArrayList<>(trainers.values());
+        return (List<Trainer>) Utils.pageSlice(list,pageSize,pageNumber);
+    }
+
+    public Trainer getTrainer(String id) {
+        var pt = trainers.get(id);
+
+        if (pt == null) {
+            throw new NotFoundException("Pokemon '" + id + "' not found!");
+        }
+
+        return pt;
+    }
+
+    public void load() throws IOException {
+        ObjectMapper mapper = new ObjectMapper();
+        File source = existsTrainers() ?
+                new File(TRAINERS) :
+                new File(ORIGINAL_TRAINERS);
+        Trainer[] arr = mapper.readValue(source, Trainer[].class);
+
+        Arrays.stream(arr).forEach(trainer -> trainers.put(trainer.id, trainer));
+    }
+
+    public void save() throws IOException {
+        ObjectMapper mapper = new ObjectMapper();
+        ObjectWriter writer = mapper.writer(new DefaultPrettyPrinter());
+        File destination = new File(TRAINERS);
+
+        writer.writeValue(destination, trainers.values());
+    }
+
+    private boolean existsTrainers() {
+        File f = new File(TRAINERS);
+        return f.exists() && !f.isDirectory();
+    }
+
+    private int getMaxId() {
+        Set<String> ids = trainers.keySet();
+        return ids.isEmpty() ? 0 : ids.stream()
+                .map(Integer::parseInt)
+                .max(Integer::compareTo)
+                .get();
+    }
+
+
+    public Trainer create(Trainer newTrainer) {
+        String nextId = "" + (getMaxId() + 1);
+
+        newTrainer.id = nextId;
+        newTrainer.created = Instant.now().toString();
+        newTrainer.lastUpDate = Instant.now().toString();
+        trainers.put(nextId,newTrainer);
+
+        return newTrainer;
+    }
+
+    public Trainer update(Trainer updated) {
+        if(!updated.isValid())
+            throw new BadRequestException("Invalid trainer.");
+        if(trainers.get(updated.id) == null)
+            throw new NotFoundException("Trainer id '" + updated.id + "' not found.");
+
+        updated.lastUpDate = Instant.now().toString();
+        trainers.put(updated.id,updated);
+
+        return updated;
+    }
+
+    public int getTotalTrainers() {
+        return trainers.keySet().size();
+    }
+}
diff --git a/src/main/java/nl/utwente/mod4/pokemon/model/ResourceCollection.java b/src/main/java/nl/utwente/mod4/pokemon/model/ResourceCollection.java
index fb2868ea4538fc84ce801203be3356e3520877f7..92529e4f9c6fe66de7fbe8ad94294d3909e0bc87 100644
--- a/src/main/java/nl/utwente/mod4/pokemon/model/ResourceCollection.java
+++ b/src/main/java/nl/utwente/mod4/pokemon/model/ResourceCollection.java
@@ -1,4 +1,31 @@
 package nl.utwente.mod4.pokemon.model;
 
-public class ResourceCollection {
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Objects;
+
+public class ResourceCollection<T extends NamedEntity> {
+
+    public HashMap<String,Object> meta;
+    public HashMap<String,Object> links;
+    public T[] data;
+
+    public ResourceCollection() {
+        data = null;
+        meta = new HashMap<>();
+        links = new HashMap<>();
+    }
+
+    public ResourceCollection(T[] resources, int pageSize, int pageNumber, int total) {
+        meta = new HashMap<>();
+        links = new HashMap<>();
+
+        meta.put("total",  total);
+        meta.put("pageNumber", pageNumber);
+        meta.put("pageSize", pageSize);
+
+        data = resources;
+    }
+
 }
diff --git a/src/main/java/nl/utwente/mod4/pokemon/model/Trainer.java b/src/main/java/nl/utwente/mod4/pokemon/model/Trainer.java
new file mode 100644
index 0000000000000000000000000000000000000000..4f6f1cce08a44122424b0b5879b0d59f82fc7ddb
--- /dev/null
+++ b/src/main/java/nl/utwente/mod4/pokemon/model/Trainer.java
@@ -0,0 +1,12 @@
+package nl.utwente.mod4.pokemon.model;
+
+
+public class Trainer extends NamedEntity {
+
+    public String profileUrl;
+
+    public Trainer() {
+        super();
+        profileUrl = null;
+    }
+}
diff --git a/src/main/java/nl/utwente/mod4/pokemon/routes/PokemonTypeRoute.java b/src/main/java/nl/utwente/mod4/pokemon/routes/PokemonTypeRoute.java
index 298706dce80154e7fd463969794094931c123549..b98b707c234f1723cf7ce87d107c5c7aa5a2c391 100644
--- a/src/main/java/nl/utwente/mod4/pokemon/routes/PokemonTypeRoute.java
+++ b/src/main/java/nl/utwente/mod4/pokemon/routes/PokemonTypeRoute.java
@@ -5,6 +5,7 @@ import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.Response;
 import nl.utwente.mod4.pokemon.dao.PokemonTypeDao;
 import nl.utwente.mod4.pokemon.model.PokemonType;
+import nl.utwente.mod4.pokemon.model.ResourceCollection;
 
 import java.util.List;
 
@@ -13,21 +14,30 @@ public class PokemonTypeRoute {
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    public List<PokemonType> getPokemon() {
-        return PokemonTypeDao.INSTANCE.getPokemonTypes();
+    public ResourceCollection<PokemonType> getPokemonTypes(
+            @QueryParam("sortBy") String sortBy,
+            @QueryParam("pageSize") int pageSize,
+            @QueryParam("pageNumber") int pageNumber
+    ) {
+        int ps = pageSize > 0 ? pageSize : Integer.MAX_VALUE;
+        int pn = pageNumber > 0 ? pageNumber : 1;
+        var resources = PokemonTypeDao.INSTANCE.getPokemonTypes(ps, pn, sortBy).toArray(new PokemonType[0]);
+        var total = PokemonTypeDao.INSTANCE.getTotalPokemonTypes();
+
+        return new ResourceCollection<>(resources, ps, pn, total);
     }
 
     @POST
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
-    public PokemonType createPokemon(PokemonType pokemonType) {
+    public PokemonType createPokemonType(PokemonType pokemonType) {
         return PokemonTypeDao.INSTANCE.create(pokemonType);
     }
 
     @GET
     @Path("/{id}")
     @Produces(MediaType.APPLICATION_JSON)
-    public PokemonType getPokemon(@PathParam("id") String id) {
+    public PokemonType getPokemonType(@PathParam("id") String id) {
         return PokemonTypeDao.INSTANCE.getPokemonType(id);
     }
 
@@ -35,8 +45,8 @@ public class PokemonTypeRoute {
     @Path("/{id}")
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
-    public PokemonType updatePokemon(@PathParam("id") String id, PokemonType toUpdate) {
-        if(id == null || !id.equals(toUpdate.id))
+    public PokemonType updatePokemonType(@PathParam("id") String id, PokemonType toUpdate) {
+        if (id == null || !id.equals(toUpdate.id))
             throw new BadRequestException("Id mismatch.");
 
         return PokemonTypeDao.INSTANCE.update(toUpdate);
@@ -44,7 +54,7 @@ public class PokemonTypeRoute {
 
     @DELETE
     @Path("/{id}")
-    public void deletePokemon(@PathParam("id") String id) {
+    public void deletePokemonType(@PathParam("id") String id) {
         PokemonTypeDao.INSTANCE.delete(id);
     }
 }
\ No newline at end of file
diff --git a/src/main/java/nl/utwente/mod4/pokemon/routes/TrainerRoute.java b/src/main/java/nl/utwente/mod4/pokemon/routes/TrainerRoute.java
new file mode 100644
index 0000000000000000000000000000000000000000..41ab71ec4ae918132aceae6891bc46235780999f
--- /dev/null
+++ b/src/main/java/nl/utwente/mod4/pokemon/routes/TrainerRoute.java
@@ -0,0 +1,57 @@
+package nl.utwente.mod4.pokemon.routes;
+
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.MediaType;
+import nl.utwente.mod4.pokemon.dao.TrainerDao;
+import nl.utwente.mod4.pokemon.model.ResourceCollection;
+import nl.utwente.mod4.pokemon.model.Trainer;
+
+@Path("/trainers")
+public class TrainerRoute {
+
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public ResourceCollection<Trainer> getTrainers(
+            @QueryParam("pageSize") int pageSize,
+            @QueryParam("pageNumber") int pageNumber
+    ) {
+        int ps = pageSize > 0 ? pageSize : Integer.MAX_VALUE;
+        int pn = pageNumber > 0 ? pageNumber : 1;
+        var resources = TrainerDao.INSTANCE.getTrainers(ps, pn).toArray(new Trainer[0]);
+        var total = TrainerDao.INSTANCE.getTotalTrainers();
+
+        return new ResourceCollection<>(resources, ps, pn, total);
+    }
+
+    @POST
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Trainer createTrainer(Trainer pokemonType) {
+        return TrainerDao.INSTANCE.create(pokemonType);
+    }
+
+    @GET
+    @Path("/{id}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Trainer getTrainer(@PathParam("id") String id) {
+        return TrainerDao.INSTANCE.getTrainer(id);
+    }
+
+    @PUT
+    @Path("/{id}")
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Trainer updateTrainer(@PathParam("id") String id, Trainer toUpdate) {
+        if (id == null || !id.equals(toUpdate.id))
+            throw new BadRequestException("Id mismatch.");
+
+        return TrainerDao.INSTANCE.update(toUpdate);
+    }
+
+    @DELETE
+    @Path("/{id}")
+    public void deleteTrainer(@PathParam("id") String id) {
+        TrainerDao.INSTANCE.delete(id);
+    }
+}
diff --git a/src/main/resources/default-trainers-dataset.json b/src/main/resources/default-trainers-dataset.json
new file mode 100644
index 0000000000000000000000000000000000000000..53712364e7707b2b9060a9f302ffd0123554d7ae
--- /dev/null
+++ b/src/main/resources/default-trainers-dataset.json
@@ -0,0 +1,30 @@
+[
+  {
+    "name": "Red",
+    "id": 1,
+    "created": "24/04/2024",
+    "lastUpDate": "24/04/2024",
+    "profileUrl": "/pokemon/images/red.png"
+  },
+  {
+    "name": "Blue",
+    "id": 2,
+    "created": "24/04/2024",
+    "lastUpDate": "24/04/2024",
+    "profileUrl": "/pokemon/images/blue.png"
+  },
+  {
+    "name": "Misty",
+    "id": 3,
+    "created": "24/04/2024",
+    "lastUpDate": "24/04/2024",
+    "profileUrl": "/pokemon/images/misty.png"
+  },
+  {
+    "name": "Brock",
+    "id": 4,
+    "created": "24/04/2024",
+    "lastUpDate": "24/04/2024",
+    "profileUrl": "/pokemon/images/brock.png"
+  }
+]
\ No newline at end of file
diff --git a/src/main/webapp/images/blue.png b/src/main/webapp/images/blue.png
new file mode 100644
index 0000000000000000000000000000000000000000..f8444899b3c0b36de8c4698be98df53bf56225bc
Binary files /dev/null and b/src/main/webapp/images/blue.png differ
diff --git a/src/main/webapp/images/brock.jpg b/src/main/webapp/images/brock.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..9c90529e36f2fde2306bd28b5bbf872e6b387e2d
Binary files /dev/null and b/src/main/webapp/images/brock.jpg differ
diff --git a/src/main/webapp/images/brock.png b/src/main/webapp/images/brock.png
new file mode 100644
index 0000000000000000000000000000000000000000..b234cd691880eca73250aeb310f277cefcb54235
Binary files /dev/null and b/src/main/webapp/images/brock.png differ
diff --git a/src/main/webapp/images/misty.png b/src/main/webapp/images/misty.png
new file mode 100644
index 0000000000000000000000000000000000000000..e4cd0ae73a752db8f1c6e532878533f9d39a3fe3
Binary files /dev/null and b/src/main/webapp/images/misty.png differ
diff --git a/src/main/webapp/images/red.jpg b/src/main/webapp/images/red.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..58d5d78c110ea449e7c72805539afa72a2064b98
Binary files /dev/null and b/src/main/webapp/images/red.jpg differ
diff --git a/src/main/webapp/images/red.png b/src/main/webapp/images/red.png
new file mode 100644
index 0000000000000000000000000000000000000000..6a817dc90141b779c63cffbc57e44a51c4cb2765
Binary files /dev/null and b/src/main/webapp/images/red.png differ
diff --git a/src/main/webapp/index.html b/src/main/webapp/index.html
index 297e57248edfaef7113311f75ee797268a8e56c5..07bacaf0a7cf57f28e184b0b540deec522831903 100644
--- a/src/main/webapp/index.html
+++ b/src/main/webapp/index.html
@@ -5,9 +5,19 @@
     <title>Title</title>
 </head>
 <body>
+
 <p>Hello there</p>
-<img src="/pokemon/images/abra.png"/>
+
+<img src="/pokemon/images/red.png" style="height: 150px"/>
+<img src="/pokemon/images/abra.png" style="height: 150px"/>
+
+<form action="/pokemon/api/trainers">
+    <input type="submit" value="Trainers" />
+</form>
+
 <form action="/pokemon/api/pokemonTypes">
     <input type="submit" value="Pokemon Types" />
-</form></body>
+</form>
+
+</body>
 </html>
\ No newline at end of file