<p><strong>Meta Description:</strong> Aprenda a projetar e testar APIs REST: HTTP methods, status codes, versionamento, autenticação, documentação e segurança.</p>

<hr>
<h2>Princípios REST</h2>

<h3>Constraints REST</h3>
<ol><li><strong>Client-Server</strong>: Separação de interesses</li>
<li><strong>Stateless</strong>: Cada requisição contém toda informação</li>
<li><strong>Cacheable</strong>: Respostas podem ser cacheadas</li>
<li><strong>Uniform Interface</strong>: Interface consistente</li>
<li><strong>Layered System</strong>: Arquitetura em camadas</li>
</ol>
<hr>
<h2>HTTP Methods</h2>

<figure class="wp-block-table"><table>
<tr><th>Método</th><th>Semântica</th><th>Idempotente</th><th>Safe</th></tr>
<tr><td>GET</td><td>Ler recurso</td><td>Sim</td><td>Sim</td></tr>
<tr><td>POST</td><td>Criar recurso</td><td>Não</td><td>Não</td></tr>
<tr><td>PUT</td><td>Substituir recurso</td><td>Sim</td><td>Não</td></tr>
<tr><td>PATCH</td><td>Atualizar parcialmente</td><td>Não</td><td>Não</td></tr>
<tr><td>DELETE</td><td>Remover recurso</td><td>Sim</td><td>Não</td></tr>
<tr><td>HEAD</td><td>Ler headers</td><td>Sim</td><td>Sim</td></tr>
<tr><td>OPTIONS</td><td>Verbos suportados</td><td>Sim</td><td>Sim</td></tr>
</table></figure>

<hr>
<h2>Status Codes</h2>

<h3>2xx Success</h3>

<figure class="wp-block-table"><table>
<tr><th>Código</th><th>Significado</th><th>Uso</th></tr>
<tr><td>200</td><td>OK</td><td>GET, PUT, PATCH bem-sucedido</td></tr>
<tr><td>201</td><td>Created</td><td>POST que cria recurso</td></tr>
<tr><td>202</td><td>Accepted</td><td>Async processing</td></tr>
<tr><td>204</td><td>No Content</td><td>DELETE bem-sucedido</td></tr>
</table></figure>

<h3>3xx Redirection</h3>

<figure class="wp-block-table"><table>
<tr><th>Código</th><th>Significado</th><th>Uso</th></tr>
<tr><td>301</td><td>Moved Permanently</td><td>Redirect permanente</td></tr>
<tr><td>302</td><td>Found</td><td>Redirect temporário</td></tr>
<tr><td>304</td><td>Not Modified</td><td>Cache válido</td></tr>
</table></figure>

<h3>4xx Client Error</h3>

<figure class="wp-block-table"><table>
<tr><th>Código</th><th>Significado</th><th>Uso</th></tr>
<tr><td>400</td><td>Bad Request</td><td>Dados inválidos</td></tr>
<tr><td>401</td><td>Unauthorized</td><td>Não autenticado</td></tr>
<tr><td>403</td><td>Forbidden</td><td>Sem permissão</td></tr>
<tr><td>404</td><td>Not Found</td><td>Recurso não existe</td></tr>
<tr><td>409</td><td>Conflict</td><td>Conflito de estado</td></tr>
<tr><td>422</td><td>Unprocessable</td><td>Validação falhou</td></tr>
<tr><td>429</td><td>Too Many Requests</td><td>Rate limit</td></tr>
</table></figure>

<h3>5xx Server Error</h3>

<figure class="wp-block-table"><table>
<tr><th>Código</th><th>Significado</th><th>Uso</th></tr>
<tr><td>500</td><td>Internal Server Error</td><td>Erro genérico</td></tr>
<tr><td>502</td><td>Bad Gateway</td><td>Gateway inválido</td></tr>
<tr><td>503</td><td>Service Unavailable</td><td>Manutenção</td></tr>
<tr><td>504</td><td>Gateway Timeout</td><td>Timeout</td></tr>
</table></figure>

<hr>
<h2>Design de Endpoints</h2>

<h3>Resource Naming</h3>

<pre><code># BOAS PRÁTICAS

<p># Recursos (substantivos, não verbos)<br>GET    /users              # Lista usuários<br>GET    /users/{id}         # Busca usuário<br>POST   /users              # Cria usuário<br>PUT    /users/{id}         # Atualiza usuário<br>DELETE /users/{id}         # Remove usuário</p>

<p># Sub-recursos<br>GET    /users/{id}/orders          # Pedidos do usuário<br>GET    /users/{id}/orders/{orderId}  # Pedido específico<br>POST   /users/{id}/orders          # Cria pedido para usuário</p>

<p># Evite:<br>GET /getUsers<br>POST /createUser<br>PUT /updateUserData<br></code></pre></p>

<h3>Versionamento</h3>

<pre><code># Via URL (mais comum)
GET /v1/users
GET /v2/users

<p># Via Header<br>Accept: application/vnd.api.v2+json</p>

<p># Via Query Param (evite)<br>GET /users?version=2<br></code></pre></p>

<hr>
<h2>Autenticação e Autorização</h2>

<h3>Bearer Token (JWT)</h3>

<pre><code># Flask API
from flask import Flask, request, jsonify
import jwt

<p>app = Flask(__name__)<br>SECRET_KEY = "your-secret-key"</p>

<p>@app.route("/protected")<br>def protected():<br>    token = request.headers.get("Authorization", "").replace("Bearer ", "")</p>

<p>if not token:<br>        return jsonify({"error": "Token required"}), 401</p>

<p>try:<br>        payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])<br>        return jsonify({<br>            "user_id": payload["sub"],<br>            "role": payload["role"]<br>        })<br>    except jwt.ExpiredSignatureError:<br>        return jsonify({"error": "Token expired"}), 401<br>    except jwt.InvalidTokenError:<br>        return jsonify({"error": "Invalid token"}), 401</p>

<p>@app.route("/login", methods=["POST"])<br>def login():<br>    # Validate credentials<br>    user = validate_credentials(request.json)</p>

<p>token = jwt.encode({<br>        "sub": user.id,<br>        "role": user.role,<br>        "exp": datetime.utcnow() + timedelta(hours=1)<br>    }, SECRET_KEY, algorithm="HS256")</p>

<p>return jsonify({"token": token})<br></code></pre></p>

<h3>OAuth 2.0</h3>

<pre><code># Flask + OAuth
from authlib.integrations.flask_client import OAuth

<p>oauth = OAuth(app)<br>google = oauth.register(name='google')</p>

<p>@app.route("/login/google")<br>def login_google():<br>    return google.authorize_redirect(redirect_uri=url_for("callback", _external=True))</p>

<p>@app.route("/callback/google")<br>def callback():<br>    token = google.authorize_access_token()<br>    user_info = google.get("userinfo").json()<br>    # Create session<br>    return jsonify(user_info)<br></code></pre></p>

<hr>
<h2>Documentação OpenAPI</h2>

<pre><code># openapi.yaml
openapi: 3.0.3
info:
  title: E-commerce API
  version: 1.0.0
  description: API for e-commerce platform

<p>servers:<br>  - url: https://api.exemplo.com/v1<br>    description: Production<br>  - url: https://staging.exemplo.com/v1<br>    description: Staging</p>

<p>paths:<br>  /users:<br>    get:<br>      summary: List users<br>      parameters:<br>        - name: page<br>          in: query<br>          schema:<br>            type: integer<br>            default: 1<br>        - name: limit<br>          in: query<br>          schema:<br>            type: integer<br>            default: 20<br>            maximum: 100<br>      responses:<br>        '200':<br>          description: List of users<br>          content:<br>            application/json:<br>              schema:<br>                type: object<br>                properties:<br>                  data:<br>                    type: array<br>                    items:<br>                      $ref: '#/components/schemas/User'<br>                  pagination:<br>                    $ref: '#/components/schemas/Pagination'<br>        '401':<br>          $ref: '#/components/responses/Unauthorized'</p>

<p>post:<br>      summary: Create user<br>      requestBody:<br>        required: true<br>        content:<br>          application/json:<br>            schema:<br>              $ref: '#/components/schemas/CreateUser'<br>      responses:<br>        '201':<br>          description: User created<br>          content:<br>            application/json:<br>              schema:<br>                $ref: '#/components/schemas/User'<br>        '422':<br>          $ref: '#/components/responses/ValidationError'</p>

<p>components:<br>  schemas:<br>    User:<br>      type: object<br>      properties:<br>        id:<br>          type: integer<br>        name:<br>          type: string<br>        email:<br>          type: string<br>          format: email<br>        created_at:<br>          type: string<br>          format: date-time</p>

<p>CreateUser:<br>      type: object<br>      required:<br>        - name<br>        - email<br>        - password<br>      properties:<br>        name:<br>          type: string<br>          minLength: 1<br>        email:<br>          type: string<br>          format: email<br>        password:<br>          type: string<br>          minLength: 8</p>

<p>responses:<br>    Unauthorized:<br>      description: Authentication required<br>      content:<br>        application/json:<br>          schema:<br>            type: object<br>            properties:<br>              error:<br>                type: string</p>

<p>ValidationError:<br>      description: Validation failed<br>      content:<br>        application/json:<br>          schema:<br>            type: object<br>            properties:<br>              errors:<br>                type: array<br>                items:<br>                  type: object<br>                  properties:<br>                    field:<br>                      type: string<br>                    message:<br>                      type: string<br></code></pre></p>

<hr>
<h2>Conclusão</h2>

<p>API REST bem desenhada é crucial para integrações. As chaves são:<br><ol><li><strong>HTTP semantics corretas</strong> - Métodos e status codes</li><br><li><strong>Recursos bem nomeados</strong> - Substantivos, não verbos</li><br><li><strong>Documentação completa</strong> - OpenAPI/Swagger</li><br><li><strong>Autenticação segura</strong> - JWT/OAuth</li><br><li><strong>Versionamento</strong> - Para evoluir sem quebrar</li></ol></p>