Aprender a usar kwargs en Python te permite crear funciones flexibles que reciben parámetros nombrados y construir un cliente de APIs reutilizable con poco código. Esta guía es ideal si programas en Python y quieres conectar servicios como NewsAPI o The Guardian con una sola función.
La idea central es sencilla: los keywords funcionan parecido a los args, con una diferencia clave. Mientras los args pasan valores sin nombre, los kwargs pasan valores nombrados, es decir, conservan el nombre de la variable tal como la enviaste para que puedas usarla dentro de la función. Y aquí viene lo interesante: combinar ambos te da una función robusta.
Cómo funcionan los kwargs y en qué se diferencian de los args
Cuando defines una función con kwargs, usas dos asteriscos delante del parámetro. En el ejemplo de args se usa un solo asterisco y los valores no van nombrados. Con dos asteriscos es como decir key value: cada par representa un nombre y su valor [00:15].
Aunque el nombre del parámetro puede ser cualquiera, por convención siempre se escribe kwargs. Veamos el ejemplo básico:
Al ejecutarlo notas algo importante: el tipo que devuelve es un diccionario [01:32]. Ese diccionario guarda el nombre con el que pasaste el parámetro como llave y el valor que enviaste como su contenido.
¿Qué devuelve kwargs en Python? Devuelve un diccionario donde cada llave es el nombre del parámetro que enviaste y cada valor es lo que asociaste a ese nombre. Así recibes todos los datos nombrados en una sola estructura.
Lo curioso es que la función no declara ningún valor nombrado directamente, pero tú envías esos valores nombrados y los recuperas todos juntos en un diccionario listo para usar. Fíjate que en el ejemplo se usa una palabra en español, llave, justo para dejar claro que se recibe de forma dinámica.
Cómo construir una función flexible para conectar con varias APIs
Aquí es donde args y kwargs se vuelven poderosos. La meta es tener un solo método que obtenga un cliente de API tanto de NewsAPI como de The Guardian. Con la misma función puedes pasarle parámetros distintos y seguirá funcionando [03:20].
Por ejemplo, para NewsAPI puedes enviar un api_key con valor demo y una query con noticias de Python. Para The Guardian puedes enviar un api_key demo Guardian, una section de sports y una fecha como 2020-10-10. Misma función, parámetros diferentes.
La función principal se llama fetch_news y sigue un orden que importa mucho:
El parámetro obligatorio api_name, que indica qué API quieres usar.
Luego los args.
Al final los kwargs.
Recuerda esta regla: los parámetros obligatorios van al comienzo y los opcionales o dinámicos van a la derecha. Si inviertes el orden, Python protesta.
¿Por qué el orden de args y kwargs importa en Python? Porque los parámetros obligatorios deben ir primero y los dinámicos al final. Si pones kwargs antes de un parámetro obligatorio, la función lanza un error de sintaxis.
Cómo mezclar una configuración base con kwargs usando dos asteriscos
Dentro de la función defines una configuración base en un diccionario. Son los valores que se repiten en todas las APIs, como timeout y retries [05:40].
python
def fetch_news(api_name, *args, **kwargs):
"""Funcion flexible para conectar con la API"""
base_config = {
"timeout": 30,
"retries": 3,
}
config = {**base_config, **kwargs}
Cuando escribes {**base_config, **kwargs} estás copiando dinámicamente los valores del diccionario base y sumando todos los que lleguen por kwargs. Así generas una configuración nueva que arranca con timeout y retries, y se completa cuando pasas datos como from_date o query [06:30].
Después creas el diccionario api_clients, donde cada llave es el nombre de la API (NewsAPI o Guardian) y su valor es el cliente correspondiente. Con api_clients[api_name] seleccionas el cliente según lo que ingrese el usuario.
Por último llamas al cliente pasándole los args requeridos y la configuración completa con doble asterisco. Usar **config es como desempacar cada campo del diccionario dentro de la llamada, uno por uno. Como la función hace fetch news, retornas el resultado.
Qué reto sigue después de dominar args y kwargs
Con esta estructura ya tienes una función que se conecta a cualquiera de las dos APIs desde un solo punto. Por ahora la conexión está simulada, así que el siguiente paso es hacerla real [09:10].
El reto propuesto tiene tres pasos concretos:
Entra a la pagina de NewsAPI y crea tu API key.
Instala la libreria Requests.
Agrega Requests dentro de la función para consultar noticias reales.
¿Ya intentaste combinar args y kwargs en tu propio cliente de API? Cuéntame en los comentarios cómo te fue con la implementación real.
No se si sea al unico que le pase pero como no se de apis estoy re perdido y me toco por otros metodos entender el tema
Yo igual.
Yo al minuto 0:00: "Qué es una api?"
Yo al minuto 9:47: "Qué es una api?"
Aqui esta mi función real para obtener las noticias de python:
Primero declaro las importaciones necesarias:
from pprint import pprint
import requests
Despues defino las constantes:
API_KEY="tu api key aquí"API_ENDPOINT="https://newsapi.org/v2/everything"API_TIMEOUT=30
Y por ultimo la definición de la función y la llamada:
"""Llamada real a la API NewsAPI con kwargs y requests"""def get_news_from_newsapi(query, api_key=API_KEY,**kwargs): url =API_ENDPOINT params ={"q": query,"apiKey": api_key,**kwargs,}return requests.get(url, params=params)response =get_news_from_newsapi("Python", language=DEFAULT_LANGUAGE, timeout=API_TIMEOUT)response_data = response.json()pprint(response_data)
Buenísimo, muchísimas gracias por compartir tu versión. 😃
Aqui la pongo por si acaso
Gracias, ese es el link!
Gracias
🧩 🌐 Parámetros nombrados y dinámicos en Python
🧠 IDEA CENTRAL
Usa *args y **kwargs para crear funciones flexibles, capaces de:
🔸 Aceptar cualquier cantidad de parámetros.
🔸 Fusionar configuraciones.
🔸 Conectarse a múltiples APIs (News API, The Guardian, etc.)
con una sola función.
🔹 1. Qué son los keywords (**kwargs)
📘 Definición:
Son parámetros nombrados que se reciben como diccionario.
Cada elemento tiene una clave y un valor.
client(*args, **config) → pasa argumentos nombrados al ejecutar la función.
✅ Resultado:
Código más limpio, sin sobrescribir manualmente parámetros.
🧭 5. Orden correcto de parámetros
🧱 Regla de oro en Python:
1️⃣ Parámetros obligatorios
2️⃣ *args → posicionales variables
3️⃣ **kwargs → nombrados y dinámicos
🧩 Ejemplo:
def fetch_news(api_name, *args, **kwargs):
...
🔍 6. Selección dinámica del cliente
🔧 Cómo funciona:
Se define un diccionario con los clientes de API:
api_clients = {
"newsAPI": news_api_client,
"Guardian": guardian_client,
}
El parámetro api_name selecciona el cliente correcto:
client = api_clients[api_name]
💡 Permite conectar múltiples servicios con una sola función.
Mezclando *args y **kwargs
Una vez entendemos el uso de *args y **kwargs, podemos complicar las cosas un poco más. Es posible mezclar argumentos normales con *args y **kwargs dentro de la misma función. Lo único que necesitas saber es que debes definir la función en el siguiente orden:
Primero argumentos normales.
Después los *args.
Y por último los **kwargs.
FUENTE: El libro de Python
<u>Codigo y explicacion general</u>
## RETO: Crear una función que reciba un número indefinido de argumentos y calcule la suma de todos ellos. Imprimir el resultado.import requests
API_KEY ="mi_api_key"API_ENDPOINT ="https://newsapi.org/v2/everything"API_TIMEOUT =30defget_news_from_newsapi(query, api_key=API_KEY, timeout=API_TIMEOUT,**kwargs): params ={"q": query,"apiKey": api_key,**kwargs}# Corrección para la palabra reservada 'from'if"from_date"in params: params["from"]= params.pop("from_date")try: response = requests.get(API_ENDPOINT, params=params, timeout=timeout) response.raise_for_status()return response.json()except requests.exceptions.RequestException as e:print(f"Error fetching news: {e}")returnNone# Llamada limpia usando 'from_date' para evitar el conflicto de sintaxisnoticias = get_news_from_newsapi("Apple", language="en", sortBy="relevancy", from_date="2026-06-03")print(noticias)
<u>1. ¿Qué es una API?</u>
Una API (Application Programming Interface) es un intermediario de software que permite a dos aplicaciones comunicarse entre sí. En este caso, tu código actúa como el "cliente" que solicita información (noticias) a un "servidor" externo (NewsAPI) a través de la web, utilizando el protocolo HTTP.
<u>2. ¿Qué es la API_KEY y cómo se obtiene?</u>
Definición: Una API_KEY es una cadena de texto única que actúa como una contraseña o credencial de identificación. Sirve para que el servidor de la API sepa quién está haciendo la consulta, controle el límite de peticiones permitidas y evite el abuso del servicio.
Cómo obtenerla: Debes registrarte con una cuenta en el sitio web del proveedor (en este caso, newsapi.org), ir a tu panel de usuario y generar una clave gratuita o de pago.
<u>3. ¿Qué es el TIMEOUT?</u>
El Timeout es el tiempo máximo de espera (en segundos) que tu programa tolerará para recibir una respuesta del servidor. En tu código es de 30 segundos. Si el servidor no responde en ese lapso, la ejecución se interrumpe y se lanza una excepción, evitando que tu programa se quede congelado indefinidamente si el servidor está caído.
<u>4. ¿Qué recibe la función get_news_from_newsapi?</u>
La función recibe los siguientes parámetros:
query: El término de búsqueda obligatorio (ej. "Apple").
api_key: La credencial de acceso (por defecto toma la constante API_KEY).
timeout: El tiempo límite de espera (por defecto toma la constante API_TIMEOUT).
**kwargs: Argumentos opcionales con nombre (como language o sortBy).
<u>5. ¿Cuál es la función de **kwargs?</u>
**kwargs (Keyword Arguments) permite pasar un número indeterminado de argumentos con nombre a una función. Dentro de la función, estos argumentos se capturan y se transforman automáticamente en un diccionario ordinario. Esto le da flexibilidad a la función para recibir cualquier parámetro adicional que la API de noticias soporte en el futuro sin necesidad de modificar la estructura del código.
<u>6. ¿Por qué formamos un diccionario llamado params?</u>
La librería requests necesita enviar los criterios de búsqueda al servidor en formato de pares clave-valor (Query Parameters), los cuales se añaden al final de la URL del enlace (ej. ?q=Apple&apiKey=...). Crear el diccionario params agrupa de forma limpia y ordenada todas estas variables para que la librería las procese automáticamente.
<u>7. ¿Por qué quitamos from_date?</u>
El problema: La API de NewsAPI exige un parámetro llamado from para filtrar la fecha de inicio de las noticias. Sin embargo, en Python, from es una palabra reservada utilizada para importar módulos (ej. from math import sqrt). No puedes usarla como nombre de variable o argumento porque causaría un error de sintaxis (SyntaxError).
La solución: En la llamada a la función utilizas el nombre ficticio from_date. Luego, la línea params["from"] = params.pop("from_date") elimina (pop) la clave ficticia del diccionario y asigna su valor a la clave real "from". Así engañas al sistema de nombres de Python pero le envías al servidor la palabra exacta que necesita.
<u>8. ¿Cómo funciona requests.get?</u>
El método requests.get() realiza una petición HTTP de tipo GET hacia la URL especificada (API_ENDPOINT). Envía internamente el diccionario params transformado en parámetros de URL y configura el tiempo de espera con timeout. Al ejecutarse, este método devuelve un objeto de respuesta (Response) que contiene el estado de la conexión, los encabezados y el contenido de los datos devueltos por el servidor.
<u>9. ¿Qué hace el .json()?</u>
Las APIs web suelen responder enviando los datos en formato de texto plano estructurado llamado JSON (JavaScript Object Notation). El método .json() toma ese texto plano devuelto por el servidor y lo deserializa, transformándolo automáticamente en tipos de datos nativos de Python (usualmente diccionarios y listas). Esto te permite acceder a las noticias fácilmente escribiendo código como noticias["articles"][0].
<u>Conceptos adicionales</u>
try ... except (Manejo de excepciones): Bloque de seguridad. Si la petición falla (por falta de internet, URL incorrecta o servidor caído), el programa no se detiene abruptamente con un error en pantalla. En su lugar, el bloque except atrapa el error (RequestException), imprime un mensaje amigable y devuelve None.
response.raise_for_status(): Este método verifica el código de estado HTTP devuelto por el servidor. Si el código indica un error (como un error 401 Unauthorized por una API Key inválida o 404 Not Found), este método lanza automáticamente una excepción para activar el bloque except.
El Reto Inicial: El código incluye un comentario superior sobre un "RETO" de suma indefinida de argumentos (*args), pero el cuerpo del código resuelve otra cosa (consumo de API con **kwargs). *args recibe argumentos posicionales como una tupla (ej. suma(1, 2, 3)), mientras que **kwargs recibe argumentos nombrados como un diccionario.
from dotenv import load_dotenv
import os
import requests
load_dotenv()defnews_api_client(api_key, query, timeout=30, retries=3): url =f"https://newsapi.org/v2/everything?q={query}&pageSize=5&apiKey={api_key}" request = requests.get(url, timeout=timeout) titles =[article['title']for article in request.json()["articles"]]print("\n".join(titles))defguardian_client(api_key, section, from_date, timeout=30, retries=3):returnf"Guardian {section} desde {from_date} con timeout {timeout}"deffetch_news(api_name,**kwargs):"""
Funcion flexible para conectar con la API
"""# variable que contiene variables que se comparten entre las APIs base_config ={"timeout":30,"retries":3,}# Ahora configuramos el resto de las variables config ={**base_config,# Con el ** copiamos los valores del diccionario anterior en este**kwargs,} api_clients ={"newapi": news_api_client,"guardian": guardian_client,} client = api_clients[api_name] client(**config)# Prueba para news apinews_api_key = os.getenv("API_KEY_NEWS_API")fetch_news('newapi', api_key=news_api_key, query="Artificial Intelligence")
Explicame brevemente qué son los args y los kwargs y sus diferencias
Luis, piensa en *args como una lista de valores sueltos que llegan sin nombre, mientras que **kwargs es un diccionario de pares clave-valor que sí tienen nombre. Los primeros son para cantidad variable de datos; los segundos, para configuraciones flexibles donde el nombre importa.
Si tuvieras que diseñar una función que acepte cualquier cantidad de parámetros, ¿cuál de los dos usarías para identificar cada dato por su nombre?
Hola
La única parte que se me complico entender fueron las ultimas dos lineas.
Por que me puse a investigar sobre funciones y logre entender.
Aquí va la explicación para quienes como yo se perdieron un poco,
En Python, es diferente escribir el nombre de la función y escribir el nombre con paréntesis:
guardian_client() Ejecuta la función y da el resultado
guardian_client Hace referencia a la funcion misma (el codigo)
Con:
client = api_clients[api_name]
Le indicamos a la variable client que se convierta en un apodo o referencia temporal para la función elegida.
Luego con:
client(*args,**config)
Ejecutamos como si escribiéramos directamente el nombre de la función con los argumentos que le estamos pasando, por ejemplo:
guardian_client(...)
Si les pasa como yo, y no entienden algo, no se desanimen, paren un momento e investiguen lo que no entiendan. Precisamente así afianzamos conocimientos y salimos de dudas.
Éxito! 🙂
Se me ha dificultado un poco esta clase debido a que no entendía bien el uso de *args en todo esto, lo cual me llevó a caer en confusiones que complicaron mi entendimiento.
Al final llegué a la siguiente conclusión:
*args y **kwargs son dos tuberías paralelas; hacen cosas similares PERO su forma de actuar es diferente.
*args es la CIEGA, SORDA Y UN POCO TONTA: Eso implica que el orden de los parámetros introducidos SÍ importa. Únicamente se queda con la posición de cada parámetro introducido y actúa en consecuencia (como una fila de personas).
**kwargs es la LISTA Y ORGANIZADA (tu crush) del grupo: Sabe dónde va cada cosa independientemente del orden en el que lo pongamos (siempre y cuando le pongamos su correspondiente key para indicarle a dónde va el value).
Piensa en **kwargs como un cartero en pleno reparto: El cartero tiene una carta para "Juan Pérez, Av. X, Edificio 24, Apto 2-A". Lo que hace es ir directo al edificio, buscar el buzón "2-A" y comprobar que pone "Juan Pérez". En ese momento, asigna la carta a su buzón exacto. No le importa si esa carta estaba arriba o abajo en su saca, la entrega por la dirección.
Por eso, si probáis a eliminar *args de la definición de la función (y del return), veréis que el código sigue funcionando sin problemas con los ejemplos que hemos visto.
¿Pero por qué debemos poner *args de todas formas? La respuesta es sencilla: flexibilidad. Porque en un futuro podemos estar trabajando con una API sencilla (o antigua) que solo acepte parámetros por posición y no por nombre (como una que solo pida API_KEY y Query en orden estricto). Al dejar *args, nuestra función estará preparada para aceptar esos datos ordenados si hiciera falta.
A continuacion pongo mi solucion al ejercicio propuesto por el teacher 🙂
He de decir que me ha costado bastante llegar hasta aqui, pero con paciencia (y leyendo la documentacion de request, sobre todo) se consigue
NO HE USADO NewsApi por que han cambiado sus politicas y se ha vuelto un dolor de huevos tener acceso a la API.
En el ejemplo he usado OpenLibrary (Para **kwargs) y PokeApi (Para *args)
import requests
def cliente_pokemon(*args, retries=3, timeout=30,**kwargs)-> str: last_error ="Error inesperado"if not args:return"¡Error! Necesito el nombre del Pokémon en *args" pokemon = args[0] # El primer argumento es ELBicho url = f"https://pokeapi.co/api/v2/pokemon/{pokemon}"for i inrange(0, retries):try:print(f"Intento {i + 1} de conexion") response = requests.get(url, timeout=timeout)if response.status_code==200: data = response.json()return f"✅ Capturado: {data['name'].upper()} (ID: {data['id']}) - Altura: {data['height']}" elif response.status_code==404:return"❌ Pokemon no encontrado" except requests.Timeout:print("⚠️ Timeout... reintentando") last_error ="Timeout" except requests.ConnectionError:print("⚠️ Error de conexión... reintentando") last_error ="Error de Conexión"return f"Upss... Parece que algo ha salido mal.\nNumero de intentos -> {retries}\nMotivo -> {last_error}"def book_client(**kwargs)-> str: url ="https://openlibrary.org/search.json" timeout_val = kwargs.pop("timeout",5) retries = kwargs.pop("retries",3)print(f"📚 Buscando en Open Library...")print(f"🔎 Filtros de búsqueda: {kwargs}")for i inrange(retries):try:print(f"Intento {i + 1} de conexion") response = requests.get(url, params=kwargs, timeout=timeout_val)if response.status_code==200: data = response.json() num_found = data.get("numFound",0)if num_found ==0:return"❌ No se encontraron libros." first_book = data["docs"][0] titulo = first_book.get("title","Sin título") autor = first_book.get("author_name",["Desconocido"])[0] year = first_book.get("first_publish_year","N/A")return( f"✅ENCONTRADO ({num_found} total): '{titulo}' de {autor} ({year})")else:print(f"❌Error API: {response.status_code}\nReintentando...") except requests.Timeout:print("⏱️ Error: La busqueda tarda demasiado.\nReintentando...")return"❌ Ha ocurrido un error inesperado..."def fetch_api(api_name,*args,**kwargs): base_config ={"retries":3,"timeout":30} config ={**base_config,**kwargs,} # Recuerda:El orden importa, si pusieramos primero **kwargs y luego **base_config, la configuracion por defecto podria sustiruir a la configuracion personalizada
api_clients ={"pokemon": cliente_pokemon,"book": book_client} client = api_clients.get( api_name
) # Mejor usar get, por que si intentamos acceder mediante el nombre de la key y resulta que no existe hace kabooomm
ifclient:returnclient(*args,**config)return f"❌ Error: La API '{api_name}' no existe o no esta configurada."if __name__ =="__main__":print(fetch_api("pokemon","torchic")) # mi pokemon favorito jsjs
print("="*10)print(fetch_api("book", title="harry potter"))
**kwargs en Python permite pasar un número variable de argumentos con nombre (clave-valor) a una función, los cuales se reciben dentro de la función como un diccionario.
*args en Python permite que una función acepte un número variable de argumentos posicionales (sin nombre), los cuales se agrupan automáticamente en una tupla dentro de la función; el asterisco (*) es crucial, no el nombre args, que es solo una convención para "argumentos"
Buen ejemplo! sigue practicando.
¡Claro! Aquí tienes un ejemplo en Python usando **kwargs para crear un cliente de APIs flexible, siguiendo lo visto en la clase "Uso de kwargs para crear un cliente de APIs flexible":
deffetch_news(api_name,**kwargs):"""
Función flexible para conectar con la API.
""" base_config ={"timeout":10,"retries":3}# Combina la configuración base con los kwargs config ={**base_config,**kwargs} api_clients ={"NewsAPI":"NewsAPI_client_instance",# Simulación"Guardian":"Guardian_client_instance"# Simulación} client = api_clients.get(api_name)if client:print(f"Conectando a {api_name} con configuración: {config}")# Aquí iría la lógica real para llamar al cliente con la configuraciónreturnf"Resultado de {client} con {config}"else:return"API no reconocida"# Ejemplo de usoprint(fetch_news("NewsAPI", query="Python", language="es", country="co"))print(fetch_news("Guardian", section="technology", from_date="2023-01-01"))
Este código simula cómo **kwargs te permite pasar parámetros dinámicos (como query, language, section) que se fusionan con una configuración base y se usan para interactuar con diferentes APIs, como se explicó en la clase.
Me tomo tiempo, pero lo logre.
La consulta esta por los titulares principales por país: las siglas (us) son la query de búsqueda que se puede modificar para filtrar por país y la api_key es la variable que contiene mi llave API: saben que no se debe compartir.
Acceso a la base de datos del cliente
defnewsapi_client(api_key, query, timeout=30, retries=3):'''Acceso a la base de datos del cliente''' url =f"https://newsapi.org/v2/top-headlines?country={query}&apiKey={api_key}"try: response = requests.get(url)except requests.exceptions.RequestException as e:print(f"Error en la peticion: {e}")return response.json()
Función flexible para elegir el cliente al que se quiere acceder
deffetch_news(api_name,*args,**kwargs):"""Función flexiblle que nos permite conectarnos con la API""" base_config ={"timeout":30,"retries":3} config ={**base_config,**kwargs} api_clients ={"newapi": newsapi_client,"guardian": guardian_client} client = api_clients[api_name]return client(*args,**config)
Creo que es un poco mas fácil de leer de lo que algunos códigos suelen ser.
Una pregunta, en la implementación de la función "fetch_news" en la ultima linea del return no haria falta pasar tambien un api_key como parametro?
import requests
API_KEY="MI_API_KEY"API_ENDPOINT="https://newsapi.org/v2/everything"API_TIMEOUT=30def buscar_noticias(**kwargs):"""
Función para buscar noticias usando NewsAPI"""
# en el diccionario de params solo se incluye lo estrictamente necesario para la consulta, no la configuración general
params ={"apiKey":API_KEY,**kwargs, # Agrega los parámetros específicos de la búsqueda
} # params=params es donde se le pasa mi diccionario de parámetros a la función requests.get, que se encargará de convertirlo en una cadena de consulta adecuada para la URL # Timeout es propio de get, por eso no se agrega en el diccionario de params
try: respuesta = requests.get(API_ENDPOINT, params=params, timeout=API_TIMEOUT) # Este método levanta una excepción si el status code es de error(4xx o 5xx) respuesta.raise_for_status()return respuesta.json() # Devuelve la respuesta como un diccionario de Python except requests.exceptions.RequestExceptionase: # Aquí manejamos el error
print(f"Error en la petición: {e}")returnNone# Uso de la función
noticias =buscar_noticias(q="QA", language="es")ifnoticias:print("Éxito al obtener las noticias")else:print("Falló la obtención de noticias")
# en el diccionario de params solo se incluye lo estrictamente necesario para la consulta, no la configuración general
params = {
"apiKey": API_KEY,
**kwargs, # Agrega los parámetros específicos de la búsqueda
}
# params=params es donde se le pasa mi diccionario de parámetros a la función requests.get, que se encargará de convertirlo en una cadena de consulta adecuada para la URL
# Timeout es propio de get, por eso no se agrega en el diccionario de params
import os
importrequestsfrom dotenv import load_dotenv
API_TIMEOUT_DEFAULT=int(os.getenv("API_TIMEOUT_DEFAULT",30))MAX_RETRIES_DEFAULT=int(os.getenv("MAX_RETRIES_DEFAULT",3))DEFAULT_LANGUAGE="es" # PEP8:Uso de comillas dobles para cadenas de texto
url_template = os.getenv("URL_TEMPLATE")api_key_news_api = os.getenv("API_KEY_NEWS_API")
def newsapi_client( api_key, query, timeout=API_TIMEOUT_DEFAULT, retries=MAX_RETRIES_DEFAULT):print( f"Conectando a NewsAPI con api_key={api_key}, query={query}, timeout={timeout}, retries={retries}") response = requests.get(url_template.format(query, api_key), timeout=timeout)if response.status_code!=200: raise Exception(f"Error al conectar con NewsAPI: {response.status_code}")print(response.json())return response.json()
def fetch_news(api_name,*args,**kwargs):"""Funcion flexible para obtener noticias de cualquier API con opciones dinámicas."""print(f"Fetching news from {api_name} with args: {args} and kwargs: {kwargs}") base_config ={"timeout":30,"retries":3,"language":"es"} config ={**base_config,**kwargs,} api_client ={"newsapi": news_api_client,"theguardian": guardian_client,} client = api_client[api_name.lower()]returnclient(*args,**config)# Definimos los clientes que usarán la librería 'requests'def newsApi_client(*args,**config): url = args[0]try: response = requests.get( url, params={"q": config.get("query"),"language": config.get("language"),"apiKey":"087d58a2b9524315b92c2a4911ba9926",}, timeout=config.get("timeout"),) # Lanza una excepción si el código no es 2xx(éxito) response.raise_for_status()return response.json() except requests.exceptions.HTTPErroraserrh:return{"error": f"Error HTTP: {errh}","status": response.status_code} except requests.exceptions.ConnectionError:return{"error":"Error de conexión: Revisa tu internet."} except requests.exceptions.Timeout:return{"error":"Error de tiempo de espera: El servidor tardó mucho."} except Exceptionase:return{"error": f"Ocurrió un error inesperado: {e}"}# 2. función original(el orquestador)def fetch_news(api_name,*args,**kwargs): base_config ={"timeout":30,"retries":3,"language":"es"} config ={**base_config,**kwargs} api_client ={"newsapi": newsApi_client}
# llamamos a la función cliente
client = api_client[api_name.lower()]returnclient(*args,**config)# Peticionresultado =fetch_news("newsapi","https://newsapi.org/v2/everything", query="IA", timeout=10)print("Resultado de la petición a NewsAPI:")print(resultado)