Añadir un cliente C# para la API de Umami
El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad de oportunidades entre los hombres y las mujeres en materia de empleo, incluida la asignación de recursos suficientes a la educación y la formación profesional.
En este post, le mostraré cómo crear un cliente CM SK1 para la API de reporting Umami. Este es un ejemplo sencillo que demuestra cómo autenticar con la API y extraer datos de ellaMSC3
Puede encontrar todo el código fuente para esto en mi GitHub repo.
El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer.
Instalar Umami. Puede encontrar las instrucciones de instalación a) Adopte todas las medidas necesarias para garantizar la igualdad de oportunidades entre hombres y mujeres en todos los ámbitos de la vida, incluida la educación; esto detalla cómo instalo y uso Umami para proporcionar análisis para este sitio.
De nuevo, esta es una simple implementación de algunos de los puntos finales del API de Estadísticas Web de Umami. Puede encontrar la documentación completa del API a) Adopte todas las medidas necesarias para garantizar la igualdad de oportunidades entre hombres y mujeres en todos los ámbitos de la vida, incluida la educación;.
En este caso he optado por aplicar los siguientes puntos finales:
GET /api/websites/:websiteId/pageviews- Como sugiere el nombre, este punto final devolve las visitas de página y 'sessionsM SK3 para un determinado sitio web en un período de tiempoMSC4
{
"pageviews": [
{ "x": "2020-04-20 01:00:00", "y": 3 },
{ "x": "2020-04-20 02:00:00", "y": 7 }
],
"sessions": [
{ "x": "2020-04-20 01:00:00", "y": 2 },
{ "x": "2020-04-20 02:00:00", "y": 4 }
]
}
GET /api/websites/:websiteId/stats- esto returna las estadísticas básicas de un sitio web dadoM SK1
{
"pageviews": { "value": 5, "change": 5 },
"visitors": { "value": 1, "change": 1 },
"visits": { "value": 3, "change": 2 },
"bounces": { "value": 0, "change": 0 },
"totaltime": { "value": 4, "change": 4 }
}
GET /api/websites/:websiteId/metrics- esto reembolsa las mediciones para un sitio web dado bu URL etc.
[
{ "x": "/", "y": 46 },
{ "x": "/docs", "y": 17 },
{ "x": "/download", "y": 14 }
]
Como se puede ver de los docs, estos todos aceptan un número de parámetros M SK1y he representado estos como parámetros de consulta en el código de abajo).
Examen en Rider httpClient
Siempre empezo con el test de la API en Rider's built-in HTTP clientM SK2 Esto me permite probar rápidamente la API y ver la respuesta
### Login Request and Store Token
POST https://{{umamiurl}}/api/auth/login
Content-Type: application/json
{
"username": "{{username}}",
"password": "{{password}}"
}
> {% client.global.set("auth_token", response.body.token);
client.global.set("endAt", Math.round(new Date().getTime()).toString() );
client.global.set("startAt", Math.round(new Date().getTime() - 7 * 24 * 60 * 60 * 1000).toString());
%}
### Use Token in Subsequent Request
GET https://{{umamiurl}}/api/websites/{{websiteid}}/stats?endAt={{endAt}}&startAt={{startAt}}
Authorization: Bearer {{auth_token}}
### Use Token in Subsequent Request
GET https://{{umamiurl}}/api/websites/{{websiteid}}/pageviews?endAt={{endAt}}&startAt={{startAt}}&unit=day
Authorization: Bearer {{auth_token}}
###
GET https://{{umamiurl}}}}/api/websites/{{websiteid}}/metrics?endAt={{endAt}}&startAt={{startAt}}&type=url
Authorization: Bearer {{auth_token}}
Es una buena práctica mantener los nombres de las variables aquí en {{}} un archivo env.json que usted puede referirse a como abajo
{
"local": {
"umamiurl":"umamilocal.mostlylucid.net",
"username": "admin",
"password": "<password{>",
"websiteid" : "32c2aa31-b1ac-44c0-b8f3-ff1f50403bee"
}
}
El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer.
En primer lugar, necesitamos configurar HttpClient y los servicios que utilizaremos para hacer las peticiones.
public static class UmamiSetup
{
public static void SetupUmamiServices(this IServiceCollection services, IConfiguration config)
{
var umamiSettings = services.ConfigurePOCO<UmamiSettings>(config.GetSection(UmamiSettings.Section));
services.AddHttpClient<AuthService>(options =>
{
options.BaseAddress = new Uri(umamiSettings.BaseUrl);
}) .SetHandlerLifetime(TimeSpan.FromMinutes(5)) //Set lifetime to five minutes
.AddPolicyHandler(GetRetryPolicy());;
services.AddScoped<UmamiService>();
services.AddScoped<AuthService>();
}
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
return HttpPolicyExtensions
.HandleTransientHttpError()
.OrResult(msg => msg.StatusCode == HttpStatusCode.ServiceUnavailable)
.WaitAndRetryAsync(6, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}
}
Aquí configuramos la clase de ajustes. UmamiSettings El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. AuthService El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. UmamiService a la recogida de servicios. También añademos una política de repetición al cliente Http para tratar errores transitorios.
De conformidad con el párrafo 2 del artículo 5 de la Convención, el Comité recomienda al Estado Parte que: UmamiService El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. AuthService El Comité recomienda que el Estado Parte adopte todas las medidas necesarias para garantizar la igualdad de oportunidades entre los hombres y las mujeres en materia de empleo, incluida la eliminación del trabajo forzoso.
El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. AuthService es simplemente responsable de obtener el token JWT del API.
public class AuthService(HttpClient httpClient, UmamiSettings umamiSettings, ILogger<AuthService> logger)
{
private string _token;
public HttpClient HttpClient => httpClient;
public async Task<bool> LoginAsync()
{
var loginData = new
{
username = umamiSettings.Username,
password = umamiSettings.Password
};
var content = new StringContent(JsonSerializer.Serialize(loginData), Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync("/api/auth/login", content);
if (response.IsSuccessStatusCode)
{
var authResponse = await response.Content.ReadFromJsonAsync<AuthResponse>();
_token = authResponse.Token;
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _token);
logger.LogInformation("Login successful");
return true;
}
logger.LogError("Login failed");
return false;
}
}
Aquí tenemos un método sencillo. LoginAsync El Comité recomienda al Estado Parte que incluya en su próximo informe periódico información detallada sobre la situación de los derechos humanos y las libertades fundamentales en el marco del Pacto Internacional de Derechos Civiles y Políticos. /api/auth/login final con el nombre de usuario y contraseña. Si la solicitud es satisfactoria, almacenamos el token JWT en el _token En el párrafo 2 de la parte dispositiva del proyecto de resolución, la Asamblea General pidió al Secretario General que le presentara en su quincuagésimo noveno período de sesiones un informe sobre los progresos realizados en la aplicación de las recomendaciones formuladas por la Comisión Consultiva en Asuntos Administrativos y de Presupuesto. Authorization el encabezamiento en el HttpClient.
El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. UmamiService Es responsable de hacer las peticiones al API.
Para cada uno de los métodos principales I'he definido objetos de solicitud que aceptan todos los parámetros para cada punto finalM SK1 Esto facilita el test y mantenimiento del código.
Todos ellos siguen un patrón simiiar,, así que yo ' voy a mostrar solo uno de ellos aquí.
public async Task<UmamiResult<StatsResponseModels>> GetStatsAsync(StatsRequest statsRequest)
{
// Start building the query string
var queryParams = new List<string>
{
$"start={statsRequest.StartAt}",
$"end={statsRequest.EndAt}"
};
// Add optional parameters if they are not null
if (!string.IsNullOrEmpty(statsRequest.Url)) queryParams.Add($"url={statsRequest.Url}");
if (!string.IsNullOrEmpty(statsRequest.Referrer)) queryParams.Add($"referrer={statsRequest.Referrer}");
if (!string.IsNullOrEmpty(statsRequest.Title)) queryParams.Add($"title={statsRequest.Title}");
if (!string.IsNullOrEmpty(statsRequest.Query)) queryParams.Add($"query={statsRequest.Query}");
if (!string.IsNullOrEmpty(statsRequest.Event)) queryParams.Add($"event={statsRequest.Event}");
if (!string.IsNullOrEmpty(statsRequest.Host)) queryParams.Add($"host={statsRequest.Host}");
if (!string.IsNullOrEmpty(statsRequest.Os)) queryParams.Add($"os={statsRequest.Os}");
if (!string.IsNullOrEmpty(statsRequest.Browser)) queryParams.Add($"browser={statsRequest.Browser}");
if (!string.IsNullOrEmpty(statsRequest.Device)) queryParams.Add($"device={statsRequest.Device}");
if (!string.IsNullOrEmpty(statsRequest.Country)) queryParams.Add($"country={statsRequest.Country}");
if (!string.IsNullOrEmpty(statsRequest.Region)) queryParams.Add($"region={statsRequest.Region}");
if (!string.IsNullOrEmpty(statsRequest.City)) queryParams.Add($"city={statsRequest.City}");
// Combine the query parameters into a query string
var queryString = string.Join("&", queryParams);
// Make the HTTP request
var response = await authService.HttpClient.GetAsync($"/api/websites/{WebsiteId}/stats?{queryString}");
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadFromJsonAsync<StatsResponseModels>();
return new UmamiResult<StatsResponseModels>(response.StatusCode, response.ReasonPhrase ?? "Success", content ?? new StatsResponseModels());
}
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
await authService.LoginAsync();
return await GetStatsAsync(statsRequest);
}
logger.LogError("Failed to get stats");
return new UmamiResult<StatsResponseModels>(response.StatusCode, response.ReasonPhrase ?? "Failed to get stats", null);
}
Aquí usted puede ver que yo tomo el objeto de solicitud
public class BaseRequest
{
public long StartAt => StartAtDate.ToMilliseconds(); // Timestamp (in ms) of starting date
public long EndAt => EndAtDate.ToMilliseconds(); // Timestamp (in ms) of end date
public DateTime StartAtDate { get; set; }
public DateTime EndAtDate { get; set; }
}
public class StatsRequest : BaseRequest
{
// Optional properties
public string? Url { get; set; } // Name of URL
public string? Referrer { get; set; } // Name of referrer
public string? Title { get; set; } // Name of page title
public string? Query { get; set; } // Name of query
public string? Event { get; set; } // Name of event
public string? Host { get; set; } // Name of hostname
public string? Os { get; set; } // Name of operating system
public string? Browser { get; set; } // Name of browser
public string? Device { get; set; } // Name of device (e.g., Mobile)
public string? Country { get; set; } // Name of country
public string? Region { get; set; } // Name of region/state/province
public string? City { get; set; } // Name of city
}
Y construir la cadena de consulta desde los parámetros. Si la solicitud es exitosa, devolvemos el contenido como un UmamiResult Si la solicitud falla con un 401 código de estado, llamamos al LoginAsync method and retry the request. This ensures we 'elegantlyM SK2 handle the token expiry.
El Comité recomienda que el Estado Parte adopte todas las medidas necesarias para garantizar la igualdad de oportunidades entre los hombres y las mujeres en materia de empleo, incluida la eliminación del trabajo forzoso.
Este es un simple ejemplo de cómo crear un cliente C# para la API Umami. Usted puede utilizarlo como punto de partida para construir clientes más complejos o integrar la API en sus propias aplicaciones.