👔 Implement Trainer

pull/4/head
Alexis Drai 2 years ago
parent 220b2e39a9
commit af2f90890c

@ -88,6 +88,9 @@ You can run the application in dev mode using:
Thanks to this project's OpenAPI specs, you can explore the API in a lot of ways.
A popular choice is SwaggerUI -- after you run the app, just go to http://localhost:8080/q/swagger-ui and have fun.
⚠️ Unfortunately, Swagger or Quarkus or SmallRye adds the field `id` to all request examples, but in fact ***you should
not include id** when you POST a new document.*
### 🩺 API testing tools
You can use an API testing tool such as [Postman](https://www.postman.com/)

@ -44,7 +44,6 @@
* type: embedded type
* (_indexed_: would often be queried in a dashboard situation)
### types collection
* _id: ObjectId
@ -55,18 +54,34 @@
## Relationships
- [ ] trainers.pastOpponents: one-to-many and reflexive
* => referencing
- [ ] trainers.pokemongs: one-to-many
* => referencing + denormalizing on "nickname" and "species"
- [ ] pokemongs.trainer: many-to-one
* => referencing
- [x] pokemongs.types: one-to-few [1;2]
* => embedding
- [x] pokemongs.moveSet: one-to-few [1;4] but will also need to be queried independently
* => referencing + denormalizing on "name"
- [x] moves.type: one-to-one [1;1]
* => embedding
- [x] types.weakAgainst & types.effectiveAgainst: one-to-few, but reflexive
* => denormalizing on "name"
- Trainer
- [ ] trainers.pastOpponents: one-to-many and reflexive
* => referencing
- [ ] trainers.pokemongs: one-to-many
* => referencing + denormalizing on "nickname" and "species"
- Pokemong
- [ ] pokemongs.trainer: many-to-one
* => referencing
- [x] pokemongs.types: one-to-few [1;2]
* => embedding
- [x] pokemongs.moveSet: one-to-few [1;4] but will also need to be queried independently
* => referencing + denormalizing on "name"
- Move
- [x] moves.type: one-to-one [1;1]
* => embedding
- Type
- [x] types.weakAgainst & types.effectiveAgainst: one-to-few, but reflexive
* => denormalizing on "name"
## Cascades
- Pokemong
- [ ] delete ~> trainer.pokemongs
- [ ] update ~> trainer.pokemongs (denormalizing on "nickname" and "species")
- [ ] create ~> trainer.pokemongs
- Trainer
- [ ] delete ~> pokemong.trainer
- [ ] create ~> pokemong.trainer
- Move
- [x] delete ~> pokemong.moveSet
- [x] update ~> pokemong.moveSet (denormalizing on "name")

@ -54,7 +54,7 @@ public class PokemongCodec extends GenericCodec<Pokemong> {
.collect(Collectors.toList());
doc.put("evoTrack", evoTrack);
if(pokemong.getTrainer() != null) {
if (pokemong.getTrainer() != null) {
doc.put("trainer", new ObjectId(pokemong.getTrainer()));
}
@ -128,7 +128,8 @@ public class PokemongCodec extends GenericCodec<Pokemong> {
.collect(Collectors.toList());
pokemong.setEvoTrack(evoTrack);
pokemong.setTrainer(document.getString("trainer"));
pokemong.setTrainer(document.getObjectId("trainer")
.toString());
List<Type> types = document.getList("types", Document.class)
.stream()

@ -3,6 +3,8 @@ package fr.uca.iut.codecs.trainer;
import com.mongodb.MongoClientSettings;
import fr.uca.iut.codecs.GenericCodec;
import fr.uca.iut.entities.Trainer;
import fr.uca.iut.entities.TrainerPokemong;
import fr.uca.iut.utils.enums.PokemongName;
import org.bson.BsonReader;
import org.bson.BsonWriter;
import org.bson.Document;
@ -14,6 +16,8 @@ import org.bson.types.ObjectId;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
public class TrainerCodec extends GenericCodec<Trainer> {
private final Codec<Document> documentCodec;
@ -41,9 +45,25 @@ public class TrainerCodec extends GenericCodec<Trainer> {
doc.put("losses", trainer.getLosses());
doc.put("pastOpponents", trainer.getPastOpponents());
doc.put("pokemongs", trainer.getPokemongs());
List<ObjectId> pastOpponentsIds = trainer.getPastOpponents()
.stream()
.map(ObjectId::new)
.collect(Collectors.toList());
doc.put("pastOpponents", pastOpponentsIds);
List<Document> pokemongListDoc = trainer.getPokemongs()
.stream()
.map(pokemong -> {
Document moveDoc = new Document();
moveDoc.put("_id", new ObjectId(pokemong.getId()));
moveDoc.put("nickname", pokemong.getNickname());
moveDoc.put("species",
pokemong.getSpecies()
.name());
return moveDoc;
})
.collect(Collectors.toList());
doc.put("pokemongs", pokemongListDoc);
documentCodec.encode(writer, doc, encoderContext);
}
@ -74,10 +94,24 @@ public class TrainerCodec extends GenericCodec<Trainer> {
trainer.setLosses(document.getInteger("losses"));
trainer.setPastOpponents(document.getList("pastOpponents", ObjectId.class));
trainer.setPokemongs(document.getList("pokemongs", ObjectId.class));
List<String> pastOpponentsIds = document.getList("pastOpponents", ObjectId.class)
.stream()
.map(ObjectId::toString)
.collect(Collectors.toList());
trainer.setPastOpponents(pastOpponentsIds);
List<TrainerPokemong> pokemongList = document
.getList("pokemongs", Document.class)
.stream()
.map(pokemongDoc -> {
TrainerPokemong pokemong = new TrainerPokemong();
pokemong.setId(((ObjectId) pokemongDoc.get("_id")).toString());
pokemong.setNickname(pokemongDoc.getString("nickname"));
pokemong.setSpecies(PokemongName.valueOf(pokemongDoc.getString("species")));
return pokemong;
})
.collect(Collectors.toList());
trainer.setPokemongs(pokemongList);
return trainer;
}
}

@ -0,0 +1,22 @@
package fr.uca.iut.controllers;
import fr.uca.iut.entities.Trainer;
import fr.uca.iut.services.TrainerService;
import jakarta.annotation.PostConstruct;
import jakarta.inject.Inject;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/trainer")
@Produces(MediaType.APPLICATION_JSON)
public class TrainerController extends GenericController<Trainer> {
@Inject
TrainerService trainerService;
@PostConstruct
public void init() {
setService(trainerService);
}
}

@ -1,7 +1,5 @@
package fr.uca.iut.entities;
import org.bson.types.ObjectId;
import java.time.LocalDate;
import java.util.Collections;
import java.util.List;
@ -13,8 +11,8 @@ public class Trainer extends GenericEntity {
private LocalDate dob;
private Integer wins;
private Integer losses;
private List<ObjectId> pastOpponents;
private List<ObjectId> pokemongs;
private List<String> pastOpponents;
private List<TrainerPokemong> pokemongs;
public Trainer() {}
@ -50,19 +48,19 @@ public class Trainer extends GenericEntity {
this.losses = losses;
}
public List<ObjectId> getPastOpponents() {
public List<String> getPastOpponents() {
return Collections.unmodifiableList(pastOpponents);
}
public void setPastOpponents(List<ObjectId> pastOpponents) {
public void setPastOpponents(List<String> pastOpponents) {
this.pastOpponents = pastOpponents;
}
public List<ObjectId> getPokemongs() {
public List<TrainerPokemong> getPokemongs() {
return Collections.unmodifiableList(pokemongs);
}
public void setPokemongs(List<ObjectId> pokemongs) {
public void setPokemongs(List<TrainerPokemong> pokemongs) {
this.pokemongs = pokemongs;
}
}

@ -0,0 +1,30 @@
package fr.uca.iut.entities;
import com.mongodb.lang.Nullable;
import fr.uca.iut.utils.enums.PokemongName;
public class TrainerPokemong extends GenericEntity {
@Nullable
private String nickname;
private PokemongName species;
public TrainerPokemong() {}
@Nullable
public String getNickname() {
return nickname;
}
public void setNickname(@Nullable String nickname) {
this.nickname = nickname;
}
public PokemongName getSpecies() {
return species;
}
public void setSpecies(PokemongName species) {
this.species = species;
}
}

@ -14,6 +14,8 @@ import org.bson.types.ObjectId;
import java.util.ArrayList;
import java.util.List;
import static com.mongodb.client.model.Filters.eq;
@ApplicationScoped
public class PokemongRepository extends GenericRepository<Pokemong> {
@ -41,4 +43,9 @@ public class PokemongRepository extends GenericRepository<Pokemong> {
MongoDatabase db = mongoClient.getDatabase(DB_NAME);
return db.getCollection(Pokemong.COLLECTION_NAME, Pokemong.class);
}
public List<Pokemong> findByTrainer(String trainerId) {
return getCollection().find(eq("trainer", new ObjectId(trainerId)))
.into(new ArrayList<>());
}
}

@ -0,0 +1,44 @@
package fr.uca.iut.repositories;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import fr.uca.iut.entities.Trainer;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import java.util.ArrayList;
import java.util.List;
@ApplicationScoped
public class TrainerRepository extends GenericRepository<Trainer> {
// FIX?ME
/**
* Warns that "Unsatisfied dependency: no bean matches the injection point"
* but the app works
*/
@Inject
MongoClient mongoClient;
@PostConstruct
public void init() {
setMongoClient(mongoClient);
}
public List<Trainer> findByPokemong(String pokemongId) {
Bson filter = Filters.elemMatch("pokemongs", Filters.eq("_id", new ObjectId(pokemongId)));
return getCollection().find(filter)
.into(new ArrayList<>());
}
@Override
protected MongoCollection<Trainer> getCollection() {
MongoDatabase db = mongoClient.getDatabase(DB_NAME);
return db.getCollection(Trainer.COLLECTION_NAME, Trainer.class);
}
}

@ -11,6 +11,7 @@ import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
@ApplicationScoped
@ -41,11 +42,15 @@ public class MoveService extends GenericService<Move> {
public Move updateOne(@NotNull Move move) {
Move existingMove = moveRepository.findById(move.getId());
if (existingMove != null) {
existingMove.setName(move.getName());
List<Pokemong> pokemongs = pokemongService.findByMove(move.getId());
for (Pokemong pokemong : pokemongs) {
pokemong.updateMove(move.getId(), move.getName());
pokemongService.updateOne(pokemong);
if (!existingMove.getName()
.equals(move.getName()))
{
existingMove.setName(move.getName());
List<Pokemong> pokemongs = pokemongService.findByMove(move.getId());
for (Pokemong pokemong : pokemongs) {
pokemong.updateMove(move.getId(), move.getName());
pokemongService.updateOne(pokemong);
}
}
existingMove.setPower(move.getPower());
@ -62,24 +67,34 @@ public class MoveService extends GenericService<Move> {
super.validateOne(move);
if (StringUtils.isBlankString(move.getName())) {
throw new NonValidEntityException("move name was null, blank or empty");
List<String> errors = new ArrayList<>();
if (StringUtils.isBlankStringOrNull(move.getName())) {
errors.add("move name was null, blank or empty");
}
if (move.getPower() == null || move.getPower() < 0) {
throw new NonValidEntityException("move power was null or negative");
errors.add("move power was null or negative");
}
if (move.getCategory() == null) {
throw new NonValidEntityException("move category was null or invalid");
errors.add("move category was null or invalid");
}
if (move.getAccuracy() == null || move.getAccuracy() < 0) {
throw new NonValidEntityException("move accuracy was null or negative");
errors.add("move accuracy was null or negative");
}
if (move.getType() == null) {
throw new NonValidEntityException("move type was null or invalid");
errors.add("move type was null or invalid");
}
if (!errors.isEmpty()) {
throw new NonValidEntityException("Validation errors: " + String.join(", ", errors));
}
}
public boolean existsById(String moveId) {
return moveRepository.existsById(moveId);
}
}

@ -4,14 +4,16 @@ import com.mongodb.lang.Nullable;
import fr.uca.iut.entities.Pokemong;
import fr.uca.iut.entities.PokemongMove;
import fr.uca.iut.entities.Type;
import fr.uca.iut.repositories.MoveRepository;
import fr.uca.iut.repositories.PokemongRepository;
import fr.uca.iut.utils.StringUtils;
import fr.uca.iut.utils.enums.PokemongName;
import fr.uca.iut.utils.exceptions.NonValidEntityException;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@ -20,25 +22,42 @@ public class PokemongService extends GenericService<Pokemong> {
@Inject
PokemongRepository pokemongRepository;
@Inject
MoveRepository moveRepository;
MoveService moveService;
@PostConstruct
public void init() {
setRepository(pokemongRepository);
}
@Override
public Pokemong addOne(@NotNull Pokemong pokemong) {
// TODO if this pokemong has a trainer, make sure that the trainer's "pokemongs" field gets updated accordingly.
// (add a TrainerPokemong to the list, update the trainer)
return super.addOne(pokemong);
}
@Override
public void deleteOneById(String id) {
super.deleteOneById(id);
// TODO also delete any corresponding PokemongTrainer among trainers
}
@Override
@Nullable
public Pokemong updateOne(@NotNull Pokemong pokemong) {
Pokemong existingPokemong = pokemongRepository.findById(pokemong.getId());
if (existingPokemong != null) {
existingPokemong.setNickname(pokemong.getNickname());
// TODO if nickname changed also update any corresponding PokemongTrainer's nickname
existingPokemong.setDob(pokemong.getDob());
existingPokemong.setLevel(pokemong.getLevel());
existingPokemong.setPokedexId(pokemong.getPokedexId());
existingPokemong.setEvoStage(pokemong.getEvoStage());
// TODO if evoStage changed, also update any corresponding PokemongTrainer's species
existingPokemong.setEvoTrack(pokemong.getEvoTrack());
// TODO if evoTrack changed, also update any corresponding PokemongTrainer's species
existingPokemong.setTrainer(pokemong.getTrainer());
existingPokemong.setTypes(pokemong.getTypes());
existingPokemong.setMoveSet(pokemong.getMoveSet());
@ -52,24 +71,26 @@ public class PokemongService extends GenericService<Pokemong> {
super.validateOne(pokemong);
List<String> errors = new ArrayList<>();
if (pokemong.getDob() == null) {
throw new NonValidEntityException("pokemong date of birth was null or invalid");
errors.add("pokemong date of birth was null or invalid");
}
if (pokemong.getLevel() == null || pokemong.getLevel() < 1) {
throw new NonValidEntityException("pokemong level was null or less than 1");
errors.add("pokemong level was null or less than 1");
}
if (pokemong.getPokedexId() == null || pokemong.getPokedexId() < 1) {
throw new NonValidEntityException("pokemong pokedex id was null or less than 1");
errors.add("pokemong pokedex id was null or less than 1");
}
if (pokemong.getEvoStage() == null || pokemong.getEvoStage() < 0) {
throw new NonValidEntityException("pokemong evo stage was null or negative");
errors.add("pokemong evo stage was null or negative");
}
if (pokemong.getEvoTrack() == null) {
throw new NonValidEntityException("pokemong evo track was null or invalid");
errors.add("pokemong evo track was null or invalid");
}
List<Type> types = pokemong.getTypes();
@ -77,26 +98,49 @@ public class PokemongService extends GenericService<Pokemong> {
|| types.size() == 0
|| types.size() > 2)
{
throw new NonValidEntityException("pokemong types was null or empty or had more than 2 types");
errors.add("pokemong types was null or empty or had more than 2 types");
}
Set<PokemongMove> moveSet = pokemong.getMoveSet();
if (moveSet == null
|| moveSet.size() == 0
|| moveSet.size() > 4)
{
throw new NonValidEntityException("pokemong move set was null or empty or had more than 4 moves");
if (moveSet == null) {
errors.add("pokemong move set was null");
}
for (PokemongMove move : moveSet) {
String moveId = move.getId();
if (moveId == null || !moveRepository.existsById(moveId)) {
throw new NonValidEntityException("move with id " + moveId + " does not exist");
else {
if (moveSet.size() == 0 || moveSet.size() > 4) {
errors.add("pokemong move set was empty or had more than 4 moves");
}
for (PokemongMove move : moveSet) {
String moveId = move.getId();
String moveName = move.getName();
if (StringUtils.isBlankStringOrNull(moveId) || !moveService.existsById(moveId)) {
errors.add("move with id " + moveId + " does not exist");
}
if (StringUtils.isBlankStringOrNull(moveName)) {
errors.add("move name was null, blank or empty");
}
// We don't check whether the move name is consistent with the original -- trainers can rename moves
// locally in a pokemong. If once in a while a Move has its name updated, the change will be reflected
// in all the PokemongMoves, and the local aliases will be lost
}
}
if (!errors.isEmpty()) {
throw new NonValidEntityException("Validation errors: " + String.join(", ", errors));
}
}
public List<Pokemong> findByMove(String id) {
return pokemongRepository.findByMove(id);
}
public boolean isEvoValid(String id, PokemongName species) {
Pokemong pokemong = pokemongRepository.findById(id);
return pokemong != null && pokemong.getEvoTrack()
.get(pokemong.getEvoStage()) == species;
}
public boolean existsById(String pokemongId) {
return repository.existsById(pokemongId);
}
}

@ -0,0 +1,127 @@
package fr.uca.iut.services;
import com.mongodb.lang.Nullable;
import fr.uca.iut.entities.Trainer;
import fr.uca.iut.entities.TrainerPokemong;
import fr.uca.iut.repositories.TrainerRepository;
import fr.uca.iut.utils.StringUtils;
import fr.uca.iut.utils.exceptions.NonValidEntityException;
import jakarta.annotation.PostConstruct;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
@ApplicationScoped
public class TrainerService extends GenericService<Trainer> {
@Inject
TrainerRepository trainerRepository;
@Inject
PokemongService pokemongService;
@PostConstruct
public void init() {
setRepository(trainerRepository);
}
@Override
public Trainer addOne(@NotNull Trainer trainer) {
// TODO if this trainer has a pokemong, make sure that the pokemong's "trainer" field gets updated accordingly
// no validation, pokemongs can changes trainers easily in this app
return super.addOne(trainer);
}
@Override
public void deleteOneById(String id) {
super.deleteOneById(id);
// TODO set trainer reference to null in any pokemong who may have it in their "trainer" field
}
@Nullable
@Override
public Trainer updateOne(@NotNull Trainer trainer) {
Trainer existingTrainer = trainerRepository.findById(trainer.getId());
if (existingTrainer != null) {
existingTrainer.setName(trainer.getName());
existingTrainer.setDob(trainer.getDob());
existingTrainer.setWins(trainer.getLosses());
existingTrainer.setLosses(trainer.getLosses());
existingTrainer.setPastOpponents(trainer.getPastOpponents());
existingTrainer.setPokemongs(trainer.getPokemongs());
trainerRepository.persistOrUpdate(existingTrainer);
}
return existingTrainer;
}
@Override
public void validateOne(Trainer trainer) {
super.validateOne(trainer);
List<String> errors = new ArrayList<>();
if (StringUtils.isBlankStringOrNull(trainer.getName())) {
errors.add("trainer name was null, blank or empty");
}
if (trainer.getDob() == null) {
errors.add("trainer date of birth was null or invalid");
}
if (trainer.getLosses() == null || trainer.getLosses() < 0) {
errors.add("trainer losses was null or negative");
}
if (trainer.getWins() == null || trainer.getWins() < 0) {
errors.add("trainer wins was null or negative");
}
List<String> pastOpponents = trainer.getPastOpponents();
if (pastOpponents == null) {
errors.add("trainer past opponents collection was null");
}
else {
for (String trainerId : pastOpponents) {
if (StringUtils.isBlankStringOrNull(trainerId) || !trainerRepository.existsById(trainerId)) {
errors.add("trainer past opponents collection contained an invalid or unknown id");
}
}
}
List<TrainerPokemong> pokemongs = trainer.getPokemongs();
if (pokemongs == null) {
errors.add("trainer pokemongs collection was null or invalid");
}
else {
for (TrainerPokemong pokemong : pokemongs) {
String pokemongId = pokemong.getId();
if (StringUtils.isBlankStringOrNull(pokemongId) || !pokemongService.existsById(pokemongId)) {
errors.add("pokemong with id " + pokemongId + " does not exist");
}
else {
if (!pokemongService.isEvoValid(pokemongId, pokemong.getSpecies())) {
errors.add("pokemong with id " + pokemongId + " cannot be a " +
pokemong.getSpecies());
}
if (pokemong.getNickname() != null
&& !pokemong.getNickname()
.equals(pokemongService.getOneById(pokemongId)
.getNickname()))
{
errors.add("pokemong with id " + pokemongId + " already has a nickname");
}
}
}
}
if (!errors.isEmpty()) {
throw new NonValidEntityException("Validation errors: " + String.join(", ", errors));
}
}
}

@ -1,7 +1,7 @@
package fr.uca.iut.utils;
public class StringUtils {
public static boolean isBlankString(String string) {
public static boolean isBlankStringOrNull(String string) {
return string == null || string.isBlank();
}
}

@ -5,8 +5,11 @@ info:
version: "1.0.0"
servers:
- url: "http://localhost:8080"
paths:
/pokemong/{id}:
get:
summary: Get a Pokemong by ID
parameters:
@ -27,6 +30,7 @@ paths:
description: Invalid ID format
'404':
description: Entity not found for given ID
put:
summary: Update a Pokemong by ID
parameters:
@ -53,6 +57,7 @@ paths:
description: Invalid ID format or Non-valid entity
'404':
description: Entity not found for given ID
delete:
summary: Delete a Pokemong by ID
parameters:
@ -67,7 +72,9 @@ paths:
description: OK
'400':
description: Invalid ID format
/pokemong:
get:
summary: Get all Pokemongs
responses:
@ -79,6 +86,7 @@ paths:
type: array
items:
$ref: '#/components/schemas/Pokemong'
post:
summary: Create a new Pokemong
requestBody:
@ -96,7 +104,9 @@ paths:
$ref: '#/components/schemas/Pokemong'
'400':
description: Non-valid entity
/move/{id}:
get:
summary: Get a move by ID
parameters:
@ -117,6 +127,7 @@ paths:
description: Invalid ID format
'404':
description: Entity not found for given ID
put:
summary: Update a move by ID
parameters:
@ -143,6 +154,7 @@ paths:
description: Invalid ID format or Non-valid entity
'404':
description: Entity not found for given ID
delete:
summary: Delete a move by ID
parameters:
@ -157,7 +169,9 @@ paths:
description: OK
'400':
description: Invalid ID format
/move:
get:
summary: Get all moves
responses:
@ -169,6 +183,7 @@ paths:
type: array
items:
$ref: '#/components/schemas/Move'
post:
summary: Create a new move
requestBody:
@ -186,8 +201,105 @@ paths:
$ref: '#/components/schemas/Move'
'400':
description: Non-valid entity
/trainer:
get:
summary: Returns a list of all trainers
responses:
'200':
description: A list of trainers
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Trainer'
post:
summary: Creates a new trainer
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Trainer'
responses:
'201':
description: The created trainer
content:
application/json:
schema:
$ref: '#/components/schemas/Trainer'
'400':
description: Bad request - invalid trainer data
/trainer/{id}:
get:
summary: Returns a trainer by ID
parameters:
- in: path
name: id
required: true
schema:
type: string
responses:
'200':
description: A single trainer
content:
application/json:
schema:
$ref: '#/components/schemas/Trainer'
'404':
description: Trainer not found
put:
summary: Updates a trainer by ID
parameters:
- in: path
name: id
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Trainer'
responses:
'200':
description: The updated trainer
content:
application/json:
schema:
$ref: '#/components/schemas/Trainer'
'400':
description: Bad request - invalid trainer data
'404':
description: Trainer not found
delete:
summary: Deletes a trainer by ID
parameters:
- in: path
name: id
required: true
schema:
type: string
responses:
'200':
description: Trainer successfully deleted
'400':
description: Bad request - invalid trainer ID
'404':
description: Trainer not found
components:
schemas:
Pokemong:
type: object
required:
@ -235,6 +347,7 @@ components:
maxItems: 4
items:
$ref: '#/components/schemas/PokemongMove'
Move:
type: object
required:
@ -246,6 +359,7 @@ components:
properties:
name:
type: string
minLength: 1
category:
$ref: '#/components/schemas/MoveCategoryName'
power:
@ -256,19 +370,74 @@ components:
minimum: 0
type:
$ref: '#/components/schemas/TypeName'
Trainer:
type: object
required:
- name
- dob
- wins
- losses
- pastOpponents
- pokemongs
properties:
name:
type: string
minLength: 1
dob:
type: string
format: date
wins:
type: integer
minimum: 0
losses:
type: integer
minimum: 0
pastOpponents:
type: array
items:
type: string
minLength: 1
pokemongs:
type: array
items:
$ref: '#/components/schemas/TrainerPokemong'
PokemongMove:
type: object
required:
- id
- name
properties:
id:
type: string
minLength: 1
name:
type: string
minLength: 1
TrainerPokemong:
type: object
required:
- id
- species
properties:
id:
type: string
minLength: 1
nickname:
type: string
nullable: true
species:
$ref: '#/components/schemas/PokemongName'
MoveCategoryName:
type: string
enum: [
PHYSICAL,
SPECIAL,
STATUS ]
TypeName:
type: string
enum: [
@ -291,6 +460,7 @@ components:
FIGHTING,
FAIRY
]
PokemongName:
type: string
enum: [

Loading…
Cancel
Save