Skip to content

Commit

Permalink
Update types to align with OpenAPI
Browse files Browse the repository at this point in the history
* Use `conlist` instead of `Tuple`s:

  Due to the way pydantic converts types to JSON types, Tuples are not
  converted to OpenAPI-compliant JSON types.
  Instead, conlist can be used to limit the length of the list and still
  comply with the desired effects in the actual use of the models.

* Fields with constant values:

  These fields were not listed as required, nor was it known what the
  constant value was from the OpenAPI.
  This has been updated by adding the `pattern` attribute to Field,
  specifying the value wrapped in `^` and `$`.
  `pattern` is used instead of `regex`, because there is no need to add
  an extra validator.

  These fields mainly include `type`, but also `id`.

  Also, it seems from the pydantic documentation that the value of the
  `const` attribute of Field should be the same as the supplied
  `default` value. So this has been updated for all `const` attribute
  values.

* Warning model better represented in OpenAPI:

  The `status` property is not part of the OPTIMAD Warning model, this
  has now been removed in the OpenAPI specification.
  • Loading branch information
CasperWA committed Aug 31, 2020
1 parent 90d7d90 commit 70e8651
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 95 deletions.
19 changes: 12 additions & 7 deletions openapi/index_openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -778,17 +778,21 @@
"IndexInfoResource": {
"title": "IndexInfoResource",
"required": [
"id",
"type",
"attributes",
"relationships"
],
"type": "object",
"properties": {
"id": {
"title": "Id",
"pattern": "^/$",
"type": "string"
},
"type": {
"title": "Type",
"pattern": "^info$",
"type": "string"
},
"links": {
Expand Down Expand Up @@ -970,6 +974,7 @@
"title": "LinksResource",
"required": [
"id",
"type",
"attributes"
],
"type": "object",
Expand All @@ -981,6 +986,7 @@
},
"type": {
"title": "Type",
"pattern": "^links$",
"type": "string",
"description": "These objects are described in detail in the section Links Endpoint"
},
Expand Down Expand Up @@ -1326,7 +1332,8 @@
"RelatedLinksResource": {
"title": "RelatedLinksResource",
"required": [
"id"
"id",
"type"
],
"type": "object",
"properties": {
Expand All @@ -1337,6 +1344,7 @@
},
"type": {
"title": "Type",
"pattern": "^links$",
"type": "string"
}
},
Expand Down Expand Up @@ -1719,7 +1727,8 @@
"Warnings": {
"title": "Warnings",
"required": [
"detail"
"detail",
"type"
],
"type": "object",
"properties": {
Expand All @@ -1737,11 +1746,6 @@
],
"description": "A links object storing about"
},
"status": {
"title": "Status",
"type": "string",
"description": "the HTTP status code applicable to this problem, expressed as a string value."
},
"code": {
"title": "Code",
"type": "string",
Expand Down Expand Up @@ -1777,6 +1781,7 @@
},
"type": {
"title": "Type",
"pattern": "^warning$",
"type": "string",
"description": "Warnings must be of type \"warning\""
}
Expand Down
103 changes: 32 additions & 71 deletions openapi/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1095,16 +1095,20 @@
"BaseInfoResource": {
"title": "BaseInfoResource",
"required": [
"id",
"type",
"attributes"
],
"type": "object",
"properties": {
"id": {
"title": "Id",
"pattern": "^/$",
"type": "string"
},
"type": {
"title": "Type",
"pattern": "^info$",
"type": "string"
},
"links": {
Expand Down Expand Up @@ -1822,6 +1826,7 @@
"title": "LinksResource",
"required": [
"id",
"type",
"attributes"
],
"type": "object",
Expand All @@ -1833,6 +1838,7 @@
},
"type": {
"title": "Type",
"pattern": "^links$",
"type": "string",
"description": "These objects are described in detail in the section Links Endpoint"
},
Expand Down Expand Up @@ -2211,6 +2217,7 @@
"title": "ReferenceResource",
"required": [
"id",
"type",
"attributes"
],
"type": "object",
Expand All @@ -2222,6 +2229,7 @@
},
"type": {
"title": "Type",
"pattern": "^references$",
"type": "string",
"description": "The name of the type of an entry.\n- **Type**: string.\n- **Requirements/Conventions**:\n - **Support**: MUST be supported by all implementations, MUST NOT be `null`.\n - **Query**: MUST be a queryable property with support for all mandatory filter features.\n - **Response**: REQUIRED in the response.\n - MUST be an existing entry type.\n - The entry of type <type> and ID <id> MUST be returned in response to a request for `/<type>/<id>` under the versioned base URL.\n- **Example**: `\"structures\"`"
},
Expand Down Expand Up @@ -2930,6 +2938,7 @@
"title": "StructureResource",
"required": [
"id",
"type",
"attributes"
],
"type": "object",
Expand All @@ -2941,6 +2950,7 @@
},
"type": {
"title": "Type",
"pattern": "^structures$",
"type": "string",
"description": "The name of the type of an entry.\n\n- **Type**: string.\n\n- **Requirements/Conventions**:\n - **Support**: MUST be supported by all implementations, MUST NOT be `null`.\n - **Query**: MUST be a queryable property with support for all mandatory filter features.\n - **Response**: REQUIRED in the response.\n - MUST be an existing entry type.\n - The entry of type `<type>` and ID `<id>` MUST be returned in response to a request for `/<type>/<id>` under the versioned base URL.\n\n- **Examples**:\n - `\"structures\"`"
},
Expand Down Expand Up @@ -3050,18 +3060,12 @@
},
"dimension_types": {
"title": "Dimension Types",
"maxItems": 3,
"minItems": 3,
"type": "array",
"items": [
{
"$ref": "#/components/schemas/Periodicity"
},
{
"$ref": "#/components/schemas/Periodicity"
},
{
"$ref": "#/components/schemas/Periodicity"
}
],
"items": {
"$ref": "#/components/schemas/Periodicity"
},
"description": "List of three integers.\nFor each of the three directions indicated by the three lattice vectors (see property `lattice_vectors`), this list indicates if the direction is periodic (value `1`) or non-periodic (value `0`).\nNote: the elements in this list each refer to the direction of the corresponding entry in `lattice_vectors` and *not* the Cartesian x, y, z directions.\n\n- **Type**: list of integers.\n\n- **Requirements/Conventions**:\n - **Support**: SHOULD be supported by all implementations, i.e., SHOULD NOT be `null`.\n - **Query**: Support for queries on this property is OPTIONAL.\n - MUST be a list of length 3.\n - Each integer element MUST assume only the value 0 or 1.\n\n- **Examples**:\n - For a molecule: `[0, 0, 0]`\n - For a wire along the direction specified by the third lattice vector: `[0, 0, 1]`\n - For a 2D surface/slab, periodic on the plane defined by the first and third lattice vectors: `[1, 0, 1]`\n - For a bulk 3D system: `[1, 1, 1]`"
},
"nperiodic_dimensions": {
Expand All @@ -3071,69 +3075,29 @@
},
"lattice_vectors": {
"title": "Lattice Vectors",
"maxItems": 3,
"minItems": 3,
"type": "array",
"items": [
{
"type": "array",
"items": [
{
"type": "number"
},
{
"type": "number"
},
{
"type": "number"
}
]
},
{
"type": "array",
"items": [
{
"type": "number"
},
{
"type": "number"
},
{
"type": "number"
}
]
"items": {
"type": "array",
"items": {
"type": "number"
},
{
"type": "array",
"items": [
{
"type": "number"
},
{
"type": "number"
},
{
"type": "number"
}
]
}
],
"minItems": 3,
"maxItems": 3
},
"description": "The three lattice vectors in Cartesian coordinates, in \u00e5ngstr\u00f6m (\u00c5).\n\n- **Type**: list of list of floats or unknown values.\n\n- **Requirements/Conventions**:\n - **Support**: SHOULD be supported by all implementations, i.e., SHOULD NOT be `null`.\n - **Query**: Support for queries on this property is OPTIONAL.\n If supported, filters MAY support only a subset of comparison operators.\n - MUST be a list of three vectors *a*, *b*, and *c*, where each of the vectors MUST BE a list of the vector's coordinates along the x, y, and z Cartesian coordinates.\n (Therefore, the first index runs over the three lattice vectors and the second index runs over the x, y, z Cartesian coordinates).\n - For databases that do not define an absolute Cartesian system (e.g., only defining the length and angles between vectors), the first lattice vector SHOULD be set along *x* and the second on the *xy*-plane.\n - MUST always contain three vectors of three coordinates each, independently of the elements of property `dimension_types`.\n The vectors SHOULD by convention be chosen so the determinant of the `lattice_vectors` matrix is different from zero.\n The vectors in the non-periodic directions have no significance beyond fulfilling these requirements.\n - The coordinates of the lattice vectors of non-periodic dimensions (i.e., those dimensions for which `dimension_types` is `0`) MAY be given as a list of all `null` values.\n If a lattice vector contains the value `null`, all coordinates of that lattice vector MUST be `null`.\n\n- **Examples**:\n - `[[4.0,0.0,0.0],[0.0,4.0,0.0],[0.0,1.0,4.0]]` represents a cell, where the first vector is `(4, 0, 0)`, i.e., a vector aligned along the `x` axis of length 4 \u00c5; the second vector is `(0, 4, 0)`; and the third vector is `(0, 1, 4)`."
},
"cartesian_site_positions": {
"title": "Cartesian Site Positions",
"type": "array",
"items": {
"type": "array",
"items": [
{
"type": "number"
},
{
"type": "number"
},
{
"type": "number"
}
]
"items": {
"type": "number"
},
"minItems": 3,
"maxItems": 3
},
"description": "Cartesian positions of each site in the structure.\nA site is usually used to describe positions of atoms; what atoms can be encountered at a given site is conveyed by the `species_at_sites` property, and the species themselves are described in the `species` property.\n\n- **Type**: list of list of floats\n\n- **Requirements/Conventions**:\n - **Support**: SHOULD be supported by all implementations, i.e., SHOULD NOT be `null`.\n - **Query**: Support for queries on this property is OPTIONAL.\n If supported, filters MAY support only a subset of comparison operators.\n - It MUST be a list of length equal to the number of sites in the structure, where every element is a list of the three Cartesian coordinates of a site expressed as float values in the unit angstrom (\u00c5).\n - An entry MAY have multiple sites at the same Cartesian position (for a relevant use of this, see e.g., the property `assemblies`).\n\n- **Examples**:\n - `[[0,0,0],[0,0,2]]` indicates a structure with two sites, one sitting at the origin and one along the (positive) *z*-axis, 2 \u00c5 away from the origin."
},
Expand Down Expand Up @@ -3436,7 +3400,8 @@
"Warnings": {
"title": "Warnings",
"required": [
"detail"
"detail",
"type"
],
"type": "object",
"properties": {
Expand All @@ -3454,11 +3419,6 @@
],
"description": "A links object storing about"
},
"status": {
"title": "Status",
"type": "string",
"description": "the HTTP status code applicable to this problem, expressed as a string value."
},
"code": {
"title": "Code",
"type": "string",
Expand Down Expand Up @@ -3494,6 +3454,7 @@
},
"type": {
"title": "Type",
"pattern": "^warning$",
"type": "string",
"description": "Warnings must be of type \"warning\""
}
Expand Down
4 changes: 2 additions & 2 deletions optimade/models/baseinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,6 @@ def formats_and_endpoints_must_be_valid(cls, v, values):


class BaseInfoResource(Resource):
id: str = Field(default="/", const=True)
type: str = Field(default="info", const=True)
id: str = Field("/", const="/", pattern="^/$")
type: str = Field("info", const="info", pattern="^info$")
attributes: BaseInfoAttributes = Field(...)
4 changes: 2 additions & 2 deletions optimade/models/index_metadb.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class IndexInfoAttributes(BaseInfoAttributes):
"""Attributes for Base URL Info endpoint for an Index Meta-Database"""

is_index: bool = Field(
default=True,
True,
const=True,
description="This must be `true` since this is an index meta-database (see section Index Meta-Database).",
)
Expand All @@ -35,7 +35,7 @@ class IndexInfoAttributes(BaseInfoAttributes):
class RelatedLinksResource(BaseResource):
"""A related Links resource object"""

type: str = Field("links", const=True)
type: str = Field("links", const="links", pattern="^links$")


class IndexRelationship(BaseModel):
Expand Down
24 changes: 23 additions & 1 deletion optimade/models/jsonapi.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""This module should reproduce JSON API v1.0 https://jsonapi.org/format/1.0/"""
# pylint: disable=no-self-argument
from typing import Optional, Union, List
from typing import Optional, Union, List, Dict, Any, Type
from datetime import datetime, timezone
from pydantic import ( # pylint: disable=no-name-in-module
BaseModel,
Expand Down Expand Up @@ -135,6 +135,28 @@ class BaseResource(BaseModel):
id: str = Field(..., description="Resource ID")
type: str = Field(..., description="Resource type")

class Config:
@staticmethod
def schema_extra(schema: Dict[str, Any], model: Type["BaseResource"]) -> None:
"""Ensure `id` and `type` are the first two entries in the list required properties.
Note:
This _requires_ that `id` and `type` are the _first_ model fields defined
for all sub-models of `BaseResource`.
"""
if "id" not in schema.get("required", []):
schema["required"] = ["id"] + schema.get("required", [])
if "type" not in schema.get("required", []):
required = []
for field in schema.get("required", []):
required.append(field)
if field == "id":
# To make sure the property order match the listed properties,
# this ensures "type" is added immediately after "id".
required.append("type")
schema["required"] = required


class RelationshipLinks(BaseModel):
"""A resource object **MAY** contain references to other resource objects ("relationships").
Expand Down
3 changes: 2 additions & 1 deletion optimade/models/links.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,9 @@ class LinksResource(EntryResource):

type: str = Field(
"links",
const=True,
const="links",
description="These objects are described in detail in the section Links Endpoint",
pattern="^links$",
)

attributes: LinksResourceAttributes = Field(
Expand Down
Loading

0 comments on commit 70e8651

Please sign in to comment.