一键导入
postman-development
Skill completa para desenvolvimento e documentação de APIs usando Postman, incluindo automação, CI/CD, e geração a partir de OpenAPI.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Skill completa para desenvolvimento e documentação de APIs usando Postman, incluindo automação, CI/CD, e geração a partir de OpenAPI.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | postman-development |
| description | Skill completa para desenvolvimento e documentação de APIs usando Postman, incluindo automação, CI/CD, e geração a partir de OpenAPI. |
| triggers | ["postman","api documentation","newman","collection","openapi","jwt","session auth","api testing"] |
Skill completa para desenvolvimento, documentação e automação de APIs usando Postman, seguindo padrões de produção e melhores práticas de mercado.
Aplicar esta skill quando:
{
"info": {
"_postman_id": "unique-id",
"name": "Nome da API - Documentação",
"description": "# Descrição Completa\n\n## Visão Geral\n...",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
}
}
Requisitos:
Collection/
├── Authentication/
│ ├── Login
│ ├── Refresh Token
│ └── Validate Token
├── [Módulo Principal]/
│ ├── [Submódulo]/
│ │ ├── List [Resource]
│ │ ├── Create [Resource]
│ │ ├── Get [Resource]
│ │ ├── Update [Resource]
│ │ └── Delete [Resource]
│ └── [Outro Submódulo]/
└── Dashboard/
├── Filters
├── Stats
└── Charts/
Padrões de Nomenclatura:
Authentication, Financial KPIs)List Contracts, Create Contract){
"id": "postman-env-default",
"name": "Local Env",
"values": [
{ "key": "base_url", "value": "http://localhost:8000", "enabled": true },
{ "key": "auth_token", "value": "", "enabled": true },
{ "key": "refresh_token", "value": "", "enabled": true },
{ "key": "auth_expires_at", "value": "", "enabled": true },
{ "key": "user_email", "value": "test@example.com", "enabled": true },
{ "key": "user_password", "value": "changeme", "enabled": true }
]
}
Variáveis padrão:
base_url: URL base da aplicaçãoauth_token: Token JWT (preenchido automaticamente)refresh_token: Refresh token (preenchido automaticamente)auth_expires_at: Timestamp de expiração do tokenuser_email: Email do usuário de testeuser_password: Senha do usuário de testePara Django DRF:
admin_username: Username do adminadmin_password: Password do adminencoded_token: Token codificado (alternativa)Snippet obrigatório para todas as collections com JWT:
// Collection-level pre-request: attach Bearer token and auto-refresh
// 1. Attach Authorization header if token exists
if (pm.environment.get('auth_token')) {
pm.request.headers.upsert({
key: 'Authorization',
value: 'Bearer ' + pm.environment.get('auth_token')
});
}
// 2. Auto-refresh token if expired
let expiresAt = pm.environment.get('auth_expires_at');
if (expiresAt && Date.now() >= parseInt(expiresAt)) {
console.log('Access token expired — attempting refresh...');
let refreshReq = {
url: pm.environment.get('base_url') + '/auth/refresh',
method: 'POST',
header: { 'Content-Type': 'application/json' },
body: {
mode: 'raw',
raw: JSON.stringify({
refresh_token: pm.environment.get('refresh_token')
})
}
};
pm.sendRequest(refreshReq, function (err, res) {
if (!err && res.code === 200) {
let json = res.json();
if (json.access_token) {
pm.environment.set('auth_token', json.access_token);
}
if (json.refresh_token) {
pm.environment.set('refresh_token', json.refresh_token);
}
if (json.expires_in) {
pm.environment.set('auth_expires_at', Date.now() + (json.expires_in * 1000));
}
} else {
console.error('Refresh failed', err || res);
}
});
}
Para endpoints que requerem autenticação mas não têm token:
// Verificar se token existe, se não, fazer login
if (!pm.environment.get("auth_token")) {
pm.sendRequest({
url: pm.environment.get("base_url") + "/auth/login",
method: "POST",
header: {
"Content-Type": "application/json"
},
body: {
mode: "raw",
raw: JSON.stringify({
email: pm.environment.get("user_email"),
password: pm.environment.get("user_password")
})
}
}, function (err, res) {
if (res.code === 200) {
const jsonData = res.json();
if (jsonData.access_token) {
pm.environment.set("auth_token", jsonData.access_token);
}
if (jsonData.refresh_token) {
pm.environment.set("refresh_token", jsonData.refresh_token);
}
if (jsonData.expires_in) {
pm.environment.set("auth_expires_at", Date.now() + (jsonData.expires_in * 1000));
}
}
});
}
// Gerar timestamp atual
pm.environment.set("current_timestamp", new Date().toISOString());
// Gerar data futura
const futureDate = new Date();
futureDate.setDate(futureDate.getDate() + 30);
pm.environment.set("future_date", futureDate.toISOString().split('T')[0]);
Snippet obrigatório para endpoint /auth/login:
// Test: Save tokens from login response
pm.test("Login successful", function () {
pm.response.to.have.status(200);
});
let res = pm.response.json();
if (res.access_token) {
pm.environment.set('auth_token', res.access_token);
}
if (res.refresh_token) {
pm.environment.set('refresh_token', res.refresh_token);
}
if (res.expires_in) {
let expiresAt = Date.now() + (res.expires_in * 1000);
pm.environment.set('auth_expires_at', expiresAt);
}
pm.test("Status code is 200", function () {
pm.response.to.have.status(200);
});
pm.test("Response has required fields", function () {
const jsonData = pm.response.json();
pm.expect(jsonData).to.have.property("id");
pm.expect(jsonData).to.have.property("name");
});
pm.test("Response data types are correct", function () {
const jsonData = pm.response.json();
pm.expect(jsonData.id).to.be.a("string");
pm.expect(jsonData.count).to.be.a("number");
});
if (pm.response.code === 200) {
const jsonData = pm.response.json();
pm.environment.set("resource_id", jsonData.id);
pm.environment.set("logged_user", jsonData.user.id);
}
Cada endpoint DEVE ter descrição completa em Markdown:
## [Nome do Endpoint]
### Validações
- campo (tipo): Descrição → status_code: "mensagem de erro"
- campo (tipo): Descrição → status_code: "mensagem de erro"
### Regras de Negócio
- Regra 1
- Regra 2
- Regra 3
### Erros
- status_code: Descrição do erro
- status_code: Descrição do erro
Exemplo:
## Login
### Validações
- email (string): Obrigatório → 422: "Email is required"
- password (string): Obrigatório → 422: "Password is required"
### Regras de Negócio
- Credenciais devem estar corretas
- Usuário deve estar ativo
- Token válido por 24h (access_token)
- Refresh token válido por 7 dias
### Erros
- 422: Email/Password ausente
- 401: Credenciais inválidas
- 403: Usuário inativo
Cada endpoint DEVE ter:
Exemplo de Sucesso (status 200/201)
Exemplos de Erro de Validação (status 400/422)
Exemplos de Erro de Negócio (status 404/403/401)
{
"name": "✅ Sucesso - Contrato criado",
"code": 201,
"body": "{\n \"id\": 1,\n \"term_number\": \"123/2024\",\n \"status\": \"active\"\n}"
}
{
"name": "❌ 422 - term_number ausente",
"code": 422,
"body": "{\n \"detail\": [\n {\n \"type\": \"value_error.missing\",\n \"loc\": [\"body\", \"term_number\"],\n \"msg\": \"This field is required.\"\n }\n ]\n}"
}
{
"key": "year",
"value": "2024",
"description": "Ano para filtrar os dados (formato: YYYY).",
"disabled": true
}
Requisitos:
{
"variable": [
{
"key": "id",
"value": "1",
"description": "ID do contrato (número inteiro)."
}
]
}
Para JSON:
{{variable_name}}Para multipart/form-data:
### Campo: status
**Tipo:** ChoiceField
**Valores aceitos:**
- `PENDING`: Pendente
- `PROCESSING`: Processando
- `COMPLETED`: Concluído
- `FAILED`: Falha
Endpoints típicos:
POST /auth/login → retorna { access_token, refresh_token, expires_in }POST /auth/refresh → retorna novo access_token (rotacionar refresh token)POST /auth/logout → invalidar refresh token (DB ou blacklist)Configuração recomendada:
access_token: expiração curta (ex: 15 minutos)refresh_token: long-lived (ex: 7 dias)Para APIs que usam sessão:
Set-Cookie se necessário// Para Django DRF com Session
pm.request.headers.upsert({
key: 'X-CSRFToken',
value: pm.cookies.get('csrftoken')
});
Newman é o CLI (Command Line Interface) do Postman. Ele NÃO converte documentação em collection. Ele executa uma collection Postman já existente.
Diferença importante:
Arquivo: scripts/run_newman.sh
Este script executa uma collection Postman usando o Newman:
#!/usr/bin/env bash
# Runs Newman against the collection and environment.
# Usage: ./run_newman.sh [collection.json] [environment.json]
COLLECTION=${1:-postman/collection.json}
ENV=${2:-postman/environment.json}
REPORT_DIR=${REPORT_DIR:-reports/postman}
mkdir -p "$REPORT_DIR"
# EXECUTA a collection (não converte!)
npx newman run "$COLLECTION" -e "$ENV" \
--reporters cli,junit,html \
--reporter-junit-export "$REPORT_DIR/junit-results.xml" \
--reporter-html-export "$REPORT_DIR/report.html"
EXIT_CODE=$?
if [ $EXIT_CODE -ne 0 ]; then
echo "Newman tests failed (exit $EXIT_CODE)"
exit $EXIT_CODE
fi
echo "Newman finished."
# Executar com defaults (usa postman/collection.json)
./scripts/run_newman.sh
# Especificar collection e environment
./scripts/run_newman.sh postman/collection.json postman/environment.json
O que acontece:
collection.json)Arquivo: .github/workflows/postman-ci.yml
name: Postman Collection Tests
on:
push:
branches: [ main, master ]
pull_request:
jobs:
postman-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install dependencies
run: npm ci || npm i
- name: Install jq (for environment manipulation)
run: sudo apt-get update && sudo apt-get install -y jq
- name: Run Newman (Postman tests)
env:
BASE_URL: ${{ secrets.BASE_URL }}
USER_EMAIL: ${{ secrets.TEST_USER_EMAIL }}
USER_PASSWORD: ${{ secrets.TEST_USER_PASSWORD }}
run: |
# Write environment with secrets
jq '.values[] |= (if .key=="base_url" then .value="'$BASE_URL'" elif .key=="user_email" then .value="'$USER_EMAIL'" elif .key=="user_password" then .value="'$USER_PASSWORD'" else . end)' postman/environment.json > tmp_env.json
npx newman run postman/collection.json -e tmp_env.json \
--reporters cli,junit \
--reporter-junit-export postman/junit-results.xml
- name: Upload results
uses: actions/upload-artifact@v4
with:
name: postman-results
path: postman/junit-results.xml
Configurar no GitHub Repository Settings → Secrets:
BASE_URL: URL base da API (ex: https://api.example.com)TEST_USER_EMAIL: Email do usuário de testeTEST_USER_PASSWORD: Senha do usuário de testeConversão (OpenAPI → Postman):
openapi-to-postmanv2 ou postman-collection-transformerExecução (Newman):
newman (via run_newman.sh)Express.js:
npm install swagger-jsdoc
# Gera openapi.json automaticamente
Django DRF:
pip install drf-spectacular
# Gera openapi.json via /api/schema/
FastAPI:
# OpenAPI gerado automaticamente em /openapi.json
Script: generate-from-openapi.sh
#!/usr/bin/env bash
# Gera collection Postman a partir de OpenAPI/Swagger
# Usage: ./generate-from-openapi.sh [openapi.json] [output-dir]
OPENAPI_FILE=${1:-openapi.json}
OUTPUT_DIR=${2:-postman}
# Instalar ferramenta se necessário
if ! command -v openapi-to-postmanv2 &> /dev/null; then
npm install -g openapi-to-postmanv2
fi
# Converter OpenAPI para Postman
openapi-to-postmanv2 -s "$OPENAPI_FILE" -o "$OUTPUT_DIR/collection.json"
echo "✅ Collection gerada em $OUTPUT_DIR/collection.json"
Uso:
# Converter openapi.json para postman/collection.json
./generate-from-openapi.sh openapi.json postman
# Ou especificar arquivo diferente
./generate-from-openapi.sh docs/swagger.json postman
Após a conversão, você precisa adicionar manualmente (ou via script):
Exemplo de script Python para injetar scripts:
import json
# Ler collection gerada
with open('postman/collection.json', 'r') as f:
collection = json.load(f)
# Adicionar pre-request script (collection-level)
collection['event'] = [{
"listen": "prerequest",
"script": {
"exec": [
"// Auto-attach Bearer token",
"if (pm.environment.get('auth_token')) {",
" pm.request.headers.upsert({ key: 'Authorization', value: 'Bearer ' + pm.environment.get('auth_token') });",
"}"
],
"type": "text/javascript"
}
}]
# Salvar collection atualizada
with open('postman/collection.json', 'w') as f:
json.dump(collection, f, indent=2)
Agora sim, usar o run_newman.sh:
# Executar testes da collection gerada
./run_newman.sh postman/collection.json postman/environment.json
postman/collections.publish1. OpenAPI/Swagger (gerado pelo framework)
↓
2. openapi-to-postmanv2 (CONVERTE)
↓
3. postman/collection.json (collection gerada)
↓
4. Adicionar scripts manualmente (autenticação, testes)
↓
5. run_newman.sh (EXECUTA testes)
↓
6. Relatórios (junit-results.xml, report.html)
Estrutura mínima:
{
"info": {
"name": "API - Boilerplate (Auth + CRUD)",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"description": "Coleção padrão: Auth (JWT), exemplos CRUD."
},
"item": [
{
"name": "Auth",
"item": [
{
"name": "POST /auth/login",
"request": {
"method": "POST",
"header": [
{ "key": "Content-Type", "value": "application/json" }
],
"body": {
"mode": "raw",
"raw": "{\n \"email\": \"{{user_email}}\",\n \"password\": \"{{user_password}}\"\n}"
},
"url": {
"raw": "{{base_url}}/auth/login",
"host": ["{{base_url}}"],
"path": ["auth","login"]
}
},
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('status 200', function () { pm.response.to.have.status(200); });",
"let res = pm.response.json();",
"if(res.access_token){ pm.environment.set('auth_token', res.access_token); }",
"if(res.refresh_token){ pm.environment.set('refresh_token', res.refresh_token); }",
"if(res.expires_in){ let expiresAt = Date.now() + (res.expires_in * 1000); pm.environment.set('auth_expires_at', expiresAt); }"
],
"type": "text/javascript"
}
}
]
}
]
}
],
"event": [
{
"listen": "prerequest",
"script": {
"exec": [
"// Collection-level pre-request: attach Authorization header if auth_token present",
"if (pm.environment.get('auth_token')) {",
" pm.request.headers.upsert({ key: 'Authorization', value: 'Bearer ' + pm.environment.get('auth_token') });",
"}",
"",
"// Auto-refresh if token expired",
"let expiresAt = pm.environment.get('auth_expires_at');",
"if (expiresAt && Date.now() >= parseInt(expiresAt)) {",
" console.log('Access token expired — attempting refresh...');",
" let refreshReq = {",
" url: pm.environment.get('base_url') + '/auth/refresh',",
" method: 'POST',",
" header: { 'Content-Type': 'application/json' },",
" body: { mode: 'raw', raw: JSON.stringify({ refresh_token: pm.environment.get('refresh_token') }) }",
" };",
" pm.sendRequest(refreshReq, function (err, res) {",
" if (!err && res.code === 200) {",
" let json = res.json();",
" if (json.access_token) { pm.environment.set('auth_token', json.access_token); }",
" if (json.refresh_token) { pm.environment.set('refresh_token', json.refresh_token); }",
" if (json.expires_in) { pm.environment.set('auth_expires_at', Date.now() + (json.expires_in * 1000)); }",
" } else { console.error('Refresh failed', err || res); }",
" });",
"}"
],
"type": "text/javascript"
}
}
]
}
Endpoints típicos:
POST /auth/login → { access_token, refresh_token, expires_in }POST /auth/refresh → novo access_token (rotacionar refresh token)POST /auth/logout → invalidar refresh tokenPacotes recomendados:
jsonwebtoken para gerar tokensexpress-jwt ou middleware customizado para validaçãoConfiguração de desenvolvimento:
expires_in curto (ex: 15 minutos) para access_tokenConfiguração:
djangorestframework-simplejwt ou dj-rest-authsettings.py/api/token/ e /api/token/refresh/Para sessões (cookies):
Variáveis de ambiente:
admin_username: Username do adminadmin_password: Password do adminencoded_token: Token codificado (alternativa)OpenAPI automático:
openapi-to-postmanv2 para converterQuando encontrar erros durante a documentação:
Documentar o erro:
Informar necessidade de correção:
Reteste completo:
projeto/
├── postman/
│ ├── collection.json # Collection principal
│ ├── environment.json # Environment padrão
│ └── environment.prod.json # Environment de produção (gitignored)
├── scripts/
│ └── run_newman.sh # Script de execução Newman
├── .github/
│ └── workflows/
│ └── postman-ci.yml # CI/CD workflow
└── reports/
└── postman/ # Relatórios Newman (gitignored)
├── junit-results.xml
└── report.html
core/docs/programming/postman-documentation-standards.md// Pre-request snippet: attach Bearer and refresh if expired
if (pm.environment.get('auth_token')) {
pm.request.headers.upsert({
key: 'Authorization',
value: 'Bearer ' + pm.environment.get('auth_token')
});
}
let expiresAt = pm.environment.get('auth_expires_at');
if (expiresAt && Date.now() >= parseInt(expiresAt)) {
pm.sendRequest({
url: pm.environment.get('base_url') + '/auth/refresh',
method: 'POST',
header: { 'Content-Type': 'application/json' },
body: {
mode: 'raw',
raw: JSON.stringify({
refresh_token: pm.environment.get('refresh_token')
})
}
}, function (err, res) {
if (!err && res.code === 200) {
let j = res.json();
if (j.access_token) pm.environment.set('auth_token', j.access_token);
if (j.refresh_token) pm.environment.set('refresh_token', j.refresh_token);
if (j.expires_in) pm.environment.set('auth_expires_at', Date.now() + (j.expires_in * 1000));
}
});
}
pm.test("Login works", function () {
pm.response.to.have.status(200);
});
let r = pm.response.json();
if (r.access_token) pm.environment.set('auth_token', r.access_token);
if (r.refresh_token) pm.environment.set('refresh_token', r.refresh_token);
if (r.expires_in) pm.environment.set('auth_expires_at', Date.now() + (r.expires_in * 1000));
Fluxo recomendado:
swagger-jsdoc, Django: drf-spectacular, FastAPI: automático)openapi-to-postmanv2)postman/ no repocollections.publishTemplates e Exemplos: Ver core/templates/postman-collection/ para templates completos de collection, environment e scripts de automação
Python best practices e styleguide
Integração completa com Notion usando MCP customizado (notion-automation-suite)
Gera critérios de aceite Given/When/Then para requisitos funcionais. Inclui happy path, edge cases e falhas.
Cria Architecture Decision Records (ADRs) para decisões técnicas. Inclui alternativas, justificativa e consequências.
Extrai especificações de um sistema legado (código existente) quando não há documentação adequada.
Converte input não estruturado (texto, notas, docs parciais) em requisitos funcionais (FR) e perguntas abertas. Não inventa requisitos.