SwiftMesh AI Skill
Uma referência abrangente de IA para usar SwiftMesh — um wrapper Alamofire + Codable com async/await, Combine, configuração fluente, upload/download de arquivos, análise de caminhos JSON, wrappers Codable resilientes e logging integrado.
Cartão de Referência Rápida
| Recurso | Método | Descrição |
|---|---|---|
| Requisição GET | .request(of: Model.self) | Decodifica a resposta para um modelo Codable |
| Caminho de Chave | .request(of: Model.self, modelKeyPath: "data.user") | Extrai JSON aninhado |
| Upload de Arquivo | .upload(of: Result.self) | Faz upload de arquivo/Dados/stream/multipart |
| Download de Arquivo | .download() | Baixa ou retoma download |
| Dados Brutos | .requestData() | Obtém dados brutos da resposta |
| String Bruta | .requestString() | Obtém a resposta como String |
| Política de Repetição | .setInterceptor(RetryPolicy()) | Repetição automática com backoff |
| Logging | Mesh.enableLog() | Ativa o logging de rede |
Arquitetura Principal
O SwiftMesh usa um padrão de construtor na classe Mesh. Cada método de configuração retorna Self, permitindo encadeamento fluente. O fluxo é:
Configure (Mesh + Config) → Execute (Requisição/Upload/Download) → Trate (Handle)
Estrutura de Arquivos
| Arquivo | Propósito |
|---|---|
Mesh.swift | Classe construtora principal com todas as propriedades |
Config.swift | Setters encadeáveis fluentes + configuração global |
Request.swift | Execução de requisição com async/await |
Handle.swift | Construção de URL, tratamento de erros, processamento de resposta, RetryPolicy |
Upload.swift | Upload de arquivo (arquivo, dados, stream, multipart) |
Download.swift | Download de arquivo (padrão, retomável) |
KeyPath.swift | Decodificador de caminho JSON para extração aninhada |
Codable+.swift | Wrappers de propriedade resilientes (@Default, @IgnoreError, @ConvertTo*) |
Log.swift | Logger de rede (cURL, status, tempo, JSON) |
Padrões de Uso
1. Requisição GET Básica
let result = try await Mesh()
.setRequestMethod(.get)
.setUrlHost("https://api.example.com")
.setUrlPath("/weather/city/101030100")
.request(of: Weather.self)
2. GET com Extração de Caminho JSON
Extraia apenas uma parte aninhada da resposta JSON sem analisar a estrutura completa:
// JSON: { "code": 200, "data": { "yesterday": { "temp": 25, "notice": "Sunny" } } }
let yesterday = try await Mesh()
.setRequestMethod(.get)
.setUrlHost("https://api.example.com")
.setUrlPath("/weather")
.request(of: Forecast.self, modelKeyPath: "data.yesterday")
3. Requisição POST com Parâmetros
let result = try await Mesh()
.setRequestMethod(.post)
.setUrlHost("https://api.example.com")
.setUrlPath("/login")
.setParameters(["username": "admin", "password": "123456"])
.request(of: LoginResult.self)
4. POST com Codificação JSON
let result = try await Mesh()
.setRequestMethod(.post)
.setUrlHost("https://api.example.com")
.setUrlPath("/api/data")
.setRequestEncoding(JSONEncoding.default)
.setParameters(["key": "value"])
.request(of: Response.self)
5. Requisição com Cabeçalhos Personalizados
let result = try await Mesh()
.setUrlHost("https://api.example.com")
.setUrlPath("/secure/data")
.setHeads(["Authorization": "Bearer token123"])
.request(of: SecureData.self)
6. Requisição com Política de Repetição
let result = try await Mesh()
.setUrlHost("https://api.example.com")
.setUrlPath("/unstable-api")
.setInterceptor(RetryPolicy(maxRetryCount: 3))
.request(of: Data.self)
7. Requisição Baseada em URLRequest
Quando você já tem um URLRequestConvertible:
let urlRequest = try URLRequest(url: URL(string: "https://api.example.com/data")!, method: .get)
let result = try await Mesh()
.urlRequest(urlRequest, type: Response.self)
8. Resposta de Dados Brutos
let data = try await Mesh()
.setRequestMethod(.get)
.setUrlHost("https://api.example.com")
.setUrlPath("/raw")
.requestData()
9. Resposta de String Bruta
let string = try await Mesh()
.setRequestMethod(.get)
.setUrlHost("https://api.example.com")
.setUrlPath("/text")
.requestString()
10. Download de Arquivo
let fileURL = try await Mesh()
.setRequestMethod(.get)
.setUrlHost("https://example.com")
.setUrlPath("/files/document.pdf")
.setDestination { _, _ in
let dest = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
.appendingPathComponent("document.pdf")
return (dest, [.removePreviousFile, .createIntermediateDirectories])
}
.download()
11. Download Retomável
let fileURL = try await Mesh()
.setUrlHost("https://example.com")
.setUrlPath("/files/large-file.zip")
.setDownloadType(.resume)
.setResumeData(savedResumeData) // de download interrompido anteriormente
.download()
12. Upload de Arquivo Único (URL)
let result = try await Mesh()
.setRequestMethod(.post)
.setUrlHost("https://api.example.com")
.setUrlPath("/upload")
.setUploadType(.file)
.setFileURL(fileURL)
.upload(of: UploadResult.self)
13. Upload de Arquivo Único (Dados)
let result = try await Mesh()
.setRequestMethod(.post)
.setUrlHost("https://api.example.com")
.setUrlPath("/upload")
.setUploadType(.data)
.setFileData(imageData)
.upload(of: UploadResult.self)
14. Upload de Formulário Multipart
let result = try await Mesh()
.setRequestMethod(.post)
.setUrlHost("https://api.example.com")
.setUrlPath("/upload/multi")
.setUploadType(.multipart)
.setAddformData(name: "file",
fileName: "photo.jpg",
fileData: imageData,
mimeType: "image/jpeg")
.setAddformData(name: "description",
fileData: "My photo".data(using: .utf8))
.upload(of: UploadResult.self)
15. Multipart com UploadDatas Pré-construídos
let uploads = [
MultipleUpload.formData(name: "file1", fileName: "a.jpg", fileData: data1, mimeType: "image/jpeg"),
MultipleUpload.formData(name: "file2", fileName: "b.pdf", fileURL: fileURL)
]
let result = try await Mesh()
.setRequestMethod(.post)
.setUrlHost("https://api.example.com")
.setUrlPath("/upload/batch")
.setUploadType(.multipart)
.setUploadDatas(uploads)
.setParameters(["userId": "123"]) // campos de formulário adicionais
.upload(of: BatchResult.self)
16. Timeout Personalizado
let result = try await Mesh()
.setUrlHost("https://api.example.com")
.setUrlPath("/slow-api")
.setTimeout(60) // 60 segundos
.request(of: Response.self)
Configuração Global
Defina isso uma vez na inicialização do aplicativo (por exemplo, em AppDelegate):
// Ativar logging de rede
Mesh.enableLog(.log) // ou .print
// Definir cabeçalhos padrão globais
Mesh.setHeaders(["Authorization": "Bearer token", "App-Version": "1.0"])
// Definir parâmetros padrão globais
Mesh.setParameters(["platform": "ios", "sdk_version": "2.0"])
// Definir host de URL global
Mesh.setUrlHost("https://api.example.com")
Então, a configuração por requisição precisa apenas do caminho:
// Usa cabeçalhos globais, parâmetros e urlHost
let result = try await Mesh()
.setUrlPath("/weather")
.request(of: Weather.self)
Wrappers de Propriedade Codable Resilientes
Lida com respostas de API inconsistentes de forma graciosa, sem falhas de decodificação.
Wrappers @Default
Fornece valores de fallback quando campos estão ausentes ou inválidos:
struct Response: Codable {
@Default.True var isEnabled: Bool // Ausente → true
@Default.False var isDeleted: Bool // Ausente → false
@Default.EmptyString var name: String // Ausente → ""
@Default.EmptyInt var count: Int // Ausente → 0
@Default.EmptyArray var tags: [String] // Ausente → []
@Default.EmptyDictionary var meta: [String: Int] // Ausente → [:]
@Default.Now var createdAt: Date // Ausente → Date()
}
@IgnoreError
Retorna nil em vez de lançar uma exceção quando um campo falha ao decodificar:
struct Response: Codable {
@IgnoreError var description: String? // Tipo inválido → nil (sem crash)
@IgnoreError var nested: NestedModel? // Ausente/ malformado → nil
}
@ConvertToString
Aceita String, Int ou Double do JSON → converte para String?:
struct Response: Codable {
@ConvertToString var version: String? // "1.0", 1, ou 1.0 → "1.0", "1", "1.0"
}
@ConvertToInt
Aceita Int, String ou Double do JSON → converte para Int?:
struct Response: Codable {
@ConvertToInt var count: Int? // 42, "42", ou 42.9 → 42, 42, 42
}
@ConvertToDouble
Aceita Double, Int, Float ou String do JSON → converte para Double?:
struct Response: Codable {
@ConvertToDouble var price: Double? // 9.99, 10, "9.99" → 9.99, 10.0, 9.99
}
@ConvertToFloat
Aceita Float, Int, Double ou String do JSON → converte para Float?:
struct Response: Codable {
@ConvertToFloat var rating: Float? // 4.5, 5, "4.5" → 4.5, 5.0, 4.5
}
Decodificador de Caminho JSON
Extraia valores JSON aninhados sem analisar a resposta inteira:
// JSON: { "code": 200, "data": { "list": [{ "id": 1 }, { "id": 2 }] } }
// Extrai um único objeto aninhado
let firstItem = try await Mesh()
.setRequestMethod(.get)
.setUrlPath("/items")
.request(of: Item.self, modelKeyPath: "data.list.0")
// O decodificador KeyPath também funciona diretamente:
let decoder = JSONDecoder.default
let item = try decoder.decode(Item.self, from: jsonData, keyPath: "data.list.0")
let items = try decoder.decodeArray([Item].self, from: jsonData, keyPath: "data.list")
O decodificador padrão configura automaticamente:
keyDecodingStrategy = .convertFromSnakeCase(snake_case → camelCase)dateDecodingStrategy = .iso8601
Integração Combine + SwiftUI
Padrão ObservableObject
class RequestModel: ObservableObject {
@MainActor @Published var weather: Weather?
@MainActor @Published var errorMessage: String?
func fetchWeather() {
Task {
do {
let result = try await Mesh()
.setRequestMethod(.get)
.setUrlHost("https://api.example.com")
.setUrlPath("/weather")
.request(of: Weather.self)
await MainActor.run { self.weather = result }
} catch {
await MainActor.run { self.errorMessage = error.localizedDescription }
}
}
}
}
Uso em SwiftUI
struct WeatherView: View {
@StateObject private var model = RequestModel()
var body: some View {
VStack {
if let weather = model.weather {
Text("\(weather.temperature)°C")
}
if let error = model.errorMessage {
Text(error).foregroundColor(.red)
}
}
.onAppear { model.fetchWeather() }
}
}
Uso em UIKit + Combine
class ViewController: UIViewController {
private var model = RequestModel()
private var cancellables: Set<AnyCancellable> = []
override func viewDidLoad() {
super.viewDidLoad()
model.$weather
.receive(on: RunLoop.main)
.sink { weather in
print("Clima: \(String(describing: weather))")
}
.store(in: &cancellables)
model.fetchWeather()
}
}
Tratamento de Erros
O SwiftMesh normaliza erros de rede comuns em NSError amigável ao usuário:
| Código de Erro | Descrição |
|---|---|
NSURLErrorNotConnectedToInternet | Sem conexão com a internet |
NSURLErrorTimedOut | Requisição excedeu o tempo limite |
NSURLErrorCannotFindHost | Host não encontrado |
NSURLErrorCannotConnectToHost | Não é possível conectar ao host |
NSURLErrorNetworkConnectionLost | Conexão perdida durante a requisição |
Todos os erros normalizados retornam a mensagem: "Não foi possível conectar ao servidor"
Capture erros no seu código assíncrono:
do {
let result = try await Mesh()
.setUrlPath("/api")
.request(of: Response.self)
} catch let error as NSError {
print("Erro \(error.code): \(error.localizedDescription)")
}
RetryPolicy
Repetição interna com backoff linear (1s, 2s, 3s...):
// Padrão: 3 repetições
let policy = RetryPolicy()
// Personalizado: 5 repetições
let policy = RetryPolicy(maxRetryCount: 5)
// Usar com requisição
let result = try await Mesh()
.setUrlPath("/unstable-api")
.setInterceptor(policy)
.request(of: Response.self)
Logging
Ativar na inicialização do aplicativo:
// Usando o Logger unificado da Apple (os.log)
Mesh.enableLog(.log)
// Usando print() do Swift
Mesh.enableLog(.print)
A saída inclui:
- Comando cURL (para fácil reprodução)
- Código de status HTTP
- Tempo decorrido
- Resposta JSON formatada
Referência de Métodos de Configuração
Todos os métodos são encadeáveis (retornam Self):
Configuração Básica
| Método | Tipo | Descrição |
|---|---|---|
.setTimeout(_:) | TimeInterval | Tempo limite da requisição em segundos (padrão: 15) |
.setInterceptor(_:) | RequestInterceptor? | Política de repetição / manipulador de credenciais |
.setRequestMethod(_:) | HTTPMethod | GET, POST, PUT, DELETE, etc. |
.setHeads(_:) | [String: String] | Cabeçalhos por requisição |
.setRequestEncoding(_:) | ParameterEncoding | URLEncoding, JSONEncoding, etc. |
.setUrlHost(_:) | String? | Host de URL por requisição |
.setUrlPath(_:) | String? | Caminho da URL |
.setParameters(_:) | [String: Any]? | Parâmetros da requisição |
Configuração de Download
| Método | Tipo | Descrição |
|---|---|---|
.setDownloadType(_:) | DownloadType | .download ou .resume |
.setResumeData(_:) | Data? | Dados de retomada para download retomável |
.setDestination(_:) | DownloadRequest.Destination? | Caminho de destino do arquivo baixado |
Configuração de Upload
| Método | Tipo | Descrição |
|---|---|---|
.setUploadType(_:) | UploadType | .file, .data, .stream ou .multipart |
.setFileURL(_:) | URL? | URL do arquivo para upload de arquivo |
.setFileData(_:) | Data? | Dados para upload de dados |
.setStream(_:) | InputStream? | Stream para upload de stream |
.setAddformData(_:fileData:mimeType:name:) | - | Adiciona um único campo/formData multipart |
.setUploadDatas(_:) | [MultipleUpload] | Array de múltiplos dados de upload multipart |
Configuração de Análise de Resposta
| Método | Tipo | Descrição |
|---|---|---|
.setOutDataType(_:) | OutDataType | .data, .string, .jsonObject, .model |
.setModelType(_:) | Codable.Type? | Tipo do modelo para decodificação na resposta |
.setModelKeyPath(_:) | String? | Caminho de chave JSON para extrair dados aninhados |
Organização do Contexto da Skill
Esta documentação está estruturada para consulta rápida em tarefas de agentes:
- Cartão de Referência Rápida — Principais recursos e métodos para uso rápido
- Arquitetura Principal — Entenda o padrão de construtor e a estrutura de arquivos
- Padrões de Uso — Exemplos de código copiáveis para casos de uso comuns
- Configuração Global — Configuração única para toda a sessão
- Codable Resiliente — Manipulação graciosa de respostas de API irregulares
- Caminho JSON — Extração de dados aninhados sem analisar tudo
- Combine + SwiftUI — Integração reativa com IU
- Tratamento de Erros — Normalização de erros de rede
- RetryPolicy — Repetição automática com backoff
- Logging — Depuração e monitoramento
- Referência de Métodos — Tabela de métodos de configuração
Propósito da Skill
Esta skill de IA fornece documentação abrangente e exemplos de código para o SwiftMesh, uma biblioteca Swift para requisições de rede. O objetivo é permitir que agentes de IA gerem código Swift preciso, idiomático e pronto para uso utilizando o SwiftMesh. A skill cobre todos os principais recursos, desde requisições básicas GET até uploads multipart complexos, download retomável e decodificação JSON resiliente.