using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace DrDimAPI
{
public class DrDimApiClient
{
private readonly string _baseUrl;
private readonly string _publicKey;
private readonly string _secretKey;
private readonly HttpClient _httpClient;
private readonly JsonSerializerOptions _jsonOptions;
public DrDimApiClient(string baseUrl, string publicKey, string secretKey)
{
_baseUrl = baseUrl.TrimEnd('/');
_publicKey = publicKey;
_secretKey = secretKey;
_httpClient = new HttpClient
{
Timeout = TimeSpan.FromSeconds(60)
};
_httpClient.DefaultRequestHeaders.Add("X-Public-Key", _publicKey);
_httpClient.DefaultRequestHeaders.Add("X-Secret-Key", _secretKey);
_httpClient.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json")
);
_jsonOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
PropertyNameCaseInsensitive = true,
WriteIndented = true
};
}
public async Task ListarProdutosAsync(int page = 1, int perPage = 20)
{
string endpoint = $"/produtos?page={page}&per_page={perPage}";
return await MakeRequestAsync(HttpMethod.Get, endpoint);
}
public async Task CriarProdutoAsync(Dictionary produto)
{
return await MakeRequestAsync(HttpMethod.Post, "/produtos", produto);
}
public async Task AtualizarProdutoAsync(int id, Dictionary produto)
{
return await MakeRequestAsync(HttpMethod.Put, $"/produtos/{id}", produto);
}
public async Task EmitirNFeAsync(Dictionary dados)
{
return await MakeRequestAsync(HttpMethod.Post, "/nfe/emitir", dados);
}
public async Task SincronizarProdutosAsync(List> produtos)
{
var payload = new Dictionary
{
{ "produtos", produtos }
};
return await MakeRequestAsync(HttpMethod.Post, "/produtos/sync", payload);
}
private async Task MakeRequestAsync(
HttpMethod method,
string endpoint,
object data = null)
{
try
{
var url = $"{_baseUrl}{endpoint}";
var request = new HttpRequestMessage(method, url);
if (data != null && method != HttpMethod.Get)
{
var jsonContent = JsonSerializer.Serialize(data, _jsonOptions);
request.Content = new StringContent(
jsonContent,
Encoding.UTF8,
"application/json"
);
}
var response = await _httpClient.SendAsync(request);
var responseBody = await response.Content.ReadAsStringAsync();
Dictionary responseData = null;
if (!string.IsNullOrEmpty(responseBody))
{
try
{
responseData = JsonSerializer.Deserialize>(
responseBody,
_jsonOptions
);
}
catch (JsonException ex)
{
responseData = new Dictionary
{
{ "raw_response", responseBody },
{ "parse_error", ex.Message }
};
}
}
return new ApiResponse(
(int)response.StatusCode,
response.IsSuccessStatusCode,
responseData
);
}
catch (HttpRequestException ex)
{
return new ApiResponse(
0,
false,
new Dictionary
{
{ "error", "Erro de conexão" },
{ "message", ex.Message }
}
);
}
catch (TaskCanceledException ex)
{
return new ApiResponse(
0,
false,
new Dictionary
{
{ "error", "Timeout na requisição" },
{ "message", ex.Message }
}
);
}
}
public void Dispose()
{
_httpClient?.Dispose();
}
}
public class ApiResponse
{
public int StatusCode { get; }
public bool Success { get; }
public Dictionary Data { get; }
public ApiResponse(int statusCode, bool success, Dictionary data)
{
StatusCode = statusCode;
Success = success;
Data = data ?? new Dictionary();
}
public T GetData(string key)
{
if (Data.TryGetValue(key, out var value))
{
if (value is JsonElement jsonElement)
{
return JsonSerializer.Deserialize(jsonElement.ToString());
}
return (T)value;
}
return default;
}
public Dictionary GetDataMap()
{
return GetData>("data");
}
public string GetMessage()
{
return GetData("message");
}
public Dictionary GetErrors()
{
return GetData>("errors");
}
}
}
// Exemplo de uso
class Program
{
static async Task Main(string[] args)
{
var api = new DrDimAPI.DrDimApiClient(
"https://api.drdim.com.br/api/v1",
"pk_live_abc123def456",
"sk_live_xyz789uvw012"
);
try
{
// Listar produtos
Console.WriteLine("=== Listando Produtos ===");
var produtos = await api.ListarProdutosAsync(1, 20);
if (produtos.Success)
{
var dataMap = produtos.GetDataMap();
if (dataMap != null && dataMap.ContainsKey("data"))
{
var produtosList = produtos.GetData>>("data");
if (produtosList != null)
{
Console.WriteLine($"Total de produtos: {produtosList.Count}");
foreach (var produto in produtosList)
{
Console.WriteLine($"- ID: {produto["id"]}, Nome: {produto["nome"]}");
}
}
}
}
else
{
Console.WriteLine($"Erro: {produtos.GetMessage()}");
}
// Criar novo produto
Console.WriteLine("\n=== Criando Novo Produto ===");
var novoProduto = new Dictionary
{
{ "nome", "Produto Teste C#" },
{ "descricao", "Criado via API C#" },
{ "preco", 149.90 },
{ "codigo_barras", "7891234567890" },
{ "estoque", 100 },
{ "categoria_id", 5 },
{ "ativo", true }
};
var resultado = await api.CriarProdutoAsync(novoProduto);
if (resultado.Success)
{
var produtoCriado = resultado.GetDataMap();
if (produtoCriado != null)
{
Console.WriteLine($"Produto criado com ID: {produtoCriado["id"]}");
}
}
else
{
Console.WriteLine($"Erro ao criar produto: {resultado.GetMessage()}");
var errors = resultado.GetErrors();
if (errors != null)
{
foreach (var error in errors)
{
Console.WriteLine($"- {error.Key}: {error.Value}");
}
}
}
// Emitir NFe
Console.WriteLine("\n=== Emitindo NFe ===");
var dadosNFe = new Dictionary
{
{ "cliente_id", 123 },
{ "produtos", new List>
{
new Dictionary
{
{ "produto_id", 456 },
{ "quantidade", 2 },
{ "valor_unitario", 99.90 }
}
}
},
{ "desconto", 0 },
{ "observacoes", "Venda via API C#" }
};
var nfe = await api.EmitirNFeAsync(dadosNFe);
if (nfe.Success)
{
var nfeCriada = nfe.GetDataMap();
if (nfeCriada != null)
{
Console.WriteLine($"NFe emitida com número: {nfeCriada["numero"]}");
Console.WriteLine($"Chave de acesso: {nfeCriada["chave_acesso"]}");
}
}
else
{
Console.WriteLine($"Erro ao emitir NFe: {nfe.GetMessage()}");
}
}
catch (Exception ex)
{
Console.WriteLine($"Erro inesperado: {ex.Message}");
Console.WriteLine(ex.StackTrace);
}
finally
{
api.Dispose();
}
}
}