SQL HTTP функция или процедура - PullRequest
0 голосов
/ 23 января 2020

Я звоню на мой веб-интерфейс из sql. Следующий код работает как задумано и возвращает один большой JSON ответ в таблицу.

Моя проблема заключается в превращении этого в полезную функцию или процедуру.

Я не могу использовать 'INSERT EXE C' внутри функции, и я обязан это сделать, потому что ответ слишком велик для скалярного предела для sp_OAGetProperty.

Я не могу получить ответ в виде выбора из сохраненная версия pro c, потому что это создает вложенную ошибку EXE C.

Я не знаю, как превратить это в нечто, что я могу вызвать в другом месте, и фактически работать с возвращенными данными

DECLARE @contentType NVARCHAR(64);
DECLARE @postData NVARCHAR(2000);
DECLARE @responseTable table(content nvarchar(max));
DECLARE @ret INT;
DECLARE @token INT;
DECLARE @url NVARCHAR(256);
DECLARE @Authorization NVARCHAR(200);


DECLARE @AccessToken varchar(500) = 'REDACTED'
DECLARE @ApiMethod varchar(200) = 'GET'

SET @contentType = 'application/x-www-form-urlencoded';
SET @postData = 'TestParam=123';
SET @url = 'http://localhost/api/testmethod';

IF @ApiMethod = 'GET'
BEGIN
    SET @url = @url + '?' + @postData;
END

EXEC @ret = sp_OACreate 'MSXML2.ServerXMLHTTP', @token OUT;
EXEC @ret = sp_OAMethod @token, 'open', NULL, @ApiMethod, @url, 'false';
DECLARE @bearer varchar(600) = 'Bearer ' + @AccessToken;
EXEC sp_OAMethod @token, 'SetRequestHeader', NULL, 'Authorization', @bearer
EXEC @ret = sp_OAMethod @token, 'setRequestHeader', NULL, 'Content-type', @contentType;

IF @ApiMethod = 'POST'
BEGIN
    EXEC @ret = sp_OAMethod @token, 'send', NULL, @postData;
END

IF @ApiMethod = 'GET'
BEGIN
    EXEC @ret = sp_OAMethod @token, 'send', NULL, NULL;
END

INSERT INTO @responseTable exec sp_OAGetProperty @token, 'responseText'

EXEC @ret = sp_OADestroy @token;

SELECT * FROM @responseTable

1 Ответ

0 голосов
/ 23 января 2020

В случае, если кому-то это нужно, я использовал сохраненный pro c с выходным параметром для возврата ответа json от API, а затем проанализировал его вне pro c. Я все еще ищу лучшее решение для помещения части 2 в proc / function, но сейчас это работает

CREATE Procedure [dbo].[CallApiProc]
(
    @AccessToken varchar(500),
    @ApiPath varchar(200),
    @ApiMethod varchar(200),
    @FormEncodedBody varchar(max),
    @response varchar(max) OUT
)
AS
BEGIN
    -- Declare the return variable here
    DECLARE @authHeader NVARCHAR(64);
    DECLARE @contentType NVARCHAR(64);
    DECLARE @postData NVARCHAR(2000);
    declare @responseTable table(content nvarchar(max));
    DECLARE @responseText NVARCHAR(max);
    DECLARE @responseXML NVARCHAR(2000);
    DECLARE @ret INT;
    DECLARE @status NVARCHAR(32);
    DECLARE @statusText NVARCHAR(32);
    DECLARE @token INT;
    DECLARE @url NVARCHAR(256);
    DECLARE @Authorization NVARCHAR(200);

    --set your post params
    SET @contentType = 'application/x-www-form-urlencoded';
    SET @postData = @FormEncodedBody;
    SET @url = 'http://localhost/api/' + @ApiPath;

    IF @ApiMethod = 'GET'
    BEGIN
        SET @url = @url + '?' + @FormEncodedBody
    END

    -- Open the connection.
    EXEC @ret = sp_OACreate 'MSXML2.ServerXMLHTTP', @token OUT;
    IF @ret <> 0 
    BEGIN
        declare @errorOpen int = cast('Unable to open API connection' as int);
    END
    -- Send the request.
    EXEC @ret = sp_OAMethod @token, 'open', NULL, @ApiMethod, @url, 'false';
    --set a custom header Authorization is the header key and VALUE is the value in the header
    declare @bearer varchar(600) = 'Bearer ' + @AccessToken;
    EXEC sp_OAMethod @token, 'SetRequestHeader', NULL, 'Authorization', @bearer

    EXEC @ret = sp_OAMethod @token, 'setRequestHeader', NULL, 'Content-type', @contentType;

    IF @ApiMethod = 'POST'
    BEGIN
        EXEC @ret = sp_OAMethod @token, 'send', NULL, @postData;
    END

    IF @ApiMethod = 'GET'
    BEGIN
        EXEC @ret = sp_OAMethod @token, 'send', NULL, NULL;
    END

    -- Handle the response.
    EXEC @ret = sp_OAGetProperty @token, 'status', @status OUT;
    EXEC @ret = sp_OAGetProperty @token, 'statusText', @statusText OUT;

    insert into @responseTable exec sp_OAGetProperty @token, 'responseText'


    -- Close the connection.
    EXEC @ret = sp_OADestroy @token;
    IF @ret <> 0 
    BEGIN
        declare @errorClose int = cast('Failed to close API connection' as int);
    END

    select @response = content FROM @responseTable;

END

, а затем я назвал это так

declare @AccessToken varchar(500) = 'REDACTED'

declare @StartDate DATETIME = '2019-12-01';
declare @EndDate DATETIME= '2019-12-08';
declare @TimeGrouping INT = 0;
declare @HierarchyGrouping INT = 1;
declare @RecordType INT = 0;
declare @IncludeZeroRecords BIT = 0;
declare @response varchar(max) = '';

declare @results TABLE (
    UserOId BIGINT,
    LocationOId BIGINT,
    ClientUserId varchar(max),
    ClientLocationId varchar(max),
    ClientMarketId varchar(max),
    StraightTime decimal(18,10),
    Overtime decimal(18,10),
    Doubletime decimal(18,10),
    NonCoverageTime decimal(18,10),
    BudgetTime decimal(18,10)
)

declare @formBody varchar(max) = 
'startDate=' + dbo.UrlEncode(convert(varchar, @StartDate, 101)) + 
'&endDate=' + dbo.UrlEncode(convert(varchar, @EndDate, 101)) + 
'&timeGrouping=' + convert(varchar, @TimeGrouping) + 
'&hierarchyGrouping=' + convert(varchar, @HierarchyGrouping) + 
'&recordType=' + convert(varchar, @RecordType) + 
'&includeZeroRecords=' + case when @IncludeZeroRecords = 1 then 'true' ELSE 'false' END;

EXEC dbo.CallApiProc @AccessToken, 'Employment/TimeBreakdown', 'GET', @formBody, @response OUTPUT;

INSERT INTO @results
SELECT 
    JSON_VALUE(value, '$.UserOId'),
    JSON_VALUE(value, '$.LocationOId'),
    JSON_VALUE(value, '$.ClientUserId'),
    JSON_VALUE(value, '$.ClientLocationId'),
    JSON_VALUE(value, '$.ClientMarketId'),
    JSON_VALUE(value, '$.StraightTime'),
    JSON_VALUE(value, '$.Overtime'),
    JSON_VALUE(value, '$.Doubletime'),
    JSON_VALUE(value, '$.NonCoverageTime'),
    JSON_VALUE(value, '$.BudgetTime')
FROM OPENJSON(@response)

SELECT *, u.* FROM @results r
JOIN [User] u on r.UserOId = u.OId
...