Перейти к содержанию

Remote Config (v1)

API-метод Remote Config позволяет получить актуальный набор параметров для проекта, который определяется по токену доступа. Подробнее о создании токена читайте в руководстве по аутентификации.

Метод предназначен для динамического конфигурирования приложения без внесения изменений в исходный код.


Метод Endpoint
POST /v1/configs
Почему используется POST, а не GET?

Хотя текущая версия метода не требует тела запроса, использование POST является осознанным архитектурным решением для обеспечения обратной совместимости. В будущем это позволит передавать в теле запроса контекст пользователя (например, геолокацию, версию приложения) для таргетинга параметров или участия в A/B-тестах, не изменяя при этом эндпоинт.

Пример будущего тела запроса:

{
    "conditions": {
        "country": "DE",
        "appVersion": "2.3.1"
    },
    "experiments": {
        "checkout_redesign": "B"
    }
}


Тело запроса

Тело запроса для данного вызова должно быть пустым.


Структура ответа

API возвращает плоский JSON-объект, где каждый ключ является строковым идентификатором параметра, а значение — его актуальным значением.

Тип каждого значения (String, Boolean, Number или JSON) определяется при создании параметра в панели управления. Подробнее: Инструкция по настройке параметров.

Возможные типы значений:

Тип в панели управления Пример значения в ответе
String "Добро пожаловать!"
Boolean true
Number 500 или 7.5
JSON "{\"default\":\"card\",\"methods\":[\"card\"]}"

Особенность обработки типа JSON

Если параметр имеет тип JSON, его значение будет возвращено в виде экранированной строки, а не вложенного JSON-объекта. Вам потребуется дополнительный парсинг этой строки в вашем коде.


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

curl -X POST https://<DOMAIN>/v1/configs \
  -H "Authorization: Bearer <ENCODED_TOKEN>" \
  -H "Content-Type: application/json"
import requests

url = "https://<DOMAIN>/v1/configs"
headers = {
    "Authorization": "Bearer <ENCODED_TOKEN>",
    "Content-Type": "application/json"
}

response = requests.post(url, headers=headers)
response.raise_for_status()
config = response.json()
const url = "https://<DOMAIN>/v1/configs";
const options = {
    method: "POST",
    headers: {
        "Authorization": "Bearer <ENCODED_TOKEN>",
        "Content-Type": "application/json"
    }
};

fetch(url, options)
    .then(response => {
        if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
        return response.json();
    })
    .then(config => console.log(config))
    .catch(error => console.error('Error fetching config:', error));
using System.Net.Http.Headers;
using System.Text.Json;

var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://<DOMAIN>/v1/configs");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "<ENCODED_TOKEN>");

var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();

var config = await response.Content.ReadFromJsonAsync<Dictionary<string, JsonElement>>();
package main

import (
    "encoding/json"
    "net/http"
)

func main() {
    client := &http.Client{}
    req, _ := http.NewRequest("POST", "https://<DOMAIN>/v1/configs", nil)
    req.Header.Add("Authorization", "Bearer <ENCODED_TOKEN>")

    res, err := client.Do(req)
    if err != nil { /* ... обработка ошибки ... */ }
    defer res.Body.Close()

    var config map[string]interface{}
    json.NewDecoder(res.Body).Decode(&config)
}
import okhttp3.*;
import org.json.JSONObject;
import java.io.IOException;

OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
    .url("https://<DOMAIN>/v1/configs")
    .post(RequestBody.create(new byte[0]))
    .addHeader("Authorization", "Bearer <ENCODED_TOKEN>")
    .build();

try (Response response = client.newCall(request).execute()) {
    if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

    JSONObject config = new JSONObject(response.body().string());
}

В параметре <DOMAIN> указывается адрес вашего сервера. В зависимости от типа вашей установки, это может быть:

  • On-premises / Private Cloud: используйте ваш корпоративный домен.
  • SaaS: версия в разработке (домен будет предоставлен после выпуска).

Примеры ответа

{
    "isNewFeatureEnabled": true,
    "maxUsers": 500,
    "welcomeText": "Добро пожаловать!",
    "paymentOptions": "{\"methods\":[\"card\",\"apple_pay\",\"google_pay\"],\"default\":\"card\"}"
}
{}

Примеры обработки ответа

Лучшая практика: Отказоустойчивый доступ

Мы настоятельно рекомендуем всегда указывать локальное значение по умолчанию при получении параметра из конфигурации. Это делает ваше приложение устойчивым к непредвиденным ситуациям, таким как удаление параметра в панели администратора.

Все приведенные ниже примеры следуют этому принципу.

Boolean

is_feature_enabled: bool = config.get('isNewFeatureEnabled', False)
const isFeatureEnabled = config.isNewFeatureEnabled || false;
bool isFeatureEnabled = config.TryGetValue("isNewFeatureEnabled", out var el) && el.ValueKind == JsonValueKind.True;
isFeatureEnabled, _ := config["isNewFeatureEnabled"].(bool)
boolean isFeatureEnabled = config.optBoolean("isNewFeatureEnabled", false);

Number

max_users: int = config.get('maxUsers', 0)
const maxUsers = config.maxUsers || 0;
int maxUsers = config.TryGetValue("maxUsers", out var el) ? el.GetInt32() : 0;
maxUsers, _ := config["maxUsers"].(float64)
int maxUsers = config.optInt("maxUsers", 0);

String

welcome_text: str = config.get('welcomeText', '')
const welcomeText = config.welcomeText || '';
string welcomeText = config.TryGetValue("welcomeText", out var el) ? el.GetString() : "";
welcomeText, _ := config["welcomeText"].(string)
String welcomeText = config.optString("welcomeText", "");

JSON (требует двойного парсинга)

import json

payment_options_str = config.get('paymentOptions', '{}')
payment_options = json.loads(payment_options_str)

methods = payment_options.get('methods', [])
default_method = payment_options.get('default', '')
const paymentOptionsStr = config.paymentOptions || '{}';
const paymentOptions = JSON.parse(paymentOptionsStr);

const methods = paymentOptions.methods || [];
const defaultMethod = paymentOptions.default || '';
using System.Text.Json;
using System.Collections.Generic;
using System.Linq;

string paymentOptionsStr = config.TryGetValue("paymentOptions", out var el) ? el.GetString() : "{}";
var paymentOptions = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(paymentOptionsStr);

List<string> methods = new List<string>();
if (paymentOptions.TryGetValue("methods", out var methodsEl) && methodsEl.ValueKind == JsonValueKind.Array)
{
    methods = methodsEl.EnumerateArray().Select(m => m.GetString()).ToList();
}

string defaultMethod = "";
if (paymentOptions.TryGetValue("default", out var defaultEl) && defaultEl.ValueKind == JsonValueKind.String)
{
    defaultMethod = defaultEl.GetString();
}
import "encoding/json"

var paymentOptions map[string]interface{}
if paymentOptionsStr, ok := config["paymentOptions"].(string); ok {
    json.Unmarshal([]byte(paymentOptionsStr), &paymentOptions)
}

var methods []string
if methodsInterface, ok := paymentOptions["methods"].([]interface{}); ok {
    for _, m := range methodsInterface {
        if methodStr, ok := m.(string); ok {
            methods = append(methods, methodStr)
        }
    }
}
defaultMethod, _ := paymentOptions["default"].(string)
import org.json.JSONObject;
import org.json.JSONArray;
import java.util.ArrayList;
import java.util.List;

String paymentOptionsStr = config.optString("paymentOptions", "{}");
JSONObject paymentOptions = new JSONObject(paymentOptionsStr);

JSONArray methodsArray = paymentOptions.optJSONArray("methods");
List<String> methods = new ArrayList<>();
if (methodsArray != null) {
    for (int i = 0; i < methodsArray.length(); i++) {
        methods.add(methodsArray.getString(i));
    }
}
String defaultMethod = paymentOptions.optString("default", "");

См. также