Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Use o SDK do Microsoft Entra para a ID do Agente para lidar com a aquisição de token e a comunicação HTTP em uma única operação. O SDK troca seu token de entrada por um token que possui escopos específicos para a API de destino, depois realiza a chamada HTTP e retorna a resposta. Este guia mostra como configurar APIs downstream, implementar chamadas em TypeScript e Python, lidar com diferentes métodos HTTP e gerenciar erros com novas tentativas.
Pré-requisitos
- Uma conta Azure com uma assinatura ativa. Crie uma conta gratuitamente.
- Microsoft Entra SDK para AgentID implantado e em execução em seu ambiente. Consulte o Guia de Instalação para obter instruções de instalação.
- API downstream configurada no SDK com a URL base e os escopos necessários para as APIs que você deseja chamar.
- Tokens de acesso de clientes autenticados – seu aplicativo recebe tokens de aplicativos de cliente que você encaminha para o SDK.
- Permissões adequadas no Microsoft Entra ID - sua conta deve ter permissões para registrar aplicativos e conceder permissões de API.
Configuração
Configure a API downstream em seu SDK de Microsoft Entra para configurações de ambiente de ID do agente:
env:
- name: DownstreamApis__Graph__BaseUrl
value: "https://graph.microsoft.com/v1.0"
- name: DownstreamApis__Graph__Scopes__0
value: "User.Read"
- name: DownstreamApis__Graph__Scopes__1
value: "Mail.Read"
A configuração especifica:
- BaseUrl: o ponto de extremidade raiz da API downstream
- Escopos: as permissões necessárias para acessar a API downstream
TypeScript/Node.js
Os exemplos a seguir mostram como chamar APIs intermediárias a partir de aplicativos em TypeScript e Node.js. O código demonstra uma função reutilizável e uma integração com Express.js.
interface DownstreamApiResponse {
statusCode: number;
headers: Record<string, string>;
content: string;
}
async function callDownstreamApi(
incomingToken: string,
serviceName: string,
relativePath: string,
method: string = 'GET',
body?: any
): Promise<any> {
const sdkUrl = process.env.ENTRA_SDK_URL || 'http://localhost:5000';
const url = new URL(`${sdkUrl}/DownstreamApi/${serviceName}`);
url.searchParams.append('optionsOverride.RelativePath', relativePath);
if (method !== 'GET') {
url.searchParams.append('optionsOverride.HttpMethod', method);
}
const requestOptions: any = {
method: method,
headers: {
'Authorization': incomingToken
}
};
if (body) {
requestOptions.headers['Content-Type'] = 'application/json';
requestOptions.body = JSON.stringify(body);
}
const response = await fetch(url.toString(), requestOptions);
if (!response.ok) {
throw new Error(`SDK error: ${response.statusText}`);
}
const data = await response.json() as DownstreamApiResponse;
if (data.statusCode >= 400) {
throw new Error(`API error ${data.statusCode}: ${data.content}`);
}
return JSON.parse(data.content);
}
// Usage examples
async function getUserProfile(incomingToken: string) {
return await callDownstreamApi(incomingToken, 'Graph', 'me');
}
async function listEmails(incomingToken: string) {
return await callDownstreamApi(
incomingToken,
'Graph',
'me/messages?$top=10&$select=subject,from,receivedDateTime'
);
}
async function sendEmail(incomingToken: string, message: any) {
return await callDownstreamApi(
incomingToken,
'Graph',
'me/sendMail',
'POST',
{ message }
);
}
O exemplo a seguir demonstra como integrar essas funções a um aplicativo Express.js usando manipuladores de middleware e de rota:
// Express.js API example
import express from 'express';
const app = express();
app.use(express.json());
app.get('/api/profile', async (req, res) => {
try {
const incomingToken = req.headers.authorization;
if (!incomingToken) {
return res.status(401).json({ error: 'No authorization token' });
}
const profile = await getUserProfile(incomingToken);
res.json(profile);
} catch (error) {
console.error('Error:', error);
res.status(500).json({ error: 'Failed to fetch profile' });
}
});
app.get('/api/messages', async (req, res) => {
try {
const incomingToken = req.headers.authorization;
if (!incomingToken) {
return res.status(401).json({ error: 'No authorization token' });
}
const messages = await listEmails(incomingToken);
res.json(messages);
} catch (error) {
console.error('Error:', error);
res.status(500).json({ error: 'Failed to fetch messages' });
}
});
app.post('/api/messages/send', async (req, res) => {
try {
const incomingToken = req.headers.authorization;
if (!incomingToken) {
return res.status(401).json({ error: 'No authorization token' });
}
const message = req.body;
await sendEmail(incomingToken, message);
res.json({ success: true });
} catch (error) {
console.error('Error:', error);
res.status(500).json({ error: 'Failed to send message' });
}
});
app.listen(8080, () => {
console.log('Server running on port 8080');
});
Python
Os exemplos a seguir mostram como chamar APIs downstream de aplicativos Python usando a biblioteca de solicitações e o Flask para tratamento de HTTP:
import os
import json
import requests
from typing import Dict, Any, Optional
def call_downstream_api(
incoming_token: str,
service_name: str,
relative_path: str,
method: str = 'GET',
body: Optional[Dict[str, Any]] = None
) -> Any:
"""Call a downstream API via the Microsoft Entra SDK for AgentID."""
sdk_url = os.getenv('ENTRA_SDK_URL', 'http://localhost:5000')
params = {
'optionsOverride.RelativePath': relative_path
}
if method != 'GET':
params['optionsOverride.HttpMethod'] = method
headers = {'Authorization': incoming_token}
json_body = None
if body:
headers['Content-Type'] = 'application/json'
json_body = body
response = requests.request(
method,
f"{sdk_url}/DownstreamApi/{service_name}",
params=params,
headers=headers,
json=json_body
)
if not response.ok:
raise Exception(f"SDK error: {response.text}")
data = response.json()
if data['statusCode'] >= 400:
raise Exception(f"API error {data['statusCode']}: {data['content']}")
return json.loads(data['content'])
# Usage examples
def get_user_profile(incoming_token: str) -> Dict[str, Any]:
return call_downstream_api(incoming_token, 'Graph', 'me')
def list_emails(incoming_token: str) -> Dict[str, Any]:
return call_downstream_api(
incoming_token,
'Graph',
'me/messages?$top=10&$select=subject,from,receivedDateTime'
)
def send_email(incoming_token: str, message: Dict[str, Any]) -> None:
call_downstream_api(
incoming_token,
'Graph',
'me/sendMail',
'POST',
{'message': message}
)
Se você quiser integrar essas funções a um aplicativo Flask, poderá usar o seguinte exemplo:
# Flask API example
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/api/profile')
def profile():
incoming_token = request.headers.get('Authorization')
if not incoming_token:
return jsonify({'error': 'No authorization token'}), 401
try:
profile_data = get_user_profile(incoming_token)
return jsonify(profile_data)
except Exception as e:
print(f"Error: {e}")
return jsonify({'error': 'Failed to fetch profile'}), 500
@app.route('/api/messages')
def messages():
incoming_token = request.headers.get('Authorization')
if not incoming_token:
return jsonify({'error': 'No authorization token'}), 401
try:
messages_data = list_emails(incoming_token)
return jsonify(messages_data)
except Exception as e:
print(f"Error: {e}")
return jsonify({'error': 'Failed to fetch messages'}), 500
@app.route('/api/messages/send', methods=['POST'])
def send_message():
incoming_token = request.headers.get('Authorization')
if not incoming_token:
return jsonify({'error': 'No authorization token'}), 401
try:
message = request.json
send_email(incoming_token, message)
return jsonify({'success': True})
except Exception as e:
print(f"Error: {e}")
return jsonify({'error': 'Failed to send message'}), 500
if __name__ == '__main__':
app.run(port=8080)
Solicitações de POST/PUT/PATCH
O /DownstreamApi endpoint suporta operações de modificação ao passar o método HTTP e o corpo da solicitação. Use esses padrões quando precisar criar, atualizar ou excluir recursos na API downstream.
Criando recursos
// POST example - Create a calendar event
async function createEvent(incomingToken: string, event: any) {
return await callDownstreamApi(
incomingToken,
'Graph',
'me/events',
'POST',
event
);
}
// Usage
const newEvent = {
subject: "Team Meeting",
start: {
dateTime: "2024-01-15T14:00:00",
timeZone: "Pacific Standard Time"
},
end: {
dateTime: "2024-01-15T15:00:00",
timeZone: "Pacific Standard Time"
}
};
const createdEvent = await createEvent(incomingToken, newEvent);
Atualização de recursos
// PATCH example - Update user profile
async function updateProfile(incomingToken: string, updates: any) {
return await callDownstreamApi(
incomingToken,
'Graph',
'me',
'PATCH',
updates
);
}
// Usage
await updateProfile(incomingToken, {
mobilePhone: "+1 555 0100",
officeLocation: "Building 2, Room 201"
});
Cenários avançados
Os cenários a seguir demonstram configurações avançadas para casos de uso especializados.
Cabeçalhos personalizados
Adicione cabeçalhos personalizados à solicitação de API downstream:
const url = new URL(`${sdkUrl}/DownstreamApi/MyApi`);
url.searchParams.append('optionsOverride.RelativePath', 'items');
url.searchParams.append('optionsOverride.CustomHeader.X-Custom-Header', 'custom-value');
url.searchParams.append('optionsOverride.CustomHeader.X-Request-Id', requestId);
Substituir escopos
Solicite escopos diferentes dos escopos configurados padrão:
const url = new URL(`${sdkUrl}/DownstreamApi/Graph`);
url.searchParams.append('optionsOverride.RelativePath', 'me');
url.searchParams.append('optionsOverride.Scopes', 'User.ReadWrite');
url.searchParams.append('optionsOverride.Scopes', 'Mail.Send');
Com a identidade do agente
Use a identidade do agente para chamar APIs com permissões de aplicativo:
const url = new URL(`${sdkUrl}/DownstreamApi/Graph`);
url.searchParams.append('optionsOverride.RelativePath', 'users');
url.searchParams.append('AgentIdentity', agentClientId);
url.searchParams.append('AgentUsername', 'admin@contoso.com');
Tratamento de erros
Implemente a lógica de repetição de tentativas com recuo exponencial para lidar com falhas transitórias de forma graciosa.
async function callDownstreamApiWithRetry(
incomingToken: string,
serviceName: string,
relativePath: string,
method: string = 'GET',
body?: any,
maxRetries: number = 3
): Promise<any> {
let lastError: Error;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await callDownstreamApi(
incomingToken,
serviceName,
relativePath,
method,
body
);
} catch (error) {
lastError = error as Error;
// Don't retry on client errors (4xx)
if (error.message.includes('API error 4')) {
throw error;
}
// Retry on server errors (5xx) or network errors
if (attempt < maxRetries) {
const delay = Math.pow(2, attempt) * 100;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
throw new Error(`Failed after ${maxRetries} retries: ${lastError!.message}`);
}
Comparação com a abordagem AuthorizationHeader
O SDK do Microsoft Entra para ID do Agente fornece duas abordagens para chamar APIs downstream. Use essa comparação para determinar qual abordagem melhor atende às suas necessidades.
Comparação de funcionalidades
| Capability | /DownstreamApi | /AuthorizationHeader |
|---|---|---|
| Aquisição de token | Manipulado pelo SDK | Manipulado pelo SDK |
| Solicitação HTTP | Manipulado pelo SDK | Sua responsabilidade |
| Análise de resposta | Encapsulado em JSON | Resposta HTTP direta |
| Cabeçalhos personalizados | Por meio de parâmetros de consulta | Controle HTTP completo |
| Corpo da solicitação | Encaminhado automaticamente | Controle total |
| Tratamento de erros | Erros encapsulados pelo SDK | Erros HTTP padrão |
Quando usar cada abordagem
| Caso de Uso | Recomendação | Mais Adequado Para |
|---|---|---|
| Chamadas à API REST padrão com padrões convencionais | /DownstreamApi |
Operações GET, POST, PUT, PATCH, DELETE; reduzindo código padrão |
| Clientes HTTP complexos que exigem configuração personalizada | /AuthorizationHeader |
Tratamento especializado de solicitação/resposta; controle refinado |
| Necessidade de acesso direto a códigos de erro HTTP e cabeçalhos | /AuthorizationHeader |
Aplicativos que precisam de controle de comportamento HTTP de baixo nível |
| Simplicidade e integração rápida priorizadas | /DownstreamApi |
Aplicativos priorizando a simplicidade em relação ao controle de baixo nível |
Práticas recomendadas
- Reutilizar clientes HTTP: criar uma vez e reutilizar para evitar sobrecarga de conexão
- Implementar tratamento de erros: adicionar lógica de tentativa para falhas transitórias com recuo exponencial
- Verificar códigos de status: sempre verifique o código de status antes de analisar o conteúdo da resposta
- Definir tempos limite: configurar tempos limite de solicitação apropriados para evitar solicitações suspensas
- Incluir IDs de correlação: registrar todas as solicitações com identificadores exclusivos para rastreamento de ponta a ponta
- Validar entrada: sanitizar e validar dados antes de enviar para APIs downstream
- Monitorar o desempenho: acompanhar a latência de chamadas à API e as taxas de falha para observabilidade