Git Product home page Git Product logo

purl-workers's People

Contributors

jyhi avatar

Stargazers

 avatar  avatar

Watchers

 avatar

purl-workers's Issues

Add CI Workflows

Just make people fell better :) Formatting, linting, any other checks that I run locally.

Template

A template stored in a value will be rendered and returned based on the option set in the metadata object:

  1. An HTTP request is initiated upon a request to a template entry
  2. The returned JSON is used to substitute the template stored in the value
  3. The rendered template is returned

The metadata object should support some new options:

{
  "render": true,
  "fetch": "http://api.example.com"
}

Management

This enables direct KV database management (create, read, update, delete) on purl-workers, without wrangler. This requires a configuration to be stored in the database. Because all keys without a / prefix cannot be directly accessed, a special key-value can be utilized to achieve this; for example, _config:

{
  "admins": {
    "root": "toor",
    "beep": "boop"
  }
}

However, this will always introduce a second read operation on KV upon request. This feature thus should be configurable in compile time. Can use secrets.

Header Requirements

This gives an option for keeping some values secret. Both the entry object and the metadata object can use the following to enable basic authentication on a value:

{
  "auth": [
    "Basic Zm9vQGJhcg==",
    "Basic YmF6QHphYg=="
  ]
}

Update: Now it's not only authorization but also any header requirements.

Content Negotiation

Allow diverting into different responses upon different Accept MIME types. Basically this is like multi-aliases based on what the client accepts, so modifying what "is" accepts in the entry object is a good choice. The implementation can further support arbitrary header matching with RegEx.

{
  "is": {
    "accept": {
      "text/html": "/foo.html",
      "application/json": "/foo.json",
      "image/jpeg": "/foo.jpg"
    },
    "user-agent": {
      "MicroMsg": "/link-mm",
      "Safari": "/link-aapl"
    }
  }
}

Conditions

Allow a user to write a predicate to perform if-then-else branching, in an entry object or in a metadata object.

{
  "if": []
  "then": {},
  "else": {}
}

Where:

  • "if" is followed by a predicate (see below).
  • "then" is followed by an entry object or a string of an entry key in the KV database.
  • "else" is followed by an entry object or a string of an entry key in the KV database.
type Expression = (string | Expression)[];

interface Entry {
  if: Expression,
  then: Entry | string,
  else: Entry | string,
  // ... omitted
}

All of the three keys are optional:

  • If none of them is present, then no branching will occur.
  • If only "if" is present, then when the predicate evaluates to true, the current entry object will be parsed and presented. Otherwise, a HTTP 403 Forbidden will be returned.
  • If only "if" and "then" are present, then when the predicate evaluates to true, "then" branch will be taken. Otherwise, the current entry object will be parsed and presented.
  • If only "if" and "else" are present, then when the predicate evaluates to true, the current entry object will be parsed and presented. Otherwise, the "else" branch will be taken.
  • If all of them are present, then when the predicate evaluates to true, "then" branch will be taken. Otherwise, "else" branch will be taken.

If "then" and "else" are followed by entry objects, then the entry objects will be parsed and run. If they are followed by strings instead, then the string will be used as a key to get an entry in the KV database. This is a shorthand of writing an alias using "is":

{
  "if": ["header", "api-version", "^1$"],
  "then": "/test/if/v1"
}
{
  "if": ["header", "api-version", "^1$"],
  "then": {
    "is": "/test/if/v1"
  }
}

Other combinations, e.g. only "then", only "else", are invalid and will be ignored.

Examples

  • Redirect only when the client says it accepts "text/html":
{
  "if": ["header", "accept", "text/html"],
  "then": {
    "status": 307,
    "statusText": "Temporary Redirect",
    "location": "/test/if.html"
  },
  "else": {
    "status": 404,
    "statusText": "Not Found"
  }
}

Predicate

The design of predicate is inspired by S-expression; one can say it's just S-expressions written in JSON. This is for allowing complex conditions being specified, while keeping the structure of JSON (for example, if we choose a full-fledged DSL, then we need to quote it fully in a JSON string, which doesn't look good). In fact, it's a domain-specific, restricted Lisp dialect.

An example:

["all", ["any", ["header", "accept", "^application/json"],
                ["query", "t", "j"],
                ["query", "type", "json"],
                ["header", "accept", "\\*/\\*"]],
        ["any", ["header", "api-version"],
                ["header", "x-api-version", "^v.+"]]]

The above is conceptually equivalent to this Lisp code:

(all (any (header "accept" "^application/json")
          (query "t" "j")
          (query "type" "json")
          (header "accept" "\\*/\\*"))
     (any (header "api-version")
          (header "x-api-version" "^v.+")))

An expression is enclosed with a JSON array, in which the first element must be a JSON string specifying a function. The following is a list of planned functions:

  • all: true if all its arguments are true.
  • any: true if one of its arguments is true.
  • not: true if its (only) argument is false.
  • header: check whether the incoming request contains the header key and matches the header value (if specified) in regular expression.
  • query: check whether the incoming request contains the query parameter key and matches the query parameter value (if specified) in regular expression.
  • auth: check whether an authentication requirement is satisfied.

None of all, any, or not returns a boolean value by itself, so other functions (e.g. header, query) must stay in the deepest level. Complex logic can then be specified by combining all, any, and not, which correspond to logical all (&&), logical or (||), and logical not (!).

Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp. -- Greenspun's tenth rule

Caching

This turns purl-workers into a proxy to a single resource. Upon a request to a caching key, the value is first retrieved from the specified URL (upstream), then stored in the value for TTL amount of time, after which the value will be re-fetched from the upstream. This should be a configuration in the metadata object, as the value needs to be rewritten from time to time.

{
  "cacheUrl": "http://http.cat/200",
  "cacheTtl": 86400,
  "cacheTime": "2021-12-31T00:00:00Z"
}

There could also be support for expunging the cache and forcefully refresh it, either via ?refresh=1 or Purl-Workers-Cache-Refresh: 1.

Namespacing

It's possible to use a single KV database to support different hosts which cannot access each others' entries - just match the host name too. It's also possible to match the schema:

  • https://foo.example.com/link: http://foo.com
  • http://bar.example.com/link: https://foo.example.com/link

/link is returned to all host names / schema then.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.