Pular para o conteúdo principal

Endpoints

Esta lista foi montada a partir dos controllers do backend.

Formato comum de erros

Todos os erros são retornados em JSON no formato abaixo (conforme ApiError):

{
"timestamp": "2026-01-10T14:45:01.123Z",
"status": 400,
"code": "VALIDATION_ERROR",
"message": "Falha de validação dos dados enviados.",
"path": "/api/modules",
"details": [
{
"field": "title",
"message": "Título é obrigatório",
"rejectedValue": ""
}
]
}

Campos:

  • timestamp: instante UTC da falha.
  • status: status HTTP.
  • code: código estável de erro.
  • message: mensagem humana.
  • path: endpoint chamado.
  • details: lista de erros detalhados (validação/parse/constraint). Pode vir vazia.

Códigos de erro possíveis no backend:

  • 400: VALIDATION_ERROR, INVALID_JSON, BUSINESS_VALIDATION, BAD_REQUEST.
  • 401: UNAUTHORIZED.
  • 403: FORBIDDEN.
  • 404: RESOURCE_NOT_FOUND.
  • 409: CONFLICT.
  • 429: LOGIN_RATE_LIMIT_EXCEEDED.
  • 500: INTERNAL_ERROR.

AuthController

Base path: /api/auth

POST /api/auth/login (login)

Corpo (JSON)

CampoTipoObrigatórioDescrição
usernamestringSimUsuário para autenticação.
passwordstringSimSenha do usuário.

Respostas

StatusDescriçãoPayload
200Login efetuado com sucesso.{ "token": "<jwt>" }
400Erro de validação/JSON inválido.Formato de erro comum.
401Credenciais inválidas.Formato de erro comum.
429Muitas tentativas de login.Formato de erro comum.
500Falha inesperada.Formato de erro comum.

ContestController

Base path: /api/contests

GET /api/contests (list)

ParâmetroLocalTipoObrigatórioDescrição
pagequeryintegerNãoPágina (default 0, mínimo 0).
sizequeryintegerNãoTamanho (default 20, 1..100).

Respostas

StatusDescriçãoPayload
200Página de contests.Page de ContestResponse.
400Query params inválidos.Formato de erro comum.
500Falha inesperada.Formato de erro comum.

GET /api/contests/{id} (get)

ParâmetroLocalTipoObrigatórioDescrição
idpathintegerSimID do contest.

Respostas: 200, 404, 500.

POST /api/contests (create)

Corpo (JSON)

CampoTipoObrigatórioDescrição
namestringSimNome do contest.
durationMinutesintegerSimDuração (>0).
startDateTimedatetimeSimData/hora de início.
teamBasedbooleanNãoSe é por equipes.
codeforcesMirrorUrlstringNãoURL HTTP/HTTPS opcional.

Respostas: 201, 400, 500.

PUT /api/contests/{id} (update)

Mesma estrutura do create.

Respostas: 200, 400, 404, 500.

DELETE /api/contests/{id} (delete)

Respostas: 200, 404, 500.

GET /api/contests/{contestId}/teams (list teams)

Respostas: 200, 404, 500.

POST /api/contests/{contestId}/teams (register team)

Corpo (JSON)

CampoTipoObrigatórioDescrição
teamNamestringCondicionalObrigatório se teamBased=true.
coachNamestringNãoNome do coach.
institutionstringNãoInstituição.
competitor1NamestringSimCompetidor 1.
competitor2NamestringCondicionalObrigatório se teamBased=true.
competitor3NamestringCondicionalObrigatório se teamBased=true.
reserveNamestringNãoReserva.
cafeComLeitebooleanNãoTime café com leite.

Respostas: 201, 400 (VALIDATION_ERROR/BUSINESS_VALIDATION), 404, 409, 500.

ModuleController

Base path: /api/modules

GET /api/modules (list)

ParâmetroLocalTipoObrigatórioDescrição
pagequeryintegerNãoPágina (default 0, mínimo 0).
sizequeryintegerNãoTamanho (default 20, 1..100).

Respostas: 200, 400, 500.

GET /api/modules/full (list full)

Respostas: 200, 500.

GET /api/modules/{id} (get)

Respostas: 200, 404, 500.

POST /api/modules (create legacy)

CampoTipoObrigatórioDescrição
titlestringSimNome do módulo.
notesstringNãoAnotações.
publishedbooleanNãoPublicado (default true).

Respostas: 201, 400, 500.

POST /api/modules/full (create full)

Corpo ModuleAggregateRequest:

  • title, notes, published
  • lessons[] (title, videoUrl, orderIndex)
  • exercises[] (title, ojUrl, difficulty, tags[])
  • extraMaterials[] (title, url)

Respostas: 201, 400, 500.

PUT /api/modules/full/{id} (update full)

PUT /api/modules/full?id={id} (update full por query)

Mesmo corpo do create full.

Respostas: 200, 400, 404, 500.

PUT /api/modules/{id} (update)

Mesmo corpo do create legacy.

Respostas: 200, 400, 404, 500.

DELETE /api/modules/{id} (delete)

Respostas: 200, 404, 409, 500.

LessonController

Base path: /api/modules/{moduleId}/lessons

GET /api/modules/{moduleId}/lessons (list)

Respostas: 200, 404, 500.

POST /api/modules/{moduleId}/lessons (create)

CampoTipoObrigatórioDescrição
titlestringSimTítulo da lição.
videoUrlstringSimURL do vídeo (http/https).
orderIndexintegerSimOrdem da lição.

Respostas: 201, 400, 404, 500.

PUT /api/modules/{moduleId}/lessons/{lessonId} (update)

Mesmo corpo do create.

Respostas: 200, 400, 404, 500.

DELETE /api/modules/{moduleId}/lessons/{lessonId} (delete)

Respostas: 200, 400 (BUSINESS_VALIDATION quando lição não pertence ao módulo), 404, 500.

ExerciseController

Base path: /api/modules/{moduleId}/exercises

GET /api/modules/{moduleId}/exercises (list)

Respostas: 200, 404, 500.

POST /api/modules/{moduleId}/exercises (create)

CampoTipoObrigatórioDescrição
titlestringSimTítulo do exercício.
ojUrlstringSimURL do juiz online (http/https).
difficultyExerciseDifficultySimDificuldade (enum).
tagsstring[]NãoTags do exercício.

Respostas: 201, 400, 404, 500.

PUT /api/modules/{moduleId}/exercises/{exerciseId} (update)

Mesmo corpo do create.

Respostas: 200, 400, 404, 500.

DELETE /api/modules/{moduleId}/exercises/{exerciseId} (delete)

Respostas: 200, 400 (BUSINESS_VALIDATION quando exercício não pertence ao módulo), 404, 500.

ExtraMaterialController

Base path: /api/modules/{moduleId}/materials

GET /api/modules/{moduleId}/materials (list)

Respostas: 200, 404, 500.

POST /api/modules/{moduleId}/materials (create)

CampoTipoObrigatórioDescrição
titlestringSimTítulo do material.
urlstringSimURL do material (http/https).

Respostas: 201, 400, 404, 500.

PUT /api/modules/{moduleId}/materials/{materialId} (update)

Mesmo corpo do create.

Respostas: 200, 400, 404, 500.

DELETE /api/modules/{moduleId}/materials/{materialId} (delete)

Respostas: 200, 400 (BUSINESS_VALIDATION quando material não pertence ao módulo), 404, 500.

PostController

Base path: /api/posts

GET /api/posts (list)

ParâmetroLocalTipoObrigatórioDescrição
pagequeryintegerNãoPágina (default 0, mínimo 0).
sizequeryintegerNãoTamanho (default 20, 1..100).

Respostas: 200, 400, 500.

GET /api/posts/{id} (get)

Respostas: 200, 404, 500.

POST /api/posts (create)

CampoTipoObrigatórioDescrição
titlestringSimTítulo do post.
tagstringNãoTag/categoria.
slugstringSimSlug (^[a-z0-9]+(?:-[a-z0-9]+)*$).
summarystringNãoResumo.
coverImageUrlstringNãoURL da capa.
authorNamestringSimNome do autor.
statusstringSimStatus do post.
mainTextstringNãoTexto principal.
sectionsarrayNãoSeções do post.

Respostas: 201, 400, 409, 500.

PUT /api/posts/{id} (update)

Mesmo corpo do create.

Respostas: 200, 400, 404, 409, 500.

DELETE /api/posts/{id} (delete)

Respostas: 200, 404, 500.

RegistrationController

Base path: /api/registrations

GET /api/registrations (list)

ParâmetroLocalTipoObrigatórioDescrição
pagequeryintegerNãoPágina (default 0, mínimo 0).
sizequeryintegerNãoTamanho (default 20, 1..100).

Respostas: 200, 400, 500.

GET /api/registrations/{id} (get)

Respostas: 200, 404, 500.

POST /api/registrations (create)

CampoTipoObrigatórioDescrição
namestringSimNome completo.
emailstringSimEmail.
whatsappstringNãoWhatsApp.
institutionstringNãoInstituição.
campusstringSimCampus.
coursestringSimCurso.
semesterstringSimSemestre.
howDidYouHearstringSimComo conheceu.
previousExperiencestringNãoExperiência prévia.
messagestringNãoMensagem adicional.

Respostas: 201, 400, 409, 500.

PUT /api/registrations/{id} (update)

Mesmo corpo do create.

Respostas: 200, 400, 404, 409, 500.

DELETE /api/registrations/{id} (delete)

Respostas: 200, 404, 500.