Можно ли использовать шаблоны URI для соответствия URI маршрутам?

Рамки, такие как ASP.NET или Nancy, предоставляют синтаксис, который можно использовать для указания маршрутов, например:

MapRoute("/customers/{id}/invoices/{invoiceId}", ...)

В маршрутах ASP.NET работают в двух направлениях. Они могут сопоставлять URL-адрес запроса, такой как /customers/32/invoices/19, с маршрутом, и они могут разрешать параметры, такие как { id: 37, invoiceId: 19 }, в URI.

RFC 6570: шаблоны URI также определяет аналогичную, но гораздо более богатую спецификацию для URI, которые часто используются для разрешать URI. Например:

UriTemplate("/customers/{id}/invoices{/invoiceId}{?sort}", { id: 37, invoiceId: 19, sort: 'asc' } )
// returns:  /customers/37/invoices/19?sort=asc

Мой вопрос: может ли синтаксис, указанный в RFC 6570, использоваться для маршрутизации запроса соответствовать? Есть ли часть синтаксиса, которая сделает его неоднозначным для соответствия данному URI заданному шаблону URI? Существуют ли библиотеки, поддерживающие соответствие URI шаблону URI?

Ответ 1

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

Для таких вещей, как расширение сегмента пути

 {/list*}           /red/green/blue

Как бы вы узнали, какие части пути были литералами и какие части были частью параметра? В спецификации URITemplate есть довольно странное поведение, я подозреваю, что даже если это возможно, это будет довольно дорого.

Заинтересованы ли вы в этом для целей маршрутизации?

Ответ 2

Проще сказать соответствие, но в отношении разрешить вам нужно заменить часть ASP.net на RFC 6570.

К сожалению, я делаю это в node с выражением js, и это может быть не полезно, но я уверен, что что-то вроде https://github.com/geraintluff/uri-templates (для разрешения) также доступен в ASP.

Вот некоторый .js-код, который иллюстрирует переписывание гиперссылки ИСПОЛЬЗОВАНИЕ RFC 6570 для использования с express js (преимущество использования в схеме заключается в том, что вы также можете определять регулярные выражения для ваших шаблонов uri):

  var deref = require('json-schema-deref');
  var tv4 = require('tv4');
  var url = require('url');
  var rql = require('rql/parser');
  var hyperschema = {
  "$schema": "http://json-schema.org/draft-04/hyper-schema",
  "links": [
    {
      "href": "{/id}{/ooo*}{#q}",
      "method": "GET",
      "rel": "self",
      "schema": {
        "type": "object",
        "properties": {
          "params": {
            "type": "object",
            "properties": {
              "id": {"$ref": "#/definitions/id"}
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": true
      }
    }
  ],
  "definitions": {
    "id": {
      "type": "string",
      "pattern": "[a-z]{0,3}"
    }
  }
}
// DOJO lang AND _
function getDottedProperty(object, parts, create) {
    var key;
    var i = 0;

    while (object && (key = parts[i++])) {
        if (typeof object !== 'object') {
            return undefined;
        }
        object = key in object ? object[key] : (create ? object[key] = {} : undefined);
    }

    return object;
}
function getProperty(object, propertyName, create) {
    return getDottedProperty(object, propertyName.split('.'), create);
}
function _rEscape(str) {
  return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}

function getPattern(k, ldo, customCat) {
  // ...* = explode = array
  // ...: = maxLength
  var key = ((k.slice(-1) === '*') ? k.slice(0,-1) : k).split(':')[0];
  var cat = (customCat) ? customCat : 'params'; // becomes default of customCat in TS
  var pattern = '';
  if (typeof ldo === 'object' && ldo.hasOwnProperty('schema')) {
    var res = getProperty(ldo.schema, ['properties',cat,'properties',key,'pattern'].join('.'));
    if (res) {
      console.log(['properties',cat,'properties',key,'pattern'].join('.'),res);
      return ['(',res,')'].join('');
    }
  }
  return pattern;
}
function ldoToRouter(ldo) {
  var expression = ldo.href.replace(/(\{\+)/g, '{') // encoding
    .replace(/(\{\?.*\})/g, '') // query
    .replace(/\{[#]([^}]*)\}/g, function(_, arg) {
      // crosshatch
      //console.log(arg);
      return ['(?:[/]*)?#:',arg,getPattern(arg,ldo,'anchor')].join('');
    })
    .replace(/\{([./])?([^}]*)\}/g, function(_, op, arg) {
      // path seperator
      //console.log(op, '::', arg, '::', ldo.schema);
      return [op,':',arg,getPattern(arg,ldo)].join('');
    });
    return {method: ldo.method.toLowerCase(), args:[expression]};
}

deref(hyperschema, function(err, fullSchema) {
  console.log('deref hyperschema:',JSON.stringify(fullSchema));
  var router = fullSchema.links.map(ldoToRouter);

  console.log('router:',JSON.stringify(router));
});