Partilhar via


sp_invoke_external_rest_endpoint (Transact-SQL)

Aplica-se a:Banco de Dados SQL do AzureBanco de Dados SQL no Microsoft Fabric

O procedimento armazenado sp_invoke_external_rest_endpoint invoca um ponto de extremidade REST HTTPS fornecido como um argumento de entrada para o procedimento.

Sintaxe

Transact-SQL convenções de sintaxe

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 ]

Argumentos

[ @url = ] N'url'

URL do ponto de extremidade HTTPS REST a ser chamado. @url é nvarchar(4000) sem padrão.

[ @payload = ] N'request_payload'

Cadeia de caracteres Unicode em um formato JSON, XML ou TEXT que contém a carga a ser enviada para o ponto de extremidade HTTPS REST. As cargas úteis devem ser um documento JSON válido, um documento XML bem formado ou texto. @payload é nvarchar(max) sem padrão.

[ @headers = ] N'cabeçalhos'

Cabeçalhos que devem ser enviados como parte da solicitação para o ponto de extremidade HTTPS REST. Os cabeçalhos devem ser especificados usando um formato JSON simples (um documento JSON sem estruturas aninhadas). Os cabeçalhos definidos na lista nomes cabeçalhos proibidos serão ignorados mesmo se explicitamente passados no parâmetro @headers; seus valores serão descartados ou substituídos por valores fornecidos pelo sistema ao iniciar a solicitação HTTPS.

O parâmetro @headers é nvarchar(4000) sem padrão.

[ @method = ] N'método'

Método HTTP para chamar a URL. Deve ser um dos seguintes valores: GET, POST, PUT, PATCH, DELETE, HEAD. @method é nvarchar(6) com POST como valor padrão.

[ @timeout = ] segundos

Tempo em segundos permitido para a execução da chamada HTTPS. Se a solicitação e a resposta HTTP completas não puderem ser enviadas e recebidas dentro do tempo limite definido em segundos, a execução do procedimento armazenado será interrompida e uma exceção será gerada. O tempo limite começa quando a conexão HTTP é iniciada e termina quando a resposta e a carga útil incluída, se houver, foram recebidas. @timeout é um positivo smallint com um valor padrão 30. Valores aceites: 1 a 230.

[ @credential = ] credencial

Indique qual objeto DATABASE SCOPED CREDENTIAL é usado para injetar informações de autenticação na solicitação HTTPS. @credential é sysname sem valor padrão.

@response SAÍDA

Permita que a resposta recebida do ponto de extremidade chamado seja passada para a variável especificada. @response é nvarchar(max).

Valor de retorno

A execução retornará 0 se a chamada HTTPS foi feita e o código de status HTTP recebido for um código de status 2xx (Success). Se o código de status HTTP recebido não estiver no intervalo 2xx, o valor de retorno será o código de status HTTP recebido. Se a chamada HTTPS não puder ser feita, uma exceção será lançada.

Permissões

Requer a permissão de banco de dados EXECUTE ANY EXTERNAL ENDPOINT.

Por exemplo:

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

Formato da resposta

A resposta da chamada HTTP e os dados resultantes enviados de volta pelo ponto de extremidade invocado estão disponíveis por meio do parâmetro de saída @response. @response pode conter um documento JSON com o seguinte esquema:

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

Mais especificamente:

  • resposta: um objeto JSON que contém o resultado HTTP e outros metadados de resposta.
  • resultado: a carga JSON retornada pela chamada HTTP. Omitido se o resultado HTTP recebido for um 204 (No Content).

Ou o @response pode conter um documento XML com o seguinte esquema:

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

Mais especificamente:

  • resposta: um objeto XML que contém o resultado HTTP e outros metadados de resposta.
  • resultado: a carga XML retornada pela chamada HTTP. Omitido se o resultado HTTP recebido for um 204 (No Content).

Na seção response, além do código de status HTTP e da descrição, todo o conjunto de cabeçalhos de resposta recebidos será fornecido no objeto headers. O exemplo a seguir mostra uma seção response em JSON (também a estrutura para respostas de texto):

"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"
    }
  }

E o exemplo a seguir mostra uma seção response em 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>

Pontos finais permitidos

Só são permitidas chamadas para pontos finais nos seguintes serviços:

Serviço do Azure Domínio
Azure Functions *.azurewebsites.net
Serviço de Aplicativos do Azure *.azurewebsites.net
Ambiente do Serviço de Aplicativo do Azure *.appserviceenvironment.net
Aplicativos Web estáticos do Azure *.azurestaticapps.net
Aplicativos Lógicos do Azure *.logic.azure.com
Hubs de Eventos do Azure *.servicebus.windows.net
Grade de Eventos do Azure *.eventgrid.azure.net
Serviços Cognitivos do Azure *.cognitiveservices.azure.com
Azure OpenAI *.openai.azure.com
PowerApps / Dataverse *.api.crm.dynamics.com
Dinâmica da Microsoft *.dynamics.com
Instâncias de contêiner do Azure *.azurecontainer.io
Aplicativos de contêiner do Azure *.azurecontainerapps.io
Power BI api.powerbi.com
Gráfico da Microsoft graph.microsoft.com
Serviços de análise *.asazure.windows.net
IoT Central *.azureiotcentral.com
Gerenciamento de API *.azure-api.net
Armazenamento de Blobs do Azure *.blob.core.windows.net
Arquivos do Azure *.file.core.windows.net
Armazenamento de Filas do Azure *.queue.core.windows.net
Armazenamento de Tabela do Azure *.table.core.windows.net
Serviços de Comunicação do Azure *.communications.azure.com
Pesquisa do Bing api.bing.microsoft.com
Azure Key Vault *.vault.azure.net
Azure AI Search *.search.windows.net
Azure Maps *.atlas.microsoft.com
Azure AI Translator api.cognitive.microsofttranslator.com

As regras de firewall de saída para o Banco de Dados SQL do Azure e o mecanismo de controle de do Azure Synapse Analytics podem ser usadas para restringir ainda mais o acesso de saída a pontos de extremidade externos.

Observação

Se quiser invocar um serviço REST que não esteja na lista de permissões, você pode usar o Gerenciamento de API para expor com segurança o serviço desejado e disponibilizá-lo para sp_invoke_external_rest_endpoint.

Limites

Tamanho da carga útil

A carga útil, tanto quando recebida quanto quando enviada, é codificada em UTF-8 quando enviada por fio. Nesse formato, seu tamanho é limitado a 100 MB.

Comprimento do URL

O comprimento máximo da URL (gerado depois de usar o parâmetro @url e adicionar as credenciais especificadas à cadeia de caracteres de consulta, se houver) é de 8 KB; o comprimento máximo da cadeia de caracteres de consulta (cadeia de caracteres de consulta + cadeia de caracteres de consulta de credencial) é de 4 KB.

Tamanho dos cabeçalhos

O tamanho máximo do cabeçalho de solicitação e resposta (todos os campos de cabeçalho: cabeçalhos passados via parâmetro @headers + cabeçalho de credencial + cabeçalhos fornecidos pelo sistema) é de 8 KB.

Limitação

O número de conexões simultâneas com pontos de extremidade externos feitas via sp_invoke_external_rest_endpoint é limitado a 10% de threads de trabalho, com um máximo de 150 trabalhadores. Em um banco de dados único, a limitação de é imposta no nível do banco de dados, enquanto em um pool elástico a limitação é imposta no nível do banco de dados e do pool.

Para verificar quantas conexões simultâneas um banco de dados pode sustentar, execute a seguinte consulta:

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 uma nova conexão com um ponto de extremidade externo usando sp_invoke_external_rest_endpoint for tentada quando o máximo de conexões simultâneas já for atingido, o erro 10928 (ou 10936 se você tiver atingido os limites de pools elásticos) será gerado. Por exemplo:

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.

Credenciais

Alguns pontos de extremidade REST exigem autenticação para serem invocados corretamente. A autenticação geralmente pode ser feita passando alguns pares chave-valor específicos na cadeia de caracteres de consulta ou nos cabeçalhos HTTP definidos com a solicitação.

É possível usar DATABASE SCOPED CREDENTIALS para armazenar com segurança dados de autenticação (como um token de portador, por exemplo) a serem usados por sp_invoke_external_rest_endpoint para chamar um ponto de extremidade protegido. Ao criar a DATABASE SCOPED CREDENTIAL, use o parâmetro IDENTITY para especificar quais dados de autenticação serão passados para o ponto de extremidade invocado e como. O IDENTITY suporta quatro opções:

  • HTTPEndpointHeaders: enviar dados de autenticação especificados usando os cabeçalhos de solicitação
  • HTTPEndpointQueryString: enviar dados de autenticação especificados usando o Query String
  • : enviar o de identidade gerenciada atribuído pelo sistema usando os cabeçalhos de solicitação
  • : fornecer acesso delegado limitado a recursos por meio de um de URL assinado (também conhecido como SAS)

a DATABASE SCOPED CREDENTIAL criada pode ser usada através do parâmetro @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>]

Com esse valor IDENTITY, a CREDENCIAL COM ESCOPO DE BANCO DE DADOS será adicionada aos cabeçalhos de solicitação. O par chave-valor que contém as informações de autenticação deve ser fornecido através do parâmetro SECRET usando um formato JSON simples. Por exemplo:

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

Regras de nome de credenciais

A CREDENCIAL DE ESCOPO DE BANCO DE DADOS criada deve aderir a regras específicas para ser usada com sp_invoke_external_rest_endpoint. As regras são as seguintes:

  • Deve ser um URL válido
  • O domínio URL deve ser um dos domínios incluídos na lista de permissões
  • A URL não deve conter uma cadeia de caracteres de consulta
  • Protocolo + FQDN (nome de domínio totalmente qualificado) da URL chamada deve corresponder a Protocolo + FQDN do nome da credencial
  • Cada parte do caminho de URL chamado deve corresponder completamente com a respetiva parte do caminho de URL no nome da credencial
  • A credencial deve apontar para um caminho mais genérico do que a URL da solicitação. Por exemplo, uma credencial criada para o caminho https://northwind.azurewebsite.net/customers não pode ser usada para a URL https://northwind.azurewebsite.net

Regras de agrupamento e nome de credenciais

RFC 3986 Seção 6.2.2.1 afirma que "Quando um URI usa componentes da sintaxe genérica, as regras de equivalência de sintaxe de componente sempre se aplicam; ou seja, que o esquema e o host não diferenciam maiúsculas de minúsculas", e RFC 7230 Seção 2.7.3 menciona que "todos os outros são comparados de maneira sensível a maiúsculas e minúsculas".

Como há uma regra de agrupamento definida no nível do banco de dados, a lógica a seguir será aplicada, para ser coerente com a regra de agrupamento de banco de dados e a RFC mencionada acima. (A regra descrita pode ser potencialmente mais restritiva do que as regras RFC, por exemplo, se o banco de dados estiver definido para usar um agrupamento que diferencia maiúsculas de minúsculas.):

  1. Verifique se a URL e a credencial correspondem usando a RFC, o que significa:
    • Verifique o esquema e o host usando um agrupamento que não diferencia maiúsculas de minúsculas (Latin1_General_100_CI_AS_KS_WS_SC)
    • Verifique se todos os outros segmentos do URL são comparados em um agrupamento que diferencia maiúsculas de minúsculas (Latin1_General_100_BIN2)
  2. Verifique se a URL e a credencial correspondem usando as regras de agrupamento de banco de dados (e sem fazer nenhuma codificação de URL).

Conceder permissões para usar credenciais

Os usuários do banco de dados que acessam uma CREDENCIAL COM ESCOPO DE BANCO DE DADOS devem ter permissão para usar essa credencial.

Para usar a credencial, um usuário de banco de dados deve ter REFERENCES permissão em uma credencial específica:

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

Comentários

Tipo de espera

Quando sp_invoke_external_rest_endpoint estiver aguardando a conclusão da chamada para o serviço invocado, ele relatará um tipo de espera HTTP_EXTERNAL_CONNECTION.

HTTPS e TLS

Somente pontos de extremidade configurados para usar HTTPS com protocolo de criptografia TLS são suportados.

Redirecionamentos HTTP

sp_invoke_external_rest_endpoint não seguirá automaticamente qualquer redirecionamento HTTP recebido como resposta do ponto de extremidade invocado.

Cabeçalhos HTTP

sp_invoke_external_rest_endpoint injetará automaticamente os seguintes cabeçalhos na solicitação HTTP:

  • de tipo de conteúdo: definido como application/json; charset=utf-8
  • aceitar: definido como application/json
  • agente do usuário: defina <EDITION>/<PRODUCT VERSION> por exemplo: SQL Azure/12.0.2000.8

Embora do agente do usuário sempre seja substituído pelo procedimento armazenado, os de tipo de conteúdo e aceitar valores de cabeçalho podem ser definidos pelo usuário por meio do parâmetro @headers. Somente a diretiva de tipo de mídia pode ser especificada no tipo de conteúdo e especificar as diretivas charset ou boundary não é possível.

Carga útil de solicitação e resposta suportada tipos de mídia

A seguir estão os valores aceitos para o cabeçalho tipo de conteúdo.

  • Aplicação/JSON
  • aplicativo/vnd.microsoft.*.json
  • Aplicativo/XML
  • aplicativo/vnd.microsoft.*.xml
  • aplicativo/vnd.microsoft.*+xml
  • aplicação/x-www-form-urlencoded
  • Texto/*

Para o aceitar cabeçalho, a seguir estão os valores aceitos.

  • Aplicação/JSON
  • Aplicativo/XML
  • Texto/*

Para obter mais informações sobre tipos de cabeçalho de texto, consulte o registro de tipo de texto em IANA.

Observação

Se você estiver testando a invocação do ponto de extremidade REST com outras ferramentas, como cURL ou qualquer cliente REST moderno, como Insomnia, certifique-se de incluir os mesmos cabeçalhos que são injetados automaticamente por sp_invoke_external_rest_endpoint para ter o mesmo comportamento e resultados.

Melhores práticas

Use uma técnica de processamento em lote

Se você precisar enviar um conjunto de linhas para um ponto de extremidade REST, por exemplo, para uma Função do Azure ou para um hub de eventos, é recomendável agrupar as linhas em um único documento JSON para evitar a sobrecarga de chamada HTTPS para cada linha enviada. Isso pode ser feito usando a instrução FOR JSON, por exemplo:

-- 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;

Exemplos

Aqui você pode encontrar alguns exemplos sobre como usar sp_invoke_external_rest_endpoint para integrar com Serviços comuns do Azure, como o Azure Functions ou os Hubs de Eventos do Azure. Mais exemplos para integrar com outros serviços podem ser encontrados em GitHub.

Um. Chamar uma Função do Azure usando uma ligação de gatilho HTTP sem autenticação

O exemplo a seguir chama uma Função do Azure usando uma associação de gatilho HTTP que permite acesso anônimo.

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. Chamar uma Função do Azure usando uma associação de gatilho HTTP com uma chave de autorização

O exemplo a seguir chama uma Função do Azure usando uma associação de gatilho HTTP configurada para exigir uma chave de autorização. A chave de autorização será passada no cabeçalho x-function-key, conforme exigido pelo Azure Functions. Para obter mais informações, consulte Azure Functions - API key authorization.

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. Leia o conteúdo de um arquivo do Armazenamento de Blobs do Azure com um token SAS

Este exemplo lê um arquivo do Armazenamento de Blobs do Azure usando um token SAS para autenticação. Os resultados serão retornados em XML, portanto, usar o cabeçalho "Accept":"application/xml" será necessário.

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. Enviar uma mensagem para um hub de eventos usando a Identidade Gerenciada do Banco de Dados SQL do Azure

Este exemplo mostra como você pode enviar mensagens para Hubs de Eventos usando a Identidade Gerenciada SQL do Azure. Verifique se você configurou o de Identidade Gerenciada do Sistema para o servidor lógico do Banco de Dados SQL do Azure que hospeda seu banco de dados, por exemplo:

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

Depois disso, configure os Hubs de Eventos para permitir que a Identidade Gerenciada do Azure SQL Server possa enviar mensagens ("função Remetente de Dados dos Hubs de Eventos do Azure") para o hub de eventos desejado. Para obter mais informações, consulte Usar Hubs de Eventos com identidades gerenciadas.

Feito isso, você pode usar o nome de identidade Managed Identity ao definir a credencial de escopo do banco de dados que será usada por sp_invoke_external_rest_endpoint. Conforme explicado em Autenticar um aplicativo com ID do Microsoft Entra para acessar recursos de Hubs de Eventos, o nome do recurso (ou ID) a ser usado ao usar a autenticação do 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. Ler e gravar um arquivo no Armazenamento de Arquivos do Azure com credenciais de escopo do Banco de Dados SQL do Azure

Este exemplo grava um arquivo em um Armazenamento de Arquivos do Azure usando uma credencial de escopo do Banco de Dados SQL do Azure para autenticação e, em seguida, retorna o conteúdo. Os resultados serão retornados em XML, portanto, usar o cabeçalho "Accept":"application/xml" será necessário.

Comece criando uma chave mestra para o Banco de Dados SQL do Azure

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

Em seguida, crie as credenciais com escopo do banco de dados usando o token SAS fornecido pela Conta de Armazenamento de Blob do 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

Em seguida, crie o arquivo e adicione texto a ele com as duas instruções a seguir:

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

Finalmente, use a seguinte instrução para ler o arquivo

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