یک اتصال دهنده جامعه بسازید

مراحل ساخت یک رابط اجتماعی عبارتند از:

  1. یک پروژه جدید Apps Script ایجاد کنید.
  2. کد کانکتور را بنویسید.
  3. مانیفست پروژه را تکمیل کنید.

یک پروژه جدید Apps Script ایجاد کنید

برای ایجاد یک پروژه جدید به Google Apps Script مراجعه کنید. Apps Script یک اسکریپت پیش‌فرض برای شما ایجاد می‌کند. می‌توانید تابع myFunction را حذف کرده و نام پروژه را تغییر دهید. ( درباره Apps Script بیشتر بدانید )

کد کانکتور را بنویسید

هر کانکتور باید مجموعه‌ای از توابع تعریف‌شده‌ی خاص داشته باشد. برنامه‌ی میزبانی (مثلاً Looker Studio) این توابع را اجرا خواهد کرد. انتظار می‌رود کانکتور شما درخواست‌های ورودی را مدیریت کرده و مطابق آنچه در مرجع API کانکتور انجمن توضیح داده شده است، پاسخ دهد. اگر در حین توسعه‌ی کد خود با مشکل مواجه شدید، برای کمک ، راهنمای اشکال‌زدایی را مطالعه کنید.

تعریف نوع احراز هویت در getAuthType()

این تابع برای شناسایی روش احراز هویت مورد استفاده برای سرویس شخص ثالث فراخوانی می‌شود. برای جزئیات بیشتر به مرجع getAuthType() مراجعه کنید. روش‌های احراز هویت پشتیبانی‌شده‌ی فعلی در مرجع AuthType فهرست شده‌اند.

برای مثال، رابط زیر نیازی به احراز هویت ندارد:

npm-downloads/src/auth.js
var cc = DataStudioApp.createCommunityConnector();

// https://developers.google.com/datastudio/connector/reference#getauthtype
function getAuthType() {
  var AuthTypes = cc.AuthType;
  return cc
    .newAuthTypeResponse()
    .setAuthType(AuthTypes.NONE)
    .build();
}

اگر منبع داده شما نیاز به احراز هویت OAuth 2.0 دارد، راهنمای احراز هویت OAuth 2.0 را مشاهده کنید و توابع مورد نیاز اضافی را به کانکتور خود اضافه کنید.

تعریف پیکربندی از طریق getConfig()

تابع getConfig() برای دریافت پیکربندی کانکتور، از جمله مقادیر ارائه شده توسط کاربر که کانکتور شما به آنها نیاز دارد، فراخوانی می‌شود. برای جزئیات بیشتر به مرجع getConfig() مراجعه کنید.

بر اساس پاسخ ارائه شده توسط getConfig() ، Looker Studio صفحه پیکربندی کانکتور را رندر می‌کند. عناصر پیکربندی پشتیبانی شده در مرجع ConfigType فهرست شده‌اند.

اگر منبع داده شما به تاریخ به عنوان پارامتر نیاز دارد، config.setDateRangeRequired(true) را فراخوانی کنید. اگر نیاز به پرسیدن سوالات مربوط به پیکربندی شرطی یا پویا دارید، به پیکربندی مرحله‌ای مراجعه کنید.

در زیر مثالی از یک رابط آمده است که از کاربر می‌خواهد کد نام بسته npm را وارد کند. یک فیلد info و یک فیلد input در تابع getConfig() تعریف شده‌اند:

npm-downloads/src/main.js
// https://developers.google.com/datastudio/connector/reference#getconfig
function getConfig() {
  var config = cc.getConfig();

  config
    .newInfo()
    .setId('instructions')
    .setText(
      'Enter npm package names to fetch their download count. An invalid or blank entry will revert to the default value.'
    );

  config
    .newTextInput()
    .setId('package')
    .setName(
      'Enter a single package name or multiple names separated by commas (no spaces!)'
    )
    .setHelpText('e.g. "googleapis" or "package,somepackage,anotherpackage"')
    .setPlaceholder(DEFAULT_PACKAGE)
    .setAllowOverride(true);

  config.setDateRangeRequired(true);

  return config.build();
}

فیلدها را با getSchema() تعریف کنید

این تابع برای دریافت طرحواره (schema) مربوط به درخواست داده شده فراخوانی می‌شود. هر پارامتر پیکربندی که توسط تابع getConfig() تعریف شده باشد، در آرگومان request ارائه خواهد شد. برای جزئیات بیشتر به مرجع getSchema() مراجعه کنید.

بسته به منبع داده کانکتور شما و پیکربندی ارائه شده توسط کاربر، ممکن است طرحواره ثابت باشد یا ممکن است مجبور شوید آن را به صورت پویا در زمان درخواست ارائه دهید.

برای مثال، اگر یک کانکتور در حال دریافت داده‌های گزارش بر اساس یک Report ID باشد، داده‌های برگردانده شده برای آن گزارش و از این رو طرحواره ممکن است از قبل شناخته شده نباشند. در این حالت getSchema() ممکن است نیاز به دریافت داده‌ها داشته باشد و طرحواره باید محاسبه شود.

npm-downloads/src/main.js
function getFields() {
  var fields = cc.getFields();
  var types = cc.FieldType;
  var aggregations = cc.AggregationType;

  fields
    .newDimension()
    .setId('packageName')
    .setName('Package')
    .setType(types.TEXT);

  fields
    .newDimension()
    .setId('day')
    .setName('Date')
    .setType(types.YEAR_MONTH_DAY);

  fields
    .newMetric()
    .setId('downloads')
    .setName('Downloads')
    .setType(types.NUMBER)
    .setAggregation(aggregations.SUM);

  return fields;
}

// https://developers.google.com/datastudio/connector/reference#getschema
function getSchema(request) {
  return {schema: getFields().build()};
}

واکشی و بازگرداندن داده‌ها با getData()

این تابع برای دریافت داده‌ها برای درخواست داده شده فراخوانی می‌شود. هر پارامتر پیکربندی که توسط تابع getConfig() تعریف شده باشد، در آرگومان request ارائه خواهد شد. برای جزئیات بیشتر به مرجع getData() مراجعه کنید.

پارامترهای زیر از درخواست getData() نیاز به توجه بیشتری دارند:

  • lastRefresh
    lastRefresh نشان دهنده یک مهر زمانی است که زمان آخرین درخواست برای به‌روزرسانی داده‌ها را مشخص می‌کند. شما باید بتوانید این مقدار را با new Date(timestampString) تجزیه کنید. اگر از Apps Script Cache Service یا هر روش ذخیره‌سازی دیگری استفاده می‌کنید، مهر زمانی lastRefresh می‌تواند به شما کمک کند تا تعیین کنید که آیا یک درخواست واکشی جدید به منبع داده ارسال کنید یا داده‌ها را از حافظه پنهان (cache) ارائه دهید.

  • dateRange
    اگر dateRangeRequired در getConfig() روی true تنظیم شده باشد، هر فراخوانی getData() شامل محدوده تاریخ انتخاب شده در درخواست خواهد بود. برای جزئیات بیشتر به بخش «کار با محدوده‌های تاریخ» مراجعه کنید.

مثال زیر داده‌ها را بر اساس درخواست ورودی دریافت کرده و آمار بسته را برمی‌گرداند:

npm-downloads/src/main.js
// https://developers.google.com/datastudio/connector/reference#getdata
function getData(request) {
  request.configParams = validateConfig(request.configParams);

  var requestedFields = getFields().forIds(
    request.fields.map(function(field) {
      return field.name;
    })
  );

  try {
    var apiResponse = fetchDataFromApi(request);
    var normalizedResponse = normalizeResponse(request, apiResponse);
    var data = getFormattedData(normalizedResponse, requestedFields);
  } catch (e) {
    cc.newUserError()
      .setDebugText('Error fetching data from API. Exception details: ' + e)
      .setText(
        'The connector has encountered an unrecoverable error. Please try again later, or file an issue if this error persists.'
      )
      .throwException();
  }

  return {
    schema: requestedFields.build(),
    rows: data
  };
}

/**
 * Gets response for UrlFetchApp.
 *
 * @param {Object} request Data request parameters.
 * @returns {string} Response text for UrlFetchApp.
 */
function fetchDataFromApi(request) {
  var url = [
    'https://api.npmjs.org/downloads/range/',
    request.dateRange.startDate,
    ':',
    request.dateRange.endDate,
    '/',
    request.configParams.package
  ].join('');
  var response = UrlFetchApp.fetch(url);
  return response;
}

/**
 * Parses response string into an object. Also standardizes the object structure
 * for single vs multiple packages.
 *
 * @param {Object} request Data request parameters.
 * @param {string} responseString Response from the API.
 * @return {Object} Contains package names as keys and associated download count
 *     information(object) as values.
 */
function normalizeResponse(request, responseString) {
  var response = JSON.parse(responseString);
  var package_list = request.configParams.package.split(',');
  var mapped_response = {};

  if (package_list.length == 1) {
    mapped_response[package_list[0]] = response;
  } else {
    mapped_response = response;
  }

  return mapped_response;
}

/**
 * Formats the parsed response from external data source into correct tabular
 * format and returns only the requestedFields
 *
 * @param {Object} parsedResponse The response string from external data source
 *     parsed into an object in a standard format.
 * @param {Array} requestedFields The fields requested in the getData request.
 * @returns {Array} Array containing rows of data in key-value pairs for each
 *     field.
 */
function getFormattedData(response, requestedFields) {
  var data = [];
  Object.keys(response).map(function(packageName) {
    var package = response[packageName];
    var downloadData = package.downloads;
    var formattedData = downloadData.map(function(dailyDownload) {
      return formatData(requestedFields, packageName, dailyDownload);
    });
    data = data.concat(formattedData);
  });
  return data;
}

تکمیل مانیفست پروژه

فایل مانیفست حاوی اطلاعاتی در مورد Community Connector شما است که برای استقرار و استفاده از Connector شما در Looker Studio مورد نیاز است.

برای ویرایش فایل مانیفست در محیط توسعه Apps Script، روی منوی View کلیک کرده و گزینه Show manifest file را انتخاب کنید. این کار یک فایل مانیفست جدید appsscript.json ایجاد می‌کند.

مانیفست را به‌روزرسانی کنید تا داده‌های زیر را شامل شود:

npm-downloads/src/appsscript.json
{
  "dependencies": {
    "libraries": []
  },
  "dataStudio": {
    "name": "npm Downloads",
    "logoUrl": "https://raw.githubusercontent.com/npm/logos/master/npm%20square/n-64.png",
    "company": "Google Data Studio Developer Relations",
    "companyUrl": "https://developers.google.com/datastudio/",
    "addonUrl": "https://github.com/googledatastudio/community-connectors/tree/master/npm-downloads#readme",
    "supportUrl": "https://github.com/googledatastudio/community-connectors/issues",
    "description": "Get npm package download counts.",
    "sources": ["npm"],
    "templates": {
      "default": "1twu0sHjqR5dELAPyGJcw4GS3-D0_NTrQ"
    }
  },
  "oauthScopes": [
    "https://www.googleapis.com/auth/script.external_request"
  ]
}

برای جزئیات بیشتر در مورد مانیفست Looker Studio، به مرجع مانیفست مراجعه کنید.

مراحل بعدی

مرحله بعدی، استقرار Community Connector شما خواهد بود.