Skip to main content

API de Treinos

A API de Treinos do FitLocus fornece endpoints para criação, gerenciamento e execução de treinos na plataforma.

Visão Geral

A API de Treinos permite:

  • Criação e gerenciamento de treinos personalizados
  • Organização de exercícios em treinos estruturados
  • Atribuição de treinos a alunos
  • Acompanhamento de execução de treinos
  • Criação e gerenciamento de planos de treino

Modelo de Dados

TrainingDTO

O objeto TrainingDTO é utilizado para transferência de dados de treinos entre o cliente e o servidor:
{
  "id": 101,
  "name": "Treino A - Peito e Tríceps",
  "description": "Treino focado em desenvolvimento de peito e tríceps",
  "createdBy": 456,
  "createdAt": "2023-01-01T10:00:00Z",
  "updatedAt": "2023-01-15T14:30:00Z",
  "exercises": [
    {
      "id": 201,
      "exerciseId": 123,
      "exerciseName": "Supino Reto",
      "sets": 3,
      "repetitions": "12, 10, 8",
      "restTime": 60,
      "notes": "Aumentar carga progressivamente",
      "order": 1
    },
    {
      "id": 202,
      "exerciseId": 124,
      "exerciseName": "Supino Inclinado",
      "sets": 3,
      "repetitions": "12, 10, 8",
      "restTime": 60,
      "notes": "Foco na parte superior do peito",
      "order": 2
    },
    {
      "id": 203,
      "exerciseId": 125,
      "exerciseName": "Tríceps Corda",
      "sets": 3,
      "repetitions": "15, 12, 10",
      "restTime": 45,
      "notes": "Manter cotovelos junto ao corpo",
      "order": 3
    }
  ],
  "isPublic": false,
  "difficulty": "INTERMEDIARIO",
  "estimatedDuration": 45,
  "category": "PEITO_TRICEPS"
}

TrainingPlanDTO

Objeto que representa um plano de treino (conjunto de treinos organizados por dias da semana):
{
  "id": 301,
  "name": "Plano Hipertrofia - Intermediário",
  "description": "Plano de treino para ganho de massa muscular",
  "createdBy": 456,
  "createdAt": "2023-01-01T10:00:00Z",
  "updatedAt": "2023-01-15T14:30:00Z",
  "trainings": [
    {
      "id": 401,
      "trainingId": 101,
      "trainingName": "Treino A - Peito e Tríceps",
      "dayOfWeek": "MONDAY",
      "order": 1
    },
    {
      "id": 402,
      "trainingId": 102,
      "trainingName": "Treino B - Costas e Bíceps",
      "dayOfWeek": "WEDNESDAY",
      "order": 2
    },
    {
      "id": 403,
      "trainingId": 103,
      "trainingName": "Treino C - Pernas e Ombros",
      "dayOfWeek": "FRIDAY",
      "order": 3
    }
  ],
  "isPublic": false,
  "difficulty": "INTERMEDIARIO",
  "goal": "HIPERTROFIA",
  "duration": 12
}

TrainingExecutionDTO

Objeto que representa a execução de um treino:
{
  "id": 501,
  "trainingId": 101,
  "userId": 456,
  "startTime": "2023-05-20T15:00:00Z",
  "endTime": "2023-05-20T15:45:00Z",
  "duration": 2700,
  "completed": true,
  "notes": "Bom treino, aumentei carga no supino",
  "exerciseExecutions": [
    {
      "id": 601,
      "exerciseId": 123,
      "sets": [
        {
          "repetitions": 12,
          "weight": 60.0,
          "completed": true
        },
        {
          "repetitions": 10,
          "weight": 65.0,
          "completed": true
        },
        {
          "repetitions": 8,
          "weight": 70.0,
          "completed": true
        }
      ]
    },
    {
      "id": 602,
      "exerciseId": 124,
      "sets": [
        {
          "repetitions": 12,
          "weight": 50.0,
          "completed": true
        },
        {
          "repetitions": 10,
          "weight": 55.0,
          "completed": true
        },
        {
          "repetitions": 8,
          "weight": 60.0,
          "completed": true
        }
      ]
    }
  ]
}

TrainingAssignmentDTO

Objeto que representa a atribuição de um treino a um aluno:
{
  "id": 701,
  "trainingId": 101,
  "trainingName": "Treino A - Peito e Tríceps",
  "studentId": 789,
  "studentName": "João Silva",
  "personalId": 456,
  "personalName": "Carlos Oliveira",
  "assignedAt": "2023-05-15T10:00:00Z",
  "scheduledDate": "2023-05-20",
  "status": "PENDING",
  "notes": "Foco na técnica e não na carga"
}

Endpoints Principais

MétodoEndpointDescrição
GET/trainingsLista treinos com filtros opcionais
GET/trainings/{id}Obtém detalhes de um treino específico
POST/trainingsCria um novo treino
PUT/trainings/{id}Atualiza um treino existente
DELETE/trainings/{id}Remove um treino
GET/trainings/my-trainingsLista treinos criados pelo usuário autenticado
POST/trainings/{id}/assignAtribui um treino a um aluno
GET/trainings/assignmentsLista atribuições de treinos
POST/trainings/{id}/executionRegistra uma execução de treino
GET/trainings/{id}/executionsLista execuções de um treino específico
GET/training-plansLista planos de treino
GET/training-plans/{id}Obtém detalhes de um plano de treino específico
POST/training-plansCria um novo plano de treino
PUT/training-plans/{id}Atualiza um plano de treino existente
DELETE/training-plans/{id}Remove um plano de treino

Detalhes de Implementação

Autenticação

Todos os endpoints requerem autenticação via token JWT no cabeçalho Authorization:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Para mais detalhes sobre autenticação, consulte a documentação de autenticação.

Controle de Acesso

O acesso aos endpoints é controlado com base no tipo de usuário e propriedade do recurso:
  • Personal trainers podem criar, visualizar, atualizar e remover seus próprios treinos
  • Personal trainers só podem atribuir treinos aos seus alunos vinculados
  • Alunos só podem visualizar treinos atribuídos a eles
  • Alunos só podem registrar execuções de treinos atribuídos a eles

Paginação e Ordenação

Endpoints que retornam listas de treinos suportam paginação e ordenação através dos seguintes parâmetros:
  • page: Número da página (começando em 0)
  • size: Tamanho da página (número de itens por página)
  • sort: Campo e direção de ordenação (ex: name,asc)

Exemplos de Uso

Listar Treinos

curl -X GET \
  'http://localhost:8080/api/trainings?page=0&size=10&sort=name,asc' \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'

Obter Detalhes de um Treino

curl -X GET \
  'http://localhost:8080/api/trainings/101' \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'

Criar um Novo Treino

curl -X POST \
  'http://localhost:8080/api/trainings' \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Treino A - Peito e Tríceps",
    "description": "Treino focado em desenvolvimento de peito e tríceps",
    "exercises": [
      {
        "exerciseId": 123,
        "sets": 3,
        "repetitions": "12, 10, 8",
        "restTime": 60,
        "notes": "Aumentar carga progressivamente",
        "order": 1
      },
      {
        "exerciseId": 124,
        "sets": 3,
        "repetitions": "12, 10, 8",
        "restTime": 60,
        "notes": "Foco na parte superior do peito",
        "order": 2
      },
      {
        "exerciseId": 125,
        "sets": 3,
        "repetitions": "15, 12, 10",
        "restTime": 45,
        "notes": "Manter cotovelos junto ao corpo",
        "order": 3
      }
    ],
    "isPublic": false,
    "difficulty": "INTERMEDIARIO",
    "estimatedDuration": 45,
    "category": "PEITO_TRICEPS"
  }'

Atribuir Treino a um Aluno

curl -X POST \
  'http://localhost:8080/api/trainings/101/assign' \
  -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' \
  -H 'Content-Type: application/json' \
  -d '{
    "studentId": 789,
    "scheduledDate": "2023-05-20",
    "notes": "Foco na técnica e não na carga"
  }'

Códigos de Status

CódigoDescrição
200OK - A requisição foi bem-sucedida
201Created - Um novo treino, plano ou execução foi criado com sucesso
400Bad Request - A requisição contém dados inválidos
401Unauthorized - Autenticação necessária
403Forbidden - Sem permissão para acessar o recurso
404Not Found - Treino, plano ou recurso não encontrado
500Internal Server Error - Erro interno do servidor

Considerações de Segurança

  1. Validação de Dados: Todos os dados de entrada são validados para prevenir injeção de dados maliciosos.
  2. Controle de Acesso: Verificações rigorosas garantem que um usuário só possa acessar e modificar seus próprios treinos ou, no caso de personal trainers, os treinos atribuídos aos seus alunos.
  3. Sanitização de Dados: Todos os dados de entrada são sanitizados antes de serem armazenados ou exibidos.
  4. HTTPS: Todas as comunicações com a API devem ser realizadas através de HTTPS.

Implementação no Frontend

Componente de Listagem de Treinos

// Exemplo de componente de listagem de treinos em React
import React, { useEffect, useState } from 'react';
import axios from 'axios';

const TrainingList = () => {
  const [trainings, setTrainings] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  const [filters, setFilters] = useState({
    page: 0,
    size: 10,
    sort: 'name,asc'
  });
  
  useEffect(() => {
    const fetchTrainings = async () => {
      try {
        setLoading(true);
        
        // Construir query string a partir dos filtros
        const queryParams = new URLSearchParams();
        queryParams.append('page', filters.page.toString());
        queryParams.append('size', filters.size.toString());
        queryParams.append('sort', filters.sort);
        
        const response = await axios.get(`/trainings?${queryParams.toString()}`);
        setTrainings(response.data.content);
        setLoading(false);
      } catch (err) {
        setError(err.response?.data?.message || 'Erro ao carregar treinos');
        setLoading(false);
      }
    };
    
    fetchTrainings();
  }, [filters]);
  
  if (loading) return <div>Carregando...</div>;
  if (error) return <div>Erro: {error}</div>;
  
  return (
    <div className="training-list">
      <h2>Meus Treinos</h2>
      
      <div className="training-grid">
        {trainings.map(training => (
          <div key={training.id} className="training-card">
            <h3>{training.name}</h3>
            <p className="description">{training.description}</p>
            <p className="details">
              <span className="difficulty">{training.difficulty}</span>
              <span className="duration">{training.estimatedDuration} min</span>
              <span className="exercises">{training.exercises.length} exercícios</span>
            </p>
            <div className="actions">
              <button className="view-details">Ver Detalhes</button>
              <button className="assign">Atribuir</button>
            </div>
          </div>
        ))}
      </div>
      
      <div className="pagination">
        <button
          disabled={filters.page === 0}
          onClick={() => setFilters(prev => ({ ...prev, page: prev.page - 1 }))}
        >
          Anterior
        </button>
        <span>Página {filters.page + 1}</span>
        <button
          disabled={trainings.length < filters.size}
          onClick={() => setFilters(prev => ({ ...prev, page: prev.page + 1 }))}
        >
          Próxima
        </button>
      </div>
    </div>
  );
};

export default TrainingList;

Próximos Passos

Para mais detalhes sobre endpoints específicos, consulte: