Интеграция API Курсы валют Центрального Банка РФ в веб-платформе Falcon Space

Введение

В этой статье разберем как можно получать актуальные котировки валют по API от Центрального банка РФ. 

Как это работает на демостенде Falcon Space - демостенд по получению котировок ЦБ РФ API. На нем можно посмотреть как это работает на живом примере. 

Ниже идет описание обмена по API с сайтами, предоставляющими информацию о курсах валют.

Получение котировок валют с сайта ЦБ РФ

 Описание - http://www.cbr.ru/development/SXML/

 для получения котировок на заданный день

нужно отправить GET запрос вида: http://www.cbr.ru/scripts/XML_daily.asp?date_req=02/03/2002

 где    date_req= Date of query (dd/mm/yyyy)

Если параметр(date_req) отсутствует, то вы получите документ на последнюю зарегистрированную дату.  

В некоторых ситуациях, например, когда запрос отправлен вечером – актуальные данные на завтра (Дата в будущем).

<!--?xml version="1.0" encoding="windows-1251"?-->
<valcurs date="06.06.2020" name="Foreign Currency Market">
…
<valute id="R01235">
        <numcode>840</numcode>
        <charcode>USD</charcode>
        <nominal>1</nominal>
        <name>Доллар США</name>
        <value>68,6319</value>
    </valute>
    <valute id="R01239">
        <numcode>978</numcode>
        <charcode>EUR</charcode>
        <nominal>1</nominal>
        <name>Евро</name>
        <value>77,9658</value>
    </valute>
…
</valcurs>

Пример API Request по запросу валют.  

CREATE PROCEDURE [dbo].[api_currencyRatesCBR_request]
	@parameters ExtendedDictionaryParameter READONLY,  -- входящие параметры для внутренней обработки (используйте Key, Value2)
	@username nvarchar(32)  -- текущий пользователь.
    --
    ,@date_req  nvarchar(10) = ''
AS
BEGIN
--  date_req= Date of query (dd/mm/yyyy)
-- * если параметр(date_req) отсутствует, то Вы получите документ на последнюю зарегистрированную дату.
-- 103 = дд/мм/гггг = 04/06/2020
  IF  LEN(  ISNULL ( @date_req   , '' ) )=0
  -- SET @date_req  =  CONVERT ( nvarchar(10) , GETDATE() , 103 )
  SET @date_req  =  CONVERT ( nvarchar(10) , GETDATE() +1 , 103 )  	-- ПО ФАКТУ ВСЕГДА ЕСТЬ КУРС НА ЗАВТРА !!!
--  exec as_print @str = @date_req


DECLARE @apiUrl 		nvarchar(max) = '' 		-- Финальная строка для отправки -- @apiStr -- ФАКТИЧЕСКИ ЭТО Url
SET     @apiUrl = 'http://www.cbr.ru/scripts/XML_daily.asp?'
-- ОТЛАДКА
-- SET     @apiUrl = 'http://www.cbr.ru/scripts/XML_daily.asp?date_req=04/06/2020'
-- SET     @apiUrl = 'http://www.cbr.ru/scripts/XML_daily.asp?date_req=' + ISNULL ( @date_req  , '' )

    -- ОТЛАДКА
	insert into as_trace ( header, text, username, code , created )   values( '@apiUrl', @apiUrl , @username, 'api_currencyRatesCBR_request' , GETDATE() )


	-- SELECT 1  Msg, Result, Url (адрес, куда будет идти запрос)
	select '' Msg, 1 Result, @apiUrl Url

	-- SELECT 2 PARAMETERS - параметры, которые будут передаваться во внешний источник
	-- select 'id' name, '5' value, '' [type] -- form (в форме передается), header (в http headers), get запросы передавайте прямо в URL
END

PROCEDURE [dbo].[api_currencyRatesCBR_response]

 Результат запроса может быть как сообщение с информацией, так и сообщение с ошибкой.

Список возможных сообщений об ошибках.

1 - Ошибка! В результате запроса @response нет корневого элемента ValCurs!

Если ошибок в ответе не обнаружено, из ответа выбираются такие данные:

Курс  Доллар США и Евро.

Пример текста – результат: Курс на 06.06.2020 USD - Доллар США: 68,6319. EUR - Евро: 77,9658.

CREATE PROCEDURE [dbo].[api_currencyRatesCBR_response]
	@response nvarchar(max),
	@parameters ExtendedDictionaryParameter READONLY,  -- входящие параметры для внутренней обработки (используйте Key, Value2 - те же что и на request)

	@username nvarchar(32)
AS
BEGIN

    -- ОТЛАДКА
	insert into as_trace ( header, text, username, code , created )  values( '@response - 1    , 1024 ', SUBSTRING ( @response , 1    , 1024 ) , @username, 'api_currencyRatesCBR_response' , GETDATE() )



DECLARE  @xml_STR Nvarchar(max)
SET      @xml_STR = @response

DECLARE  @xml xml -- переменная в которую преобразуем полученную строку

-- Условия работы / Конвертация строка - xml
-- 1. Тип данных Nvarchar(max)
-- 2. Unicode string with N == > Строки начинаются с N'== >N' "UTF-16"

-- ПРИХОДИТ КОДИРОВКА encoding="windows-1251"
-- set @xml_STR = REPLACE( @xml_STR ,'UTF-8','UTF-16')
set @xml_STR = REPLACE( @xml_STR ,'windows-1251','UTF-16')
set @xml =convert (xml, @xml_STR)
-- select @xml

DECLARE @exist_ValCurs bit = 0
select  @exist_ValCurs = @xml.exist('/ValCurs')

      IF @exist_ValCurs = 0
      BEGIN
          SELECT 'Ошибка! В результате запроса @response нет корневого элемента ValCurs! ' Msg, 0 Result, @response Response
          RETURN
      END

-- OpenXML --
DECLARE @hdoc   int -- Дескриптор - указатель (handle) на создаваемую структуру дерева XML (потом будет использоваться в OPENXML и sp_xml_removedocument);

-- подготовка документа для работы - присвоение Дескриптор @hdoc
-- теперь к данным @xml можно обратиться FROM OPENXML (@hdoc ...
EXEC sp_xml_preparedocument @hdoc OUTPUT , @xml



		-- Во врем. переменную
DECLARE @tmp_currencyRates Table ( id int identity not null
                                  -- , ValDate Nvarchar(100) null
								  , NumCode Nvarchar(100) null, CharCode  Nvarchar(100) null
								  , Nominal Nvarchar(100) null, Name  Nvarchar(100) null, Value Nvarchar(100) null
								  )

-- Дата
DECLARE @valuteDate Nvarchar(32)
SELECT  @valuteDate = X.ValCurDate  FROM OPENXML (@hdoc, '/ValCurs',2) WITH ( ValCurDate Nvarchar(100) '@Date') AS X
-- SELECT @ValCurDate


-- все строки дублируются по 5 раза - по числу полей - ПОСТАВИТЬ DISTINCT
-- SELECT DISTINCT X. *
INSERT INTO  @tmp_currencyRates
SELECT DISTINCT X.NumCode , X.CharCode ,   X.Nominal  , X.Name ,   X.Value
		FROM OPENXML (@hdoc, '/ValCurs/Valute/*',2)      -- * - В Конце строки - работает
				WITH (  --  '.' -- ТОЧКА - ВЫВОД ТЕКУЩЕЙ СТРОКИ -- ТУТ НЕ РАБОТАЕТ
						NumCode  Nvarchar(100) '../NumCode' -- РАБОТАЕТ -- '../CharCode'
					  , CharCode Nvarchar(100) '../CharCode'
					  , Nominal  Nvarchar(100) '../Nominal'
					  , Name	 Nvarchar(100) '../Name'
					  , Value    Nvarchar(100) '../Value'
					   )
					   AS X

 -- Удалить дескриптор
EXEC sp_xml_removedocument @hdoc
-- SELECT * FROM @tmp_currencyRates

    DECLARE  @USDCharCode NVARCHAR(MAX) ,@USDName NVARCHAR(MAX) ,@USDValue NVARCHAR(MAX) , @USDNominal NVARCHAR(MAX)
	        ,@EURCharCode NVARCHAR(MAX) ,@EURName NVARCHAR(MAX) ,@EURValue NVARCHAR(MAX) , @EURNominal NVARCHAR(MAX)

SELECT @USDCharCode = CharCode ,@USDName = Name ,@USDValue = Value ,@USDNominal = Nominal
FROM @tmp_currencyRates WHERE CharCode = 'USD'

SELECT @EURCharCode = CharCode  ,@EURName = Name ,@EURValue = Value , @EURNominal  = Nominal
FROM @tmp_currencyRates WHERE CharCode = 'EUR'
-- -- Курс 69,0151 за 1(Nominal) = Доллар США (Name)

	-- SELECT 1
	select 	 'Курс на ' + ISNULL( @valuteDate, '' )
           + ' ' + ISNULL( @USDCharCode, '' ) +' - '+  ISNULL( @USDName, '' ) +': '+ ISNULL( @USDValue  , '' ) +'.'
           + ' ' + ISNULL( @EURCharCode, '' ) +' - '+  ISNULL( @EURName, '' ) +': '+ ISNULL( @EURValue  , '' ) +'.'

            AS Msg
          , 1 Result, @response Response

	-- SELECT 2 Внешние действия

END

Получение котировок валют через сайт www.cbr-xml-daily.ru

Сайт - https://www.cbr-xml-daily.ru/ предоставляет те же данные в разных форматах. В нашем случае будет получен ответ в формате JSON.

PROCEDURE [dbo].[api_currencyRatesCBRF_JSON_request]

Параметры запроса

  • Адрес сервиса (URL):   https://www.cbr-xml-daily.ru/daily_json.js
  • Метод запроса:  GET
  • Формат на выходе: JSON

 

Входные данные запроса – нет.

Дата не передаётся, при необходимости получить исторические данные запрос будет иметь вид.

https://www.cbr-xml-daily.ru/archive/2020/06/02/daily_json.js

Примечание 1. В некоторых ситуациях, например, когда запрос отправлен вечером – актуальные данные на завтра (Дата в будущем).

Пример текста ответа - response.

Приведен с сокращениями.

{
    "Date": "2020-06-06T11:30:00+03:00",
    "PreviousDate": "2020-06-05T11:30:00+03:00",
    "PreviousURL": "//www.cbr-xml-daily.ru/archive/2020/06/05/daily_json.js",
    "Timestamp": "2020-06-05T16:00:00+03:00",
    "Valute": {
…
 "USD": {
            "ID": "R01235",
            "NumCode": "840",
            "CharCode": "USD",
            "Nominal": 1,
            "Name": "Доллар США",
            "Value": 68.6319,
            "Previous": 69.0151
        },
        "EUR": {
            "ID": "R01239",
            "NumCode": "978",
            "CharCode": "EUR",
            "Nominal": 1,
            "Name": "Евро",
            "Value": 77.9658,
            "Previous": 77.3245
        },
…
    }
}
CREATE PROCEDURE [dbo].[api_currencyRatesCBRF_JSON_request]
	@parameters ExtendedDictionaryParameter READONLY,  -- входящие параметры для внутренней обработки (используйте Key, Value2)
	@username nvarchar(32)  -- текущий пользователь.
AS
BEGIN

DECLARE @apiUrl 		nvarchar(max) = '' 		-- Финальная строка для отправки -- @apiStr -- ФАКТИЧЕСКИ ЭТО Url
SET     @apiUrl = 'https://www.cbr-xml-daily.ru/daily_json.js'
-- История курсов можно брать в архиве https://www.cbr-xml-daily.ru/archive/2020/06/02/daily_json.js

    -- ОТЛАДКА
	insert into as_trace ( header, text, username, code , created )   values( '@apiUrl', @apiUrl , @username, 'api_currencyRatesCBRF_JSON_request' , GETDATE() )


	-- SELECT 1  Msg, Result, Url (адрес, куда будет идти запрос)
	select '' Msg, 1 Result, @apiUrl Url


	-- SELECT 2 PARAMETERS - параметры, которые будут передаваться во внешний источник
	-- select 'id' name, '5' value, '' [type] -- form (в форме передается), header (в http headers), get запросы передавайте прямо в URL
END

PROCEDURE [dbo].[api_currencyRatesCBRF_JSON_response]

Результат запроса может быть как сообщение с информацией, так и сообщение с ошибкой.

Список возможных сообщений об ошибках.

  • 1 - 'Ошибка! Строка @response не является JSON!' (Проверка ответа оператором ISJSON() ). 
  • 2 – 'Ошибка! Запрос @response вернул ошибку! '  @errorText '. code: ' @errorcode '. explanation: '   @errorexplanation. Если в тексте ответа присутствуют поля: error, code, explanation.

Если ошибок в ответе не обнаружено, из ответа выбираются такие данные:

Курс  Доллар США и Евро.

Пример текста – результат: Курс на 06.06.2020 USD - Доллар США: 68,6319. EUR - Евро: 77,9658.

CREATE PROCEDURE [dbo].[api_currencyRatesCBRF_JSON_response]
	@response nvarchar(max),
	@parameters ExtendedDictionaryParameter READONLY,  -- входящие параметры для внутренней обработки (используйте Key, Value2 - те же что и на request)

	@username nvarchar(32)
AS
BEGIN

    -- ОТЛАДКА
	insert into as_trace ( header, text, username, code , created )  values( '@response - 1    , 1024 ', SUBSTRING ( @response , 1    , 1024 ) , @username, 'api_currencyRatesCBRF_JSON_response' , GETDATE() )


    DECLARE @json1 NVARCHAR(MAX)  = N''
	SET @json1 = @response

    -- Для проверки правильности JSON формата существует функция ISJSON, которая возвращает 1, если это JSON, 0 — если нет и NULL, если был передан NULL
    DECLARE @presentJSON bit = 0
    SELECT @presentJSON = ISNULL( ISJSON( @json1 ) , 0 )

    IF @presentJSON <> 1
    BEGIN
        SELECT 'Ошибка! Строка @response не является JSON!' Msg, 0 Result, @response Response
        RETURN
    END

    -- Обработка ошибки в ответе
    DECLARE @presentError bit = 0 ,  @errorText NVARCHAR(MAX) , @errorcode NVARCHAR(MAX) , @errorexplanation NVARCHAR(MAX)
	-- Данные
	,@valuteDate  NVARCHAR(16)
	,@USDCharCode NVARCHAR(MAX) ,@USDName NVARCHAR(MAX) ,@USDValue NVARCHAR(MAX)
	,@EURCharCode NVARCHAR(MAX) ,@EURName NVARCHAR(MAX) ,@EURValue NVARCHAR(MAX)


    SELECT @presentError	= IIF( JSON_VALUE( @json1, '$.error') IS NULL  , 0 , 1 )
     , @errorText		= JSON_VALUE( @json1, '$.error')
     , @errorcode		= JSON_VALUE( @json1, '$.code')
     , @errorexplanation= JSON_VALUE( @json1, '$.explanation')
	 -- Данные
	 , @valuteDate   = JSON_VALUE( @json1, '$.Date')
	 , @USDCharCode  = JSON_VALUE( @json1, '$.Valute.USD.CharCode')
	 , @USDName      = JSON_VALUE( @json1, '$.Valute.USD.Name')
	 , @USDValue     = JSON_VALUE( @json1, '$.Valute.USD.Value')

	 , @EURCharCode  = JSON_VALUE( @json1, '$.Valute.EUR.CharCode')
	 , @EURName      = JSON_VALUE( @json1, '$.Valute.EUR.Name')
	 , @EURValue     = JSON_VALUE( @json1, '$.Valute.EUR.Value')


      IF @presentError = 1
      BEGIN
          SELECT 'Ошибка! Запрос @response вернул ошибку! '+ ISNULL( @errorText, '' ) + '. code: ' +ISNULL( @errorcode, '' )+ '. explanation: ' +ISNULL( @errorexplanation, '' )AS Msg
                 , 0 Result, @response Response
          RETURN
      END

	-- SELECT 1
	 select 'Курс на ' + ISNULL( @valuteDate, '' )
           + ' ' + ISNULL( @USDCharCode, '' ) +' - '+  ISNULL( @USDName, '' ) +': '+ ISNULL( @USDValue  , '' ) +'.'
           + ' ' + ISNULL( @EURCharCode, '' ) +' - '+  ISNULL( @EURName, '' ) +': '+ ISNULL( @EURValue  , '' ) +'.'

            AS Msg
            , 1 Result, @response Response

	-- SELECT 2 Внешние действия

END

Проверка - Официальные курсы валют на заданную дату, устанавливаемые ежедневно

https://www.cbr.ru/currency_base/daily/ 

Заключение

Таким образом довольно легко получать данные и с других источников по аналогии - создаем запрос request к внешнему API, платформа выполняет запрос, а затем происходит обработка результата в процедуре response. 

По данной схеме можно внедрить практически любой API, работающий с GET/POST запросами.

Falcon Space - функциональная веб-платформа разработки на узком стеке MS SQL/Bootstrap. Вводная по Falcon Space
Насколько полезной была статья?

Google поиск по нашей документации

Falcon Space

Это снижение стоимости владения

за счет меньшего количества людей для поддержки и узкого стека разработки. Про снижение стоимости владения продуктом

Это быстрое внесение изменений

по ходу эксплуатации программы. Как создается функционал на платформе

Это простой удобный интерфейс

адаптация под мобильные устройства. Про юзабилити платформы

Нужна бесплатная консультация?
Получить оценку проекта
Создайте концепцию проекта на основе нашего шаблона и получите оценку проекта в виде КП.
Демо-сайт решений
Базисные решения, которые можно гибко адаптировать под себя: менять внешний вид, бизнес-логику и даже структуру базы данных.