The metadata classes and mixin

When building a frontend-framework-based or mobile application, usually the models you define on the frontend or the data you receive from your DRF backend isn't enough to be able to create forms or lists. This is where the metadata classes and mixin proided by DRF-schema-adapters comes to the rescue by providing extra information when calling the OPTIONS method on an endpoint's root.

DRF-schema-adapters provides 2 metadata classes AutoMetadata (which inherits from DRF's SimpleMetadata class) and MinimalAutoMetadata (which inherits from DRF's BaseMetadata class). Both of those classes use the AutoMetadataMixin class that you can also apply to your own metadata classes.

To use the metadata feature of DRF-schema-adapters, you'll first have to change DRF's default settings:

## settings.py

...
REST_FRAMEWORK = {
    'DEFAULT_METADATA_CLASS': 'drf_auto_endpoint.metadata.AutoMetadata',
}

Any of the two provided metadata classes (or your own metadata class using AutoMetadataMixin) will provide an output similar to this when calling OPTIONS on an endpoint:

[
    {
        "validation": {
            "required": false
        },
        "read_only": true,
        "type": "number",
        "extra": {},
        "key": "id",
        "ui": {
            "label": "Id"
        }
    },
    {
        "validation": {
            "required": true,
            "max": 255
        },
        "read_only": false,
        "type": "text",
        "extra": {},
        "key": "name",
        "ui": {
            "label": "Name",
            "placeholder": "Enter your name here"
        }
    },
    {
        "validation": {
            "required": true
        },
        "related_endpoint": "sample/category",
        "read_only": false,
        "type": "foreignkey",
        "extra": {},
        "key": "category",
        "ui": {
            "label": "Category"
        }
    },
    {
        "validation": {
            "required": false
        },
        "read_only": false,
        "type": "select",
        "extra": {},
        "choices": [
            {
                "label": "Sellable",
                "value": "s"
            },
            {
                "label": "Rentable",
                "value": "r"
            }
        ],
        "key": "product_type",
        "ui": {
            "label": "Product Type"
        }
    },
    {
        "validation": {
            "required": false
        },
        "read_only": true,
        "type": "text",
        "extra": {},
        "key": "__str__",
        "ui": {
            "label": "Product"
        }
    }
]

Any of the two provided metadata classes will provide an output similar this when calling OPTIONS on the root of the api.

{
    "endpoints": [
        "crm/companies",
        "crm/contacts",
        "crm/contactmechanisms",
        "products/categories",
        "products/products",
        "accounting/invoices",
        "accounting/invoicelines"
    ],
    "applications": [
        {
            "models": [
                {
                    "singular": "invoice",
                    "endpoint": "accounting/invoices",
                    "name": "invoices"
                }
            ],
            "name": "accounting"
        },
        {
            "models": [
                {
                    "singular": "category",
                    "endpoint": "products/categories",
                    "name": "categories"
                },
                {
                    "singular": "product",
                    "endpoint": "products/products",
                    "name": "products"
                }
            ],
            "name": "products"
        },
        {
            "models": [
                {
                    "singular": "company",
                    "endpoint": "crm/companies",
                    "name": "companies"
                },
                {
                    "singular": "contact",
                    "endpoint": "crm/contacts",
                    "name": "contacts"
                }
            ],
            "name": "crm"
        }
    ]
}

The exact output depends on the Adapter you choose to use. Currently DRF-schama-adapters supports 3 different adapters.

Adapters

BaseAdapter

The BaseAdapter produces an output usable with JSON Schema. This is the default adapter.

BaseAdapter will produce an output similar to the one above.

AngularFormlyAdapter

The AngularFormlyAdapter is destined to be used with angular-formly. To use this adapter, you'll have to enable it in your settings first.

## settings.py

...
DRF_AUTO_METADATA_ADAPTER = 'drf_auto_endpoint.adapters.AngularFormlyAdapter'

This adapter will have a slightly different output:

[
    {
        "key": "id",
        "type": "input",
        "templateOptions": {
            "type": "number",
            "required": false,
            "label": "Id"
        },
        "read_only": true
    },
    {
        "key": "name",
        "type": "input",
        "templateOptions": {
            "label": "Name",
            "type": "text",
            "placeholder": "Enter your name here",
            "required": true,
            "max": 255
        },
        "read_only": false
    },
    {
        "key": "category",
        "type": "input",
        "templateOptions": {
            "type": "foreignkey",
            "required": true,
            "label": "Category"
        },
        "read_only": false
    },
    {
        "key": "product_type",
        "type": "select",
        "templateOptions": {
            "type": "select",
            "required": false,
            "label": "Product Type"
        },
        "read_only": false
    },
    {
        "key": "__str__",
        "type": "input",
        "templateOptions": {
            "type": "text",
            "required": false,
            "label": "Product"
        },
        "read_only": true
    }
]

ReactJsonSchemaAdapter

The ReactJsonSchemaAdapter is destined to be used with react-jsonschema-form. To use this adapter, you'll have to enable it in your settings first.

## settings.py

...
DRF_AUTO_METADATA_ADAPTER = 'drf_auto_endpoint.adapters.ReactJsonSchemaAdapter'

This adapter will have an output similar to the base adapter with extra information:

{
  "fields": [
  {
            "required": false,
            "key": "id",
            "schema": {
                "title": "Id",
                "type": "number"

            },
            "ui": {
                "ui:readonly": true

            }

  },
  {
            "required": true,
            "key": "lst",
            "schema": {
                "title": "Lst",
                "type": "string"

            },
            "ui": {}

  },
  {
            "required": true,
            "key": "description",
            "schema": {
                "title": "Description",
                "type": "string"

            },
            "ui": {
                "ui:placeholder": "Add a new task"

            }

  },
  {
            "required": false,
            "key": "done",
            "schema": {
                "title": "Done",
                "type": "boolean",
                "default": false

            },
            "ui": {}

  },
  {
            "required": false,
            "key": "__str__",
            "schema": {
                "title": "Task",
                "type": "string"

            },
            "ui": {
                "ui:readonly": true

            }

  }

  ],
  "schema": {
        "type": "object",
        "properties": {
          "description": {
                "title": "Description",
                "type": "string"

          }

        },
        "required": [
            "description"

        ]

  },
  "ui": {
    "description": {
            "ui:placeholder": "Add a new task"

    },
    "ui:order": [
            "description"

    ]

  }

}

EmberAdapter

The EmberAdapter was built to use with ember-cli-crudities and ember-cli-dynamic-model.

To use the EmberAdapter you'll also have to enable it in your settings.

## settings.py

...
DRF_AUTO_METADATA_ADAPTER = 'drf_auto_endpoint.adapters.EmberAdapter'

It's output is somewhat fuller as it is intended to render a full "admin-like" application and not just single forms; it looks like this.

{
  "fields": [
  {
            "extra": {},
            "readonly": true,
            "required": false,
            "name": "id",
            "widget": "number",
            "translated": false,
            "label": "Id"

  },
  {
    "extra": {
                "placeholder": "Enter your name here"

    },
            "readonly": false,
            "required": true,
            "name": "name",
            "widget": "text",
            "translated": false,
            "label": "Name"

  },
  {
    "extra": {
                "related_model": "sample/category"

    },
            "readonly": false,
            "required": true,
            "name": "category",
            "widget": "foreignkey",
            "translated": false,
            "label": "Category"

  },
  {
    "extra": {
      "choices": [
      {
                        "value": "s",
                        "label": "Sellable"

      },
      {
                        "value": "r",
                        "label": "Rentable"

      }

      ]

    },
            "readonly": false,
            "required": false,
            "name": "product_type",
            "widget": "select",
            "translated": false,
            "label": "Product Type"

  },
  {
            "extra": {},
            "readonly": true,
            "required": false,
            "name": "__str__",
            "widget": "text",
            "translated": false,
            "label": "Product"

  }

  ],
  "list_display": [
        "__str__"

  ],
  "filter_fields": [],
  "search_enabled": false,
  "languages": [],
  "ordering_fields": [],
  "needs": [
    {
      "app": "sample",
      "singular": "category",
      "plural": "categories"

    }

  ],
  "fieldsets": [
    {
      "fields": [
        {
          "name": "name"

        },
        {
          "name": "category"

        },
        {
          "name": "product_type"

        }

      ],
      "title": null
    }
  ],
  "list_editable": [],
  "sortable_by": null,
  "translated_fields": [],
  "save_twice": false,
  "custom_actions": [],
  "bulk_actions": [],
}

Custom adapter

If none of the provided adapters fit you needs, you can also create a custom adapter