americanas-tech / restQL-golang

Microservice query language and platform
http://restql.b2w.io/
MIT License
17 stars 8 forks source link

RFC: Administrative API #33

Closed caiorcferreira closed 3 years ago

caiorcferreira commented 4 years ago

Administrative API

Status Proposed
PR # TBD
Author(s) Caio Ferreira
Updated 2021-02-05

Motivation

Currently, restQL can read mappings and queries from a database using a plugin, however, it relies on directed manipulation of the database by a user or through the restQL-manager, which also access the database directly.

Furthermore, the plugin system allows easy support for other databases than MongoDB, however, in the actual architecture it would need the restQL-manager to also be updated to connected and manipulate this new database.

These reasons are the base for this proposal to add an administrative API to restQL which will allow basic CRUD operations on tenants, mappings, and queries.

Design Proposal

This design focus on providing a unified interface to manipulate dynamic configuration in restQL. This interface should be disabled by default and switched based on a configuration entry on the YAML file and/or an environment variable.

Database plugin

Currently, the only supported way to use dynamic configuration with restQL is through the database plugin which allows it to retrieve mappings and queries from an external store.

Hence the database plugin interface will be extended to support writing and more reading operations. The following code is a draft of the new interface:


type Plugin interface {
    Name() string
}

// DatabasePlugin is the interface that defines
// the obligatory operations needed from a database.
type DatabasePlugin interface {
    Plugin

  // Already exposed methods
  FindMappingsForTenant(ctx context.Context, tenantID string) ([]Mapping, error)
  FindQuery(ctx context.Context, namespace string, name string, revision int) (SavedQuery, error)

  // New methods
  FindAllTenants(ctx context.Context) ([]string, error)
  FindAllNamespaces(ctx context.Context) ([]string, error)
  FindQueriesForNamespace(ctx context.Context, namespace string) (map[string][]SavedQuery, error)
  FindQueryWithAllRevisions(ctx context.Context, namespace string, queryName string) ([]SavedQuery, error)

  CreateQueryRevision(ctx context.Context, namespace string, queryName string, content string) error
  SetMapping(ctx context.Context, tenantID string, mappingsName string, url string) error

}

REST endpoints

The above operations on the database plugin will support the API interface described below. It follows basic REST patterns for exposing tenants, mappings, and queries as resources.

All the endpoints described would be placed under /admin/ endpoint, i.e. GET /tenant means GET /admin/tenant.

GET /tenant

List all tenants available

Return:

{
  "tenants": [
    "dc",
    "marvel",
    "vertigo"
  ]
}

GET /tenant/:name/mapping

List mappings of name to URL under the given tenant :tenant.

Return:

{
  "tenant": "marvel",
  "mappings": {
    "hero": "http://marvel.api/hero/:id",
    "heroes": "http://marvel.api/hero/",
    "weapons": "http://marvel.api/weapons"
  }
}

POST /tenant/:name/mapping/:name

Update the URL associated with the mapping :name under the tenant :tenant

Body:

{ 
  "url": "http://some.api/resource/:id",
}

GET /namespace

List all query namespaces available

Return:

{
  "namespaces": [
    "cardgame",
    "moba"
  ]
}

GET /namespace/:namespace/query

List all queries under the given :namespace

Return:

{
  "namespace": "cardgame",
  "queries": [
    {
      "name": "my-query",
      "revisions": [
          { "text": "from hero" },
          { "text": "from hero as h" }
      ]
    }
  ]
}

GET /namespace/:namespace/query/:name

Fetch all query revisions of the :query under the namespace :namespace

Return:

{
  "namespace": "my-namespace",
  "name": "my-query",
  "revisions": [
      { "text": "from hero" },
      { "text": "from hero as h" }
  ]
}

GET /namespace/:namespace/query/:name/revision/:revision

Fetch query revision :revision of the :query under the namespace :namespace

Return:

{
  "namespace": "my-namespace",
  "name": "my-query",
  "revision": { 
    "text": "from hero" 
  }
}

POST /namespace/:namespace/query/:name

Create a new revision of query :query under namespace :namespace. If the query does not exist, create it.

Body:

{
  "text": "from hero as h" 
}

Questions and Discussion Topics

This proposal focus on dynamic configuration however some questions can extend this design:

  1. Should restQL return tenants, mappings, and queries provided via the YAML configuration file on reading operations?

  2. Should restQL support writing operation on the tenants, mappings, and queries provided via the YAML configuration file?

  3. Should restQL return tenants, mappings, and queries provided via environment variables on reading operations?

  4. Should restQL support writing operation on the tenants, mappings, and queries provided via environment variables?

Supporting any of theses configuration sources would add some new points like:

Suggestions and comments are welcome!

Edit

cupello commented 3 years ago

Nice! I think it is really good!

Questions and Discussion Topic:

1,3 -> Yes, I believe that restQL should return tenants, mappings, and queries provided via the YAML configuration file or environment on reading operations.

2,4 -> No, I think restQL should NOT support writing operations on the tenants, mappings, and queries provided via the YAML configuration file or environment. IMHO it will introduce unnecessary complexity.

If only showing these resources on reading operations, any attempt to write to a resource which source is the configuration file or an environment variable should return an error. Yes, I think this is a good way to handle it.

The endpoints should provide a filter by configuration source, allowing the client to only fetch resources from the database, for example. Such would help when debugging production.

caiorcferreira commented 3 years ago

Thanks for the feedback!

I think this settle the design draft, I will work on this features and any design change introduced during implementation will be updated here.

caiorcferreira commented 3 years ago

Draft updated with changes made during implementation.