Skip to content

Lucas Marques — back-end PHP challenge - #212

Open
yLukas077 wants to merge 13 commits into
Apiki:masterfrom
yLukas077:lucas-marques
Open

Lucas Marques — back-end PHP challenge#212
yLukas077 wants to merge 13 commits into
Apiki:masterfrom
yLukas077:lucas-marques

Conversation

@yLukas077

Copy link
Copy Markdown

Resumo

REST API de conversão de moedas conforme a spec, implementada em PHP 8.1+ orientada a objetos.

Endpoint: GET /exchange/{amount}/{from}/{to}/{rate}

Exemplo literal do enunciado: ao chamar curl http://localhost:8000/exchange/10/BRL/USD/4.50, a resposta é {"valorConvertido":45,"simboloMoeda":"$"}.

Como rodar

Direto:

  • composer install
  • php -S localhost:8000 src/index.php
  • composer test — Codeception
  • composer unit-test — PHPUnit (cobertura unitária)
  • composer lint — phpcs PSR-12

Via Docker:

  • docker compose up app — API em :8000
  • docker compose run --rm test — Codeception
  • docker compose run --rm unit-test — PHPUnit
  • docker compose run --rm lint — phpcs

Cobertura de testes

  • 15 testes Codeception — todos os 4 caminhos de conversão (BRL↔USD, BRL↔EUR) + caminhos de erro (segmentos faltando, valores inválidos, moedas não suportadas, valores/rates negativos). Inclui o exemplo literal do enunciado.
  • 46 testes PHPUnit — cobertura unitária de Currency, Exchange e Request.
  • phpcs PSR-12 limpo.

Decisões de design

Documentadas no README.md.

yLukas077 added 13 commits May 14, 2026 15:47
Configure PSR-4 autoload (App\), PHPUnit, Codeception, and PSR-12
PHP_CodeSniffer ruleset. Define composer scripts for test, lint,
and unit-test.
Currency is a backed enum with the three supported codes (BRL, USD,
EUR) and a symbol() method. ExchangeInput is an immutable readonly
value object that carries validated parameters between layers.

Modeling these at the type level guarantees that invalid currency
codes or non-validated data cannot flow through the system.
Carries the HTTP status code in getCode() so callers can map
business-rule violations directly to HTTP responses without
inspecting the message text.
Exchange operates on a validated ExchangeInput. Uses round() to
2 decimal places to avoid IEEE 754 floating-point drift on
monetary values (e.g. 0.1 * 3 = 0.30000000000000004).
Parses and validates the URI path
/exchange/{amount}/{from}/{to}/{rate}, returning an
ExchangeInput on success or throwing ExchangeException with
HTTP 400 on any malformed input.

Validation is regex-based to reject scientific notation and
ambiguous numeric formats that is_numeric() would accept.
Centralizes HTTP response writing. Uses JSON_THROW_ON_ERROR so
encoding failures surface as JsonException instead of silently
emitting an empty body.
Composes Request, Exchange, and Response. Catches
ExchangeException (mapped to its HTTP code) and JsonException
(mapped to 500), with a fallback Throwable handler.
46 unit tests covering Currency enum behavior, Exchange
conversion math and rounding, and the full Request parsing
contract (valid inputs, malformed segments, unsupported
currencies, edge cases like zero, negatives, and query strings).
15 end-to-end tests covering the four required currency
conversion paths plus all error responses (missing segments,
invalid values, unsupported currencies, negative numbers).
Includes the literal example from the challenge specification.
Dockerfile builds a PHP 8.3 CLI image and runs composer install
(respecting the lock file). docker-compose exposes services for
app, test, unit-test, and lint, isolating each command from the
host. GitHub Actions runs lint and test on every pull request.
Documents the endpoint, run instructions (direct and via
Docker), project structure, and design decisions per file.
The previous lock pinned phpspec/prophecy v1.15.0, which does
not support PHP 8.2+. Updated prophecy to v1.22.0 along with
12 transitive dependencies, all compatible with the PHP 8.3
image used in the Dockerfile.
- remove placeholder @author docblocks across src/*.php
- rename test tryApiWithoutValue to tryApiPrefixOnly to match what
  it actually exercises (the prefix-only path /exchange)
- return 405 Method Not Allowed for non-GET requests in index.php;
  spec defines GET only
- replace flaky sleep 2 in CI with curl polling against /exchange
  for deterministic server readiness
- annotate phpunit.xml with note about PHPUnit 10+ schema migration
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant