docs(swagger): clarify API contracts and response schemas
This commit is contained in:
parent
258b97eb15
commit
66adb39b9b
|
|
@ -18,21 +18,20 @@ Retorna a lista de impressoras instaladas no servidor onde a API está rodando.
|
|||
```json
|
||||
[
|
||||
{
|
||||
"name": "POS-80",
|
||||
"portName": "USB001",
|
||||
"driverName": "Generic / Text Only",
|
||||
"printerStatus": 0,
|
||||
"deviceId": "POS-80"
|
||||
"Name": "POS-80",
|
||||
"DriverName": "Generic / Text Only",
|
||||
"PrinterStatus": 0
|
||||
},
|
||||
{
|
||||
"name": "Microsoft Print to PDF",
|
||||
"portName": "PORTPROMPT:",
|
||||
"driverName": "Microsoft Print To PDF",
|
||||
"printerStatus": 0
|
||||
"Name": "Microsoft Print to PDF",
|
||||
"DriverName": "Microsoft Print To PDF",
|
||||
"PrinterStatus": 0
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
> Nota: atualmente esse endpoint repassa o resultado do PowerShell `Get-Printer` (Windows) com chaves em PascalCase.
|
||||
|
||||
---
|
||||
|
||||
### 2. Imprimir HTML (Etiquetas/Layouts)
|
||||
|
|
@ -53,6 +52,16 @@ Converte um código HTML (com suporte a Tailwind CSS) para PDF e imprime na impr
|
|||
}
|
||||
```
|
||||
|
||||
- **Exemplo de Resposta:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Tarefa enviada para a fila de impressão",
|
||||
"jobId": "123"
|
||||
}
|
||||
```
|
||||
|
||||
- **Detalhes:**
|
||||
- O backend injeta automaticamente o script do Tailwind CSS.
|
||||
- O HTML é renderizado via Puppeteer (Chrome headless).
|
||||
|
|
@ -82,22 +91,29 @@ Envia comandos de texto diretamente para a impressora. Ideal para cupons simples
|
|||
}
|
||||
```
|
||||
|
||||
- **Exemplo de Resposta:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Print successful!"
|
||||
}
|
||||
```
|
||||
|
||||
## Tipos (TypeScript Interfaces)
|
||||
|
||||
Se estiver usando TypeScript no Frontend, utilize estas interfaces:
|
||||
|
||||
```typescript
|
||||
export interface Printer {
|
||||
name: string;
|
||||
portName?: string;
|
||||
driverName?: string;
|
||||
printerStatus?: number;
|
||||
deviceId?: string;
|
||||
Name: string;
|
||||
DriverName?: string;
|
||||
PrinterStatus?: number;
|
||||
}
|
||||
|
||||
export interface PrintHtmlPayload {
|
||||
html: string;
|
||||
printerName: string;
|
||||
printerName?: string;
|
||||
width?: string;
|
||||
height?: string;
|
||||
jobId?: string;
|
||||
|
|
@ -109,6 +125,17 @@ export interface PrintTextPayload {
|
|||
upsideDown?: boolean;
|
||||
printerInterface?: string;
|
||||
}
|
||||
|
||||
export interface PrintHtmlResponse {
|
||||
success: boolean;
|
||||
message: string;
|
||||
jobId?: string;
|
||||
}
|
||||
|
||||
export interface PrintTextResponse {
|
||||
success: boolean;
|
||||
message: string;
|
||||
}
|
||||
```
|
||||
|
||||
## Swagger
|
||||
|
|
|
|||
14
README.md
14
README.md
|
|
@ -28,13 +28,18 @@ A solução utiliza uma arquitetura baseada em filas para assegurar a resiliênc
|
|||
O serviço utiliza as seguintes definições no arquivo `.env`:
|
||||
|
||||
| Variável | Descrição | Exemplo |
|
||||
| :------------------- | :------------------------------- | :------------------------ |
|
||||
| :------------------- | :-------------------------------------------- | :------------------------ |
|
||||
| `BODY_LIMIT` | Limite do body (JSON/urlencoded) | `2mb` |
|
||||
| `REDIS_HOST` | Endereço do servidor Redis | `localhost` |
|
||||
| `REDIS_PORT` | Porta do servidor Redis | `6379` |
|
||||
| `REDIS_PASSWORD` | Senha do Redis (opcional) | `minha-senha` |
|
||||
| `DB_ENABLED` | Habilita inicialização do Oracle/TypeORM | `true` |
|
||||
| `DB_USERNAME` | Usuário do Banco de Dados Oracle | `admin` |
|
||||
| `DB_PASSWORD` | Senha do Banco de Dados Oracle | `1234` |
|
||||
| `DB_CONNECT_STRING` | String de conexão Oracle | `(DESCRIPTION=...)` |
|
||||
| `ORACLE_CLIENT_PATH` | Caminho do Oracle Instant Client | `C:\oracle\instantclient` |
|
||||
| `DB_RETRY_ATTEMPTS` | Tentativas de conexão ao iniciar | `5` |
|
||||
| `DB_RETRY_DELAY_MS` | Delay base (ms) entre tentativas | `2000` |
|
||||
| `ORACLE_CLIENT_PATH` | Caminho do Oracle Instant Client (thick mode) | `C:\oracle\instantclient` |
|
||||
|
||||
### Pré-requisitos
|
||||
|
||||
|
|
@ -102,9 +107,10 @@ A interface de monitoramento em tempo real das filas está disponível no endpoi
|
|||
|
||||
Permite a visualização de tarefas ativas, concluídas e falhas, além da reinjeção manual de jobs.
|
||||
|
||||
### Telemetria
|
||||
### Swagger
|
||||
|
||||
O serviço está instrumentado com **OpenTelemetry**, exportando traces via protocolo OTLP para análise de performance e rastreabilidade distribuída.
|
||||
A documentação interativa (OpenAPI) está disponível em:
|
||||
`http://localhost:3000/api`
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -7,12 +7,20 @@ import {
|
|||
HttpStatus,
|
||||
Param,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';
|
||||
import {
|
||||
ApiBody,
|
||||
ApiOkResponse,
|
||||
ApiOperation,
|
||||
ApiParam,
|
||||
ApiTags,
|
||||
} from '@nestjs/swagger';
|
||||
import { PrinterService } from '../services/printer.service';
|
||||
import { PrintDataDto } from '../dto/print-data.dto';
|
||||
import { PrintHtmlDto } from '../dto/print-html.dto';
|
||||
import { PrinterDto } from '../dto/printer.dto';
|
||||
import { getPrinters } from '../services/get-printer';
|
||||
import { PrintResultDto } from '../dto/print-result.dto';
|
||||
import { PrintHtmlResultDto } from '../dto/print-html-result.dto';
|
||||
|
||||
@ApiTags('Printer')
|
||||
@Controller('printer')
|
||||
|
|
@ -24,7 +32,15 @@ export class PrinterController {
|
|||
@ApiOperation({
|
||||
summary: 'Envia um comando de impressão de texto simples (ESC/POS)',
|
||||
})
|
||||
@ApiResponse({ status: 200, description: 'Impressão enviada com sucesso' })
|
||||
@ApiParam({
|
||||
name: 'printerName',
|
||||
example: 'POS-80',
|
||||
description: 'Nome da impressora (será usado como printerInterface)',
|
||||
})
|
||||
@ApiOkResponse({
|
||||
description: 'Impressão enviada com sucesso',
|
||||
type: PrintResultDto,
|
||||
})
|
||||
async print(
|
||||
@Param('printerName') printerName: string,
|
||||
@Body() printData: PrintDataDto,
|
||||
|
|
@ -36,6 +52,15 @@ export class PrinterController {
|
|||
@Post('print')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: 'Envia um comando de impressão (Compatibilidade)' })
|
||||
@ApiBody({
|
||||
type: PrintDataDto,
|
||||
description:
|
||||
'Compatibilidade: informe printerInterface no body ou use /printer/:printerName/print.',
|
||||
})
|
||||
@ApiOkResponse({
|
||||
description: 'Impressão enviada com sucesso',
|
||||
type: PrintResultDto,
|
||||
})
|
||||
async printLegacy(@Body() printData: PrintDataDto) {
|
||||
return this.printerService.printReceipt(printData);
|
||||
}
|
||||
|
|
@ -46,7 +71,15 @@ export class PrinterController {
|
|||
summary:
|
||||
'Converte HTML para PDF e imprime na impressora especificada na URL',
|
||||
})
|
||||
@ApiResponse({ status: 200, description: 'HTML enviado para impressão' })
|
||||
@ApiParam({
|
||||
name: 'printerName',
|
||||
example: 'POS-80',
|
||||
description: 'Nome da impressora para o spooler (pdf-to-printer)',
|
||||
})
|
||||
@ApiOkResponse({
|
||||
description: 'HTML enviado para impressão (job enfileirado)',
|
||||
type: PrintHtmlResultDto,
|
||||
})
|
||||
async printHtml(
|
||||
@Param('printerName') printerName: string,
|
||||
@Body() printHtmlDto: PrintHtmlDto,
|
||||
|
|
@ -58,14 +91,22 @@ export class PrinterController {
|
|||
@Post('print-html')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: 'Converte HTML para PDF (Compatibilidade)' })
|
||||
@ApiBody({
|
||||
type: PrintHtmlDto,
|
||||
description:
|
||||
'Compatibilidade: informe printerName no body ou use /printer/:printerName/print-html.',
|
||||
})
|
||||
@ApiOkResponse({
|
||||
description: 'HTML enviado para impressão (job enfileirado)',
|
||||
type: PrintHtmlResultDto,
|
||||
})
|
||||
async printHtmlLegacy(@Body() printHtmlDto: PrintHtmlDto) {
|
||||
return this.printerService.printHtml(printHtmlDto);
|
||||
}
|
||||
|
||||
@Get('list')
|
||||
@ApiOperation({ summary: 'Lista impressoras disponíveis no sistema' })
|
||||
@ApiResponse({
|
||||
status: 200,
|
||||
@ApiOkResponse({
|
||||
description: 'Lista de impressoras encontradas',
|
||||
type: [PrinterDto],
|
||||
})
|
||||
|
|
|
|||
|
|
@ -2,8 +2,12 @@ import { ApiProperty } from '@nestjs/swagger';
|
|||
|
||||
export class PrintDataDto {
|
||||
@ApiProperty({
|
||||
example: ['--------------------------------', ' TESTE DE IMPRESSAO ', '--------------------------------'],
|
||||
description: 'Lista de linhas de texto para imprimir'
|
||||
example: [
|
||||
'--------------------------------',
|
||||
' TESTE DE IMPRESSAO ',
|
||||
'--------------------------------',
|
||||
],
|
||||
description: 'Lista de linhas de texto para imprimir',
|
||||
})
|
||||
lines: string[];
|
||||
|
||||
|
|
@ -11,21 +15,22 @@ export class PrintDataDto {
|
|||
required: false,
|
||||
enum: ['left', 'center', 'right'],
|
||||
example: 'center',
|
||||
description: 'Alinhamento do texto'
|
||||
description: 'Alinhamento do texto',
|
||||
})
|
||||
alignment?: 'left' | 'center' | 'right';
|
||||
|
||||
@ApiProperty({
|
||||
required: false,
|
||||
example: false,
|
||||
description: 'Se verdadeiro, imprime de cabeça para baixo (se suportado)'
|
||||
description: 'Se verdadeiro, imprime de cabeça para baixo (se suportado)',
|
||||
})
|
||||
upsideDown?: boolean;
|
||||
|
||||
@ApiProperty({
|
||||
required: false,
|
||||
example: 'tcp://10.1.119.13',
|
||||
description: 'Interface da impressora. Ex: tcp://ip:porta ou printer:NomeDaImpressora'
|
||||
description:
|
||||
'Interface da impressora. Obrigatorio ao usar /printer/print; ignorado ao usar /printer/:printerName/print. Ex: tcp://ip:porta ou printer:NomeDaImpressora',
|
||||
})
|
||||
printerInterface?: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { PrintResultDto } from './print-result.dto';
|
||||
|
||||
export class PrintHtmlResultDto extends PrintResultDto {
|
||||
@ApiProperty({
|
||||
required: false,
|
||||
example: '123',
|
||||
description: 'ID do job enfileirado no BullMQ',
|
||||
})
|
||||
jobId?: string;
|
||||
}
|
||||
|
|
@ -3,26 +3,36 @@ import { ApiProperty } from '@nestjs/swagger';
|
|||
export class PrintHtmlDto {
|
||||
@ApiProperty({
|
||||
example: '<h1>Titulo</h1><p>Conteudo do pedido...</p>',
|
||||
description: 'Conteúdo HTML para impressão'
|
||||
description: 'Conteúdo HTML para impressão',
|
||||
})
|
||||
html: string;
|
||||
|
||||
@ApiProperty({
|
||||
example: 'POS-80',
|
||||
description: 'Nome da impressora onde será impresso o PDF gerado'
|
||||
required: false,
|
||||
description:
|
||||
'Nome da impressora. Obrigatorio ao usar /printer/print-html; ignorado ao usar /printer/:printerName/print-html.',
|
||||
})
|
||||
printerName: string;
|
||||
printerName?: string;
|
||||
|
||||
@ApiProperty({ example: '60mm', required: false, description: 'Largura da etiqueta (default: 80mm)' })
|
||||
@ApiProperty({
|
||||
example: '60mm',
|
||||
required: false,
|
||||
description: 'Largura da etiqueta (default: 80mm)',
|
||||
})
|
||||
width?: string;
|
||||
|
||||
@ApiProperty({ example: '40mm', required: false, description: 'Altura da etiqueta (default: auto)' })
|
||||
@ApiProperty({
|
||||
example: '40mm',
|
||||
required: false,
|
||||
description: 'Altura da etiqueta (default: auto)',
|
||||
})
|
||||
height?: string;
|
||||
|
||||
@ApiProperty({
|
||||
example: 'impresso-12345',
|
||||
required: false,
|
||||
description: 'ID único do job para idempotência (evita duplicados)'
|
||||
description: 'ID único do job para idempotência (evita duplicados)',
|
||||
})
|
||||
jobId?: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class PrintResultDto {
|
||||
@ApiProperty({ example: true })
|
||||
success: boolean;
|
||||
|
||||
@ApiProperty({ example: 'Print successful!' })
|
||||
message: string;
|
||||
}
|
||||
|
|
@ -1,18 +1,24 @@
|
|||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class PrinterDto {
|
||||
@ApiProperty({ example: 'POS-80', description: 'Nome da impressora' })
|
||||
name: string;
|
||||
@ApiProperty({
|
||||
example: 'POS-80',
|
||||
description: 'Nome da impressora (retornado pelo PowerShell: Get-Printer)',
|
||||
})
|
||||
Name: string;
|
||||
|
||||
@ApiProperty({ example: 'USB001', description: 'Porta da impressora (Win32)' })
|
||||
portName?: string;
|
||||
@ApiProperty({
|
||||
example: 'Generic / Text Only',
|
||||
required: false,
|
||||
description: 'Nome do driver (retornado pelo PowerShell: Get-Printer)',
|
||||
})
|
||||
DriverName?: string;
|
||||
|
||||
@ApiProperty({ example: 'Generic / Text Only', description: 'Nome do driver' })
|
||||
driverName?: string;
|
||||
|
||||
@ApiProperty({ example: 0, description: 'Status da impressora (0 = Idle)' })
|
||||
printerStatus?: number;
|
||||
|
||||
@ApiProperty({ example: 'POS-80', description: 'ID do dispositivo (usado para impressão)' })
|
||||
deviceId?: string;
|
||||
@ApiProperty({
|
||||
example: 0,
|
||||
required: false,
|
||||
description:
|
||||
'Status da impressora (retornado pelo PowerShell: Get-Printer)',
|
||||
})
|
||||
PrinterStatus?: number;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,11 @@ async function bootstrap() {
|
|||
app.use(urlencoded({ extended: true, limit: bodyLimit }));
|
||||
|
||||
const config = new DocumentBuilder()
|
||||
.setTitle('API Documentation')
|
||||
.setDescription('The API description')
|
||||
.setVersion('1.0')
|
||||
.setTitle('Servico de Impressao')
|
||||
.setDescription(
|
||||
'Microservico NestJS para impressao local (ESC/POS e HTML->PDF), com processamento assincrono via BullMQ/Redis e opcional integracao Oracle via TypeORM.',
|
||||
)
|
||||
.setVersion('1.0.0')
|
||||
.build();
|
||||
const document = SwaggerModule.createDocument(app, config);
|
||||
SwaggerModule.setup('api', app, document);
|
||||
|
|
|
|||
Loading…
Reference in New Issue