Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Use o Microsoft Entra SDK para o ID do Agente para gerir tanto a aquisição de tokens como a comunicação HTTP numa única operação. O SDK troca seu token de entrada por um com escopo para a API downstream e, em seguida, faz a chamada HTTP e retorna a resposta. Este guia mostra-lhe como configurar APIs downstream, implementar chamadas em TypeScript e Python, lidar com diferentes métodos HTTP e gerir erros com retentações.
Pré-requisitos
- Uma conta no Azure com uma subscrição ativa. Crie uma conta gratuitamente.
- Microsoft Entra SDK para AgentID implementado e em execução no seu ambiente. Consulte o Guia de Instalação para obter instruções de configuração.
- API downstream configurada no SDK com a URL base e os escopos necessários para as APIs que você deseja chamar.
- Tokens de portador de clientes autenticados - Seu aplicativo recebe tokens de aplicativos cliente que você encaminhará para o SDK.
- Permissões apropriadas em Microsoft Entra ID - A sua conta deve ter permissões para registar aplicações e conceder permissões da API.
Configuração
Configure a API downstream no seu Microsoft Entra SDK para as definições de ambiente do Agent ID:
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 sua API downstream
- Escopos: As permissões necessárias para aceder à API downstream
TypeScript/Node.js
Os exemplos a seguir mostram como chamar APIs downstream de aplicativos TypeScript e Node.js. O código demonstra uma função reutilizável e 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 em um aplicativo Express.js usando middleware e manipuladores 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 seguintes mostram como chamar APIs a jusante a partir de aplicações Python usando a biblioteca de pedidos e o Flask para tratamento 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 em uma aplicação Flask, você pode 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)
Pedidos de POST/PUT/PATCH
O endpoint /DownstreamApi suporta operações de modificação através do envio do método HTTP e do corpo da solicitação. Use esses padrões quando precisar criar, atualizar ou excluir recursos na API downstream.
Criação de 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);
Atualizando 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 reintento com backoff exponencial para lidar com falhas transitórias de forma eficaz.
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 Microsoft Entra SDK para Agent ID fornece duas abordagens para chamar APIs downstream. Use esta comparação para determinar qual abordagem melhor atende às suas necessidades.
Comparação de capacidades
| Capacidade | /DownstreamApi | /AuthorizationHeader |
|---|---|---|
| Aquisição de Tokens | Tratado por SDK | Tratado por SDK |
| Solicitação HTTP | Tratado por SDK | A sua responsabilidade |
| Análise de respostas | Embrulhado em JSON | Resposta HTTP Direta |
| Cabeçalhos personalizados | Via parâmetros de consulta | Controlo HTTP total |
| Órgão do Pedido | Encaminhado automaticamente | Controlo total |
| Tratamento de erros | Erros encapsulados no SDK | Erros HTTP padrão |
Quando usar cada abordagem
| Caso de uso | Recommendation | Melhor para |
|---|---|---|
| Chamadas de API REST padrão com padrões convencionais | /DownstreamApi |
GET, POST, PUT, PATCH, DELETE operadores; redução de código padrão |
| Clientes HTTP complexos que requerem configuração personalizada | /AuthorizationHeader |
Tratamento especializado de requisições/respostas; controlo detalhado |
| Acesso direto aos códigos de erro HTTP e cabeçalhos necessários | /AuthorizationHeader |
Aplicativos que precisam de controle de comportamento HTTP de baixo nível |
| Simplicidade e integração rápida priorizadas | /DownstreamApi |
Aplicativos que priorizam a simplicidade em detrimento do controle de baixo nível |
Melhores práticas
- Reutilizar clientes HTTP: crie uma vez e reutilize para evitar sobrecarga de conexão
- Implementar tratamento de erros: adicionar lógica de tentativa para falhas transitórias com recuo exponencial
- Verifique os códigos de status: sempre verifique o código de status antes de analisar o conteúdo da resposta
- Definir tempos limites: configure tempos limite de solicitação apropriados para evitar solicitações suspensas
- Incluir IDs de correlação: registre todas as solicitações com identificadores exclusivos para rastreamento de ponta a ponta
- Validar entrada: limpe e valide dados antes de enviar para APIs downstream
- Monitore o desempenho: rastreie a latência de chamadas de API e as taxas de falha para observabilidade