sp_invoke_external_rest_endpoint (Transact-SQL)

Si applica a: Database SQL di Azure

La sp_invoke_external_rest_endpoint stored procedure richiama un endpoint REST HTTPS fornito come argomento di input per la procedura.

Sintassi

Convenzioni relative alla sintassi Transact-SQL

EXEC @returnValue = sp_invoke_external_rest_endpoint
  [ @url = ] N'url'
  [ , [ @payload = ] N'request_payload' ]
  [ , [ @headers = ] N'http_headers_as_json_array' ]
  [ , [ @method = ] 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' ]
  [ , [ @timeout = ] seconds ]
  [ , [ @credential = ] credential ]
  [ , @response OUTPUT ]

Argomenti

[ @url = ] N'url'

URL dell'endpoint REST HTTPS da chiamare. @url è nvarchar(4000) senza impostazione predefinita.

[ @payload = ] N'request_payload'

Stringa Unicode in un formato JSON, XML o TEXT che contiene il payload da inviare all'endpoint REST HTTPS. I payload devono essere un documento JSON valido, un documento XML ben formato o un testo. @payload è nvarchar(max) senza impostazione predefinita.

[ @headers = ] N'headers'

Intestazioni che devono essere inviate come parte della richiesta all'endpoint REST HTTPS. Le intestazioni devono essere specificate usando un formato JSON flat (un documento JSON senza strutture annidate). Le intestazioni definite nell'elenco dei nomi delle intestazioni non consentite verranno ignorate anche se passate in modo esplicito nel parametro @headers . I relativi valori verranno eliminati o sostituiti con i valori forniti dal sistema all'avvio della richiesta HTTPS.

Il parametro @headers è nvarchar(4000) senza impostazione predefinita.

[ @method = ] N'method'

Metodo HTTP per chiamare l'URL. Deve essere uno dei valori seguenti: GET, POST, PUT, PATCH, DELETE, HEAD. @method è nvarchar(6) con POST come valore predefinito.

[ @timeout = ] secondi

Tempo in secondi consentito per l'esecuzione della chiamata HTTPS. Se la richiesta HTTP completa e la risposta non possono essere inviate e ricevute entro il timeout definito in secondi, l'esecuzione della stored procedure viene interrotta e viene generata un'eccezione. Il timeout viene avviato all'avvio della connessione HTTP e termina quando la risposta e il payload inclusi, se presenti, sono stati ricevuti. @timeout è un smallint positivo con un valore predefinito 30. Valori accettati: da 1 a 230.

[ @credential = ] credenziali

Indicare l'oggetto DATABASE SCOPED CREDENTIAL usato per inserire le informazioni di autenticazione nella richiesta HTTPS. @credential è sysname senza alcun valore predefinito.

@response PRODOTTO

Consentire il passaggio della risposta ricevuta dall'endpoint chiamato nella variabile specificata. @response è nvarchar(max).

Valore restituito

L'esecuzione restituirà 0 se la chiamata HTTPS è stata eseguita e il codice di stato HTTP ricevuto è un codice di stato 2xx (Success). Se il codice di stato HTTP ricevuto non è compreso nell'intervallo 2xx, il valore restituito sarà il codice di stato HTTP ricevuto. Se la chiamata HTTPS non può essere eseguita affatto, verrà generata un'eccezione.

Autorizzazioni

È richiesta l'autorizzazione EXECUTE ANY EXTERNAL ENDPOINT database.

Ad esempio:

GRANT EXECUTE ANY EXTERNAL ENDPOINT TO [<PRINCIPAL>];

Formato della risposta

La risposta della chiamata HTTP e i dati risultanti inviati dall'endpoint richiamato sono disponibili tramite il parametro di output @response . @response potrebbe contenere un documento JSON con lo schema seguente:

{
  "response": {
    "status": {
      "http": {
        "code": "",
        "description": ""
      }
    },
    "headers": {}
  },
  "result": {}
}

In particolare:

  • response: oggetto JSON che contiene il risultato HTTP e altri metadati di risposta.
  • result: il payload JSON restituito dalla chiamata HTTP. Omesso se il risultato HTTP ricevuto è 204 (No Content).

In alternativa, il @response potrebbe contenere un documento XML con lo schema seguente:

<output>
    <response>
        <status>
            <http code="" description=" " />
        </status>
        <headers>
            <header key="" value="" />
            <header key="" value="" />
        </headers>
    </response>
    <result>
    </result>
</output>

In particolare:

  • response: oggetto XML che contiene il risultato HTTP e altri metadati di risposta.
  • result: payload XML restituito dalla chiamata HTTP. Omesso se il risultato HTTP ricevuto è 204 (No Content).

response Nella sezione, a parte il codice di stato HTTP e la descrizione, l'intero set di intestazioni di risposta ricevute verrà fornito nell'oggetto headers . L'esempio seguente mostra una response sezione in JSON (anche la struttura per le risposte di testo):

"response": {
  "status": {
    "http": {
      "code": 200,
      "description": "OK"
    }
  },
  "headers": {
    "Date": "Thu, 08 Sep 2022 21:51:22 GMT",
    "Content-Length": "1345",
    "Content-Type": "application\/json; charset=utf-8",
    "Server": "Kestrel",
    "Strict-Transport-Security": "max-age=31536000; includeSubDomains"
    }
  }

L'esempio seguente illustra una response sezione in XML:

<response>
    <status>
        <http code="200" description="OK" />
    </status>
    <headers>
        <header key="Date" value="Tue, 01 Apr 1976 21:12:04 GMT" />
        <header key="Content-Length" value="2112" />
        <header key="Content-Type" value="application/xml" />
        <header key="Server" value="Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0" />
        <header key="x-ms-request-id" value="31536000-64bi-64bi-64bi-31536000" />
        <header key="x-ms-version" value="2021-10-04" />
        <header key="x-ms-creation-time" value="Wed, 19 Apr 2023 22:17:33 GMT" />
        <header key="x-ms-server-encrypted" value="true" />
    </headers>
</response>

Endpoint consentiti

Sono consentite solo chiamate agli endpoint nei servizi seguenti:

Servizio di Azure Dominio
Funzioni di Azure *.azurewebsites.net
Servizio app Azure s *.azurewebsites.net
Ambiente del servizio app di Azure *.appserviceenvironment.net
App Web statiche di Azure *.azurestaticapps.net
App per la logica di azure *.logic.azure.com
Hub eventi di Azure *.servicebus.windows.net
Azure Event Grid *.eventgrid.azure.net
Servizi cognitivi di Azure *.cognitiveservices.azure.com
OpenAI di Azure *.openai.azure.com
PowerApps/Dataverse *.api.crm.dynamics.com
Microsoft Dynamics *.dynamics.com
Istanze di Azure Container *.azurecontainer.io
App contenitore di Azure *.azurecontainerapps.io
Power BI api.powerbi.com
Microsoft Graph graph.microsoft.com
Analysis Services *.asazure.windows.net
IoT Central *.azureiotcentral.com
Gestione API *.azure-api.net
Archiviazione BLOB di Azure *.blob.core.windows.net
File di Azure *.file.core.windows.net
Archiviazione code di Azure *.queue.core.windows.net
Azure Table Storage *.table.core.windows.net
Servizi di comunicazione di Azure *.communications.azure.com
Ricerca Bing api.bing.microsoft.com
Azure Key Vault *.vault.azure.net
Azure AI Search *.search.windows.net
Mappe di Azure *.atlas.microsoft.com
Traduttore per Azure AI api.cognitive.microsofttranslator.com

Le regole del firewall in uscita per database SQL di Azure e il meccanismo di controllo di Azure Synapse Analytics possono essere usate per limitare ulteriormente l'accesso in uscita agli endpoint esterni.

Nota

Se si vuole richiamare un servizio REST non compreso nell'elenco consentito, è possibile usare Gestione API per esporre in modo sicuro il servizio desiderato e renderlo disponibile a sp_invoke_external_rest_endpoint.

Limiti

Dimensioni del payload

Il payload, sia quando ricevuto che quando inviato, è codificato tramite UTF-8 quando inviato in rete. In tale formato le dimensioni sono limitate a 100 MB.

Lunghezza URL

La lunghezza massima dell'URL (generata dopo l'uso del parametro @url e l'aggiunta delle credenziali specificate alla stringa di query, se presente) è di 8 KB. La lunghezza massima della stringa di query (stringa di query e stringa di query delle credenziali) è di 4 KB.

Dimensioni intestazioni

La dimensione massima dell'intestazione di richiesta e risposta (tutti i campi di intestazione: intestazioni passate tramite @headers parametro + intestazione delle credenziali e intestazioni fornite dal sistema) è di 8 KB.

Limitazione

Il numero di connessioni simultanee agli endpoint esterni eseguite tramite sp_invoke_external_rest_endpoint è limitato al 10% dei thread di lavoro, con un massimo di 150 ruoli di lavoro. In un'unica limitazione del database viene applicata a livello di database, mentre in una limitazione del pool elastico viene applicata sia a livello di database che a livello di pool.

Per verificare il numero di connessioni simultanee che un database può sostenere, eseguire la query seguente:

SELECT
  [database_name],
  DATABASEPROPERTYEX(DB_NAME(), 'ServiceObjective') AS service_level_objective,
  [slo_name] as service_level_objective_long,
  [primary_group_max_outbound_connection_workers] AS max_database_outbound_connection,
  [primary_pool_max_outbound_connection_workers] AS max_pool_outbound_connection
FROM
  sys.dm_user_db_resource_governance
WHERE
  database_id = DB_ID();

Se viene tentata una nuova connessione a un endpoint esterno quando sp_invoke_external_rest_endpoint vengono già raggiunte le connessioni simultanee massime, verrà generato l'errore 10928 (o 10936 se sono stati raggiunti i limiti dei pool elastici). Ad esempio:

Msg 10928, Level 16, State 4, Procedure sys.sp_invoke_external_rest_endpoint_internal, Line 1 [Batch Start Line 0]
Resource ID : 1. The outbound connections limit for the database is 20 and has been reached.
See 'https://docs.microsoft.com/azure/azure-sql/database/resource-limits-logical-server' for assistance.

Credenziali

Alcuni endpoint REST richiedono l'autenticazione per poter essere richiamati correttamente. L'autenticazione può essere in genere eseguita passando alcune coppie chiave-valore specifiche nella stringa di query o nelle intestazioni HTTP impostate con la richiesta.

È possibile usare LE CREDENZIALI CON AMBITO DATABASE per archiviare in modo sicuro i dati di autenticazione,ad esempio un token di connessione, da usare per sp_invoke_external_rest_endpoint chiamare un endpoint protetto. Quando si crea LA CREDENZIALE CON AMBITO DATABASE, usare il parametro IDENTITY per specificare quali dati di autenticazione verranno passati all'endpoint richiamato e come. IDENTITY supporta quattro opzioni:

  • HTTPEndpointHeaders: inviare dati di autenticazione specificati usando le intestazioni della richiesta
  • HTTPEndpointQueryString: inviare dati di autenticazione specificati usando la stringa di query
  • Managed Identity: inviare l'identità gestita assegnata dal sistema usando le intestazioni della richiesta
  • Shared Access Signature: fornire accesso delegato limitato alle risorse tramite un URL firmato (detto anche firma di accesso condiviso)

L'CREDENTIAL CON AMBITO DATABASE creato può essere usato tramite il parametro @credential :

EXEC sp_invoke_external_rest_endpoint
  @url = N'https://<APP_NAME>.azurewebsites.net/api/<FUNCTION_NAME>?key1=value1',
  @credential = [https://<APP_NAME>.azurewebsites.net/api/<FUNCTION_NAME>]

Con questo valore IDENTITY, l'CREDENTIAL CON AMBITO DATABASE verrà aggiunto alle intestazioni della richiesta. La coppia chiave-valore contenente le informazioni di autenticazione deve essere fornita tramite il parametro SECRET usando un formato JSON flat. Ad esempio:

CREATE DATABASE SCOPED CREDENTIAL [https://<APP_NAME>.azurewebsites.net/api/<FUNCTION_NAME>]
WITH IDENTITY = 'HTTPEndpointHeaders', SECRET = '{"x-functions-key":"<your-function-key-here>"}';

Regole per il nome delle credenziali

L'CREDENTIAL CON AMBITO DATABASE creato deve rispettare regole specifiche per poter essere usate con sp_invoke_external_rest_endpoint. Le regole sono le seguenti:

  • Deve essere un URL valido
  • Il dominio URL deve essere uno di questi domini inclusi nell'elenco consenti
  • L'URL non deve contenere una stringa di query
  • Protocollo + nome di dominio completo (FQDN) dell'URL chiamato deve corrispondere al protocollo e al nome FQDN del nome della credenziale
  • Ogni parte del percorso URL chiamato deve corrispondere completamente alla rispettiva parte del percorso URL nel nome delle credenziali
  • Le credenziali devono puntare a un percorso più generico rispetto all'URL della richiesta. Ad esempio, non è possibile usare credenziali create per il percorso https://northwind.azurewebsite.net/customers per l'URL https://northwind.azurewebsite.net

Regole di confronto e nome credenziali

RFC 3986 Sezione 6.2.2.1 indica che "Quando un URI usa componenti della sintassi generica, le regole di equivalenza della sintassi dei componenti si applicano sempre; vale a dire che lo schema e l'host non fanno distinzione tra maiuscole e minuscole" e RFC 7230 Sezione 2.7.3 indica che "tutti gli altri vengono confrontati in modo con distinzione tra maiuscole e minuscole".

Poiché è presente un set di regole di confronto a livello di database, verrà applicata la logica seguente per essere coerente con la regola delle regole di confronto del database e la RFC indicata in precedenza. La regola descritta potrebbe potenzialmente essere più restrittiva rispetto alle regole RFC, ad esempio se il database è impostato per usare regole di confronto con distinzione tra maiuscole e minuscole.

  1. Controllare se l'URL e la corrispondenza delle credenziali usano la RFC, ovvero:
    • Controllare lo schema e l'host usando regole di confronto senza distinzione tra maiuscole e minuscole (Latin1_General_100_CI_AS_KS_WS_SC)
    • Verificare che tutti gli altri segmenti dell'URL vengano confrontati in regole di confronto con distinzione tra maiuscole e minuscole (Latin1_General_100_BIN2)
  2. Verificare che l'URL e le credenziali corrispondano usando le regole di confronto del database (e senza eseguire alcuna codifica URL).

Concedere le autorizzazioni per l'uso delle credenziali

Gli utenti del database che accedono a UN DATABASE SCOPED CREDENTIAL devono disporre dell'autorizzazione per l'utilizzo di tali credenziali.

Per usare le credenziali, un utente del database deve disporre REFERENCES dell'autorizzazione per credenziali specifiche:

GRANT REFERENCES ON DATABASE SCOPED CREDENTIAL::[<CREDENTIAL_NAME>] TO [<PRINCIPAL>];

Osservazioni:

Tipo di attesa

Quando sp_invoke_external_rest_endpoint è in attesa del completamento della chiamata al servizio richiamato, verrà visualizzato un HTTP_EXTERNAL_CONNECTION tipo di attesa.

HTTPS e TLS

Sono supportati solo gli endpoint configurati per l'uso di HTTPS con almeno il protocollo di crittografia TLS 1.2.

Reindirizzamenti HTTP

sp_invoke_external_rest_endpoint non seguirà automaticamente alcun reindirizzamento HTTP ricevuto come risposta dall'endpoint richiamato.

Intestazioni HTTP

sp_invoke_external_rest_endpoint inserisce automaticamente le intestazioni seguenti nella richiesta HTTP:

  • content-type: impostato su application/json; charset=utf-8
  • accept: impostato su application/json
  • user-agent: impostare <EDITION>/<PRODUCT VERSION> ad esempio: SQL Azure/12.0.2000.8

Anche se user-agent verrà sempre sovrascritto dalla stored procedure, il tipo di contenuto e accettare i valori di intestazione può essere definito dall'utente tramite il parametro @headers. È consentito specificare solo la direttiva media type nel tipo di contenuto e specificare le direttive charset o boundary non è possibile.

Tipi di supporti supportati per il payload di richiesta e risposta

Di seguito sono riportati i valori accettati per il tipo di contenuto dell'intestazione.

  • application/json
  • application/vnd.microsoft.*.json
  • application/xml
  • application/vnd.microsoft.*.xml
  • application/vnd.microsoft.*+xml
  • application/x-www-form-urlencoded
  • Testo/*

Per l'intestazione accept , di seguito sono riportati i valori accettati.

  • application/json
  • application/xml
  • Testo/*

Per altre informazioni sui tipi di intestazione di testo, vedere registro dei tipi di testo in IANA.

Nota

Se si sta testando la chiamata dell'endpoint REST con altri strumenti, ad esempio cURL o qualsiasi client REST moderno come Insonnia, assicurarsi di includere le stesse intestazioni inserite automaticamente da sp_invoke_external_rest_endpoint per avere lo stesso comportamento e risultati.

Procedure consigliate

Usare una tecnica di invio in batch

Se è necessario inviare un set di righe a un endpoint REST, ad esempio a una funzione di Azure o a un hub eventi, è consigliabile inviare in batch le righe in un singolo documento JSON, per evitare il sovraccarico delle chiamate HTTPS per ogni riga inviata. Questa operazione può essere eseguita usando l'istruzione FOR JSON , ad esempio:

-- create the payload
DECLARE @payload AS NVARCHAR(MAX);

SET @payload = (
        SELECT [object_id], [name], [column_id]
        FROM sys.columns
        FOR JSON AUTO
        );

-- invoke the REST endpoint
DECLARE @retcode INT,
    @response AS NVARCHAR(MAX);

EXEC @retcode = sp_invoke_external_rest_endpoint @url = '<REST_endpoint>',
    @payload = @payload,
    @response = @response OUTPUT;

-- return the result
SELECT @retcode, @response;

Esempi

Di seguito sono riportati alcuni esempi su come usare per l'integrazione sp_invoke_external_rest_endpoint con servizi di Azure comuni, ad esempio Funzioni di Azure o Hub eventi di Azure. Altri esempi per l'integrazione con altri servizi sono disponibili in GitHub.

R. Chiamare una funzione di Azure usando un'associazione di trigger HTTP senza autenticazione

L'esempio seguente chiama una funzione di Azure usando un'associazione di trigger HTTP che consente l'accesso anonimo.

DECLARE @ret INT, @response NVARCHAR(MAX);

EXEC @ret = sp_invoke_external_rest_endpoint
  @url = N'https://<APP_NAME>.azurewebsites.net/api/<FUNCTION_NAME>?key1=value1',
  @headers = N'{"header1":"value_a", "header2":"value2", "header1":"value_b"}',
  @payload = N'{"some":{"data":"here"}}',
  @response = @response OUTPUT;

SELECT @ret AS ReturnCode, @response AS Response;

B. Chiamare una funzione di Azure usando un'associazione di trigger HTTP con una chiave di autorizzazione

L'esempio seguente chiama una funzione di Azure usando un'associazione di trigger HTTP configurata per richiedere una chiave di autorizzazione. La chiave di autorizzazione verrà passata nell'intestazione x-function-key come richiesto da Funzioni di Azure. Per altre informazioni, vedere Funzioni di Azure - Autorizzazione della chiave API.

CREATE DATABASE SCOPED CREDENTIAL [https://<APP_NAME>.azurewebsites.net/api/<FUNCTION_NAME>]
WITH IDENTITY = 'HTTPEndpointHeaders', SECRET = '{"x-functions-key":"<your-function-key-here>"}';

DECLARE @ret INT, @response NVARCHAR(MAX);

EXEC @ret = sp_invoke_external_rest_endpoint
  @url = N'https://<APP_NAME>.azurewebsites.net/api/<FUNCTION_NAME>?key1=value1',
  @headers = N'{"header1":"value_a", "header2":"value2", "header1":"value_b"}',
  @credential = [https://<APP_NAME>.azurewebsites.net/api/<FUNCTION_NAME>],
  @payload = N'{"some":{"data":"here"}}',
  @response = @response OUTPUT;

SELECT @ret AS ReturnCode, @response AS Response;

C. Leggere il contenuto di un file da Archiviazione BLOB di Azure con un token di firma di accesso condiviso

Questo esempio legge un file da Archiviazione BLOB di Azure usando un token di firma di accesso condiviso per l'autenticazione. I risultati verranno restituiti in XML, quindi sarà necessario usare l'intestazione "Accept":"application/xml" .

DECLARE @ret INT, @response NVARCHAR(MAX);

EXEC @ret = sp_invoke_external_rest_endpoint
  @url = N'https://blobby.blob.core.windows.net/datafiles/my_favorite_blobs.txt?sp=r&st=2023-07-28T19:56:07Z&se=2023-07-29T03:56:07Z&spr=https&sv=2022-11-02&sr=b&sig=XXXXXX1234XXXXXX6789XXXXX',
  @headers = N'{"Accept":"application/xml"}',
  @method = 'GET',
  @response = @response OUTPUT;

SELECT @ret AS ReturnCode, @response AS Response;

D. Inviare un messaggio a un hub eventi usando l'identità gestita database SQL di Azure

Questo esempio illustra come inviare messaggi a Hub eventi usando l'identità gestita di SQL di Azure. Assicurarsi di aver configurato l'identità gestita di sistema per il server logico database SQL di Azure che ospita il database, ad esempio:

az sql server update -g <resource-group> -n <azure-sql-server> --identity-type SystemAssigned

Successivamente, configurare Hub eventi per consentire all'identità gestita di SQL Server di Azure di poter inviare messaggi ("Hub eventi di Azure ruolo Mittente dati") all'hub eventi desiderato. Per altre informazioni, vedere Usare Hub eventi con identità gestite.

Al termine, è possibile usare il nome dell'identità Managed Identity quando si definiscono le credenziali con ambito database che verranno usate da sp_invoke_external_rest_endpoint. Come illustrato in Autenticare un'applicazione con Microsoft Entra ID per accedere alle risorse di Hub eventi, il nome della risorsa (o l'ID) da usare quando si usa l'autenticazione Microsoft Entra è https://eventhubs.azure.net:

CREATE DATABASE SCOPED CREDENTIAL [https://<EVENT-HUBS-NAME>.servicebus.windows.net]
    WITH IDENTITY = 'Managed Identity',
        SECRET = '{"resourceid": "https://eventhubs.azure.net"}';
GO

DECLARE @Id UNIQUEIDENTIFIER = NEWID();
DECLARE @payload NVARCHAR(MAX) = (
        SELECT *
        FROM (
            VALUES (@Id, 'John', 'Doe')
            ) AS UserTable(UserId, FirstName, LastName)
        FOR JSON AUTO,
            WITHOUT_ARRAY_WRAPPER
        )
DECLARE @url NVARCHAR(4000) = 'https://<EVENT-HUBS-NAME>.servicebus.windows.net/from-sql/messages';
DECLARE @headers NVARCHAR(4000) = N'{"BrokerProperties": "' + STRING_ESCAPE('{"PartitionKey": "' + CAST(@Id AS NVARCHAR(36)) + '"}', 'json') + '"}'
DECLARE @ret INT, @response NVARCHAR(MAX);

EXEC @ret = sp_invoke_external_rest_endpoint @url = @url,
    @headers = @headers,
    @credential = [https://<EVENT-HUBS-NAME>.servicebus.windows.net],
    @payload = @payload,
    @response = @response OUTPUT;

SELECT @ret AS ReturnCode, @response AS Response;

E. Leggere e scrivere un file in Archiviazione file di Azure con un database SQL di Azure credenziali con ambito

Questo esempio scrive un file in un archivio file di Azure usando un database SQL di Azure credenziali con ambito per l'autenticazione e quindi restituisce il contenuto. I risultati verranno restituiti in XML, quindi sarà necessario usare l'intestazione "Accept":"application/xml" .

Per iniziare, creare una chiave master per il database SQL di Azure

create master key encryption by password = '2112templesmlm2BTS21.qwqw!@0dvd'
go

Creare quindi le credenziali con ambito database usando il token di firma di accesso condiviso fornito dall'account Archiviazione BLOB di Azure.

create database scoped credential [filestore]
with identity='SHARED ACCESS SIGNATURE',
secret='sv=2022-11-02&ss=bfqt&srt=sco&sp=seespotrun&se=2023-08-03T02:21:25Z&st=2023-08-02T18:21:25Z&spr=https&sig=WWwwWWwwWWYaKCheeseNXCCCCCCDDDDDSSSSSU%3D'
go

Creare quindi il file e aggiungervi testo con le due istruzioni seguenti:

declare @payload nvarchar(max) = (select * from (values('Hello from Azure SQL!', sysdatetime())) payload([message], [timestamp])for json auto, without_array_wrapper)
declare @response nvarchar(max), @url nvarchar(max), @headers nvarchar(1000);
declare @len int = len(@payload)

-- Create the File
set @url = 'https://myfiles.file.core.windows.net/myfiles/test-me-from-azure-sql.json'
set @headers = json_object(
        'x-ms-type': 'file',
        'x-ms-content-length': cast(@len as varchar(9)),
        'Accept': 'application/xml')
exec sp_invoke_external_rest_endpoint
    @url = @url,
    @method = 'PUT',
    @headers = @headers,
    @credential = [filestore],
    @response = @response output
select cast(@response as xml);

-- Add text to the File
set @headers = json_object(
        'x-ms-range': 'bytes=0-' + cast(@len-1 as varchar(9)),
        'x-ms-write': 'update',
        'Accept': 'application/xml');
set @url = 'https://myfiles.file.core.windows.net/myfiles/test-me-from-azure-sql.json'
set @url += '?comp=range'
exec sp_invoke_external_rest_endpoint
    @url = @url,
    @method = 'PUT',
    @headers = @headers,
    @payload = @payload,
    @credential = [filestore],
    @response = @response output
select cast(@response as xml)
go

Usare infine l'istruzione seguente per leggere il file

declare @response nvarchar(max);
declare @url nvarchar(max) = 'https://myfiles.file.core.windows.net/myfiles/test-me-from-azure-sql.json'
exec sp_invoke_external_rest_endpoint
    @url = @url,
    @headers = '{"Accept":"application/xml"}',
    @credential = [filestore],
    @method = 'GET',
    @response = @response output
select cast(@response as xml)
go