Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documented json #41

Merged
merged 4 commits into from
Jun 14, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
279 changes: 227 additions & 52 deletions optimade/server/models/jsonapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,72 +2,206 @@
This module should reproduce https://jsonapi.org/schema
"""
from typing import Optional, Set, Union, Dict, Any
from pydantic import BaseModel, UrlStr, constr
from pydantic import BaseModel, UrlStr, constr, Schema

class Meta(Dict[str, Any]):
"""Non-standard meta-information that can not be represented as an attribute or relationship."""

class Link(BaseModel):
href: UrlStr
meta: Optional[dict]
"""A link **MUST** be represented as either: a string containing the link's URL or a link object."""
href: UrlStr = Schema(
...,
description="a string containing the link’s URL."
)
meta: Optional[dict] = Schema(
...,
description="a meta object containing non-standard meta-information about the link."
)

class Links(BaseModel):
next: Optional[Union[UrlStr,Link]]
self: Optional[Union[UrlStr,Link]]
about: Optional[Union[UrlStr, Link]]
"""A Links object is a set of keys with a Link value"""
next: Optional[Union[UrlStr,Link]] = Schema(
...,
description="A Link to the next object"
)
self: Optional[Union[UrlStr,Link]] = Schema(
...,
description="A link to itself"
)
related: Optional[Union[UrlStr,Link]] = Schema(
...,
description="A related resource link"
)
about: Optional[Union[UrlStr, Link]] = Schema(
...,
description="a link that leads to further details about this particular occurrence of the problem."
)

class JsonAPI(BaseModel):
version: str
meta: Optional[dict]
"""An object describing the server's implementation"""
version: str = Schema(
...,
description="Version of the json API used"
)
meta: Optional[dict] = Schema(
...,
description="Non-standard meta information"
)

class Pagination(BaseModel):
first: Optional[UrlStr]
last: Optional[UrlStr]
prev: Optional[UrlStr]
next: Optional[UrlStr]
"""
A set of urls to different pages:
"""
first: Optional[UrlStr] = Schema(
...,
description="The first page of data"
)
last: Optional[UrlStr] = Schema(
...,
description="The last page of data"
)
prev: Optional[UrlStr] = Schema(
...,
description="The previous page of data"
)
next: Optional[UrlStr] = Schema(
...,
description="The next page of data"
)

class Source(BaseModel):
pointer: Optional[str]
parmeter: Optional[str]
"""an object containing references to the source of the error"""
pointer: Optional[str] = Schema(
...,
description="a JSON Pointer [RFC6901] to the associated entity in the request document [e.g. \"/data\" for a primary data object, or \"/data/attributes/title\" for a specific attribute]."
)
parmeter: Optional[str] = Schema(
...,
description="a string indicating which URI query parameter caused the error."
)

class Error(BaseModel):
id: Optional[str]
status: Optional[str]
code: Optional[str]
title: Optional[str]
detail: Optional[str]
source: Optional[Source]
meta: Optional[dict]
links: Optional[Links]
"""
An error response
"""
id: Optional[str] = Schema(
...,
description="A unique identifier for this particular occurrence of the problem."
)
links: Optional[Links] = Schema(
...,
description="A links object storing about"
)
status: Optional[str] = Schema(
...,
description="the HTTP status code applicable to this problem, expressed as a string value."
)
code: Optional[str] = Schema(
...,
description="an application-specific error code, expressed as a string value."
)
title: Optional[str] = Schema(
...,
description="A short, human-readable summary of the problem. It **SHOULD NOT** change from occurrence to occurrence of the problem, except for purposes of localization."
)
detail: Optional[str] = Schema(
...,
description="A human-readable explanation specific to this occurrence of the problem."
)
source: Optional[Source] = Schema(
...,
description="An object containing references to the source of the error"
)
meta: Optional[dict] = Schema(
...,
description="a meta object containing non-standard meta-information about the error."
)

class Failure(BaseModel):
errors: Set[Error]
meta: Optional[dict]
jsonapi: Optional[JsonAPI]
links: Optional[Links]
"""A failure object"""
errors: Set[Error] = Schema(
...,
description="A list of errors"
)
meta: Optional[dict] = Schema(
...,
description="a meta object containing non-standard meta-information about the failure."
)
jsonapi: Optional[JsonAPI] = Schema(
...,
description="Information about the JSON API used"
)
links: Optional[Links] = Schema(
...,
description="Links associated with the failure"
)

class Info(BaseModel):
meta: dict
jsonapi: Optional[JsonAPI]
links: Optional[Links]
"""Information dict about the API"""
meta: dict = Schema(
...,
description="a meta object containing non-standard meta-information about the failure."
)
jsonapi: Optional[JsonAPI] = Schema(
...,
description="Information about the JSON API used"
)
links: Optional[Links] = Schema(
...,
description="Links associated with the failure"
)

att_pat_prop = constr(regex=r'^(?!relationships$|links$|id$|type$)\\w[-\\w_]*$')
class Attributes(BaseModel):
items: Optional[Dict[att_pat_prop, Any]]
class Attributes(Dict[str, Any]):
"""
Members of the attributes object (\"attributes\") represent information about the resource object in which it's defined.
The keys for Attributes must NOT be:
relationships
links
id
type
"""

class RelationshipLinks(BaseModel):
self: Optional[Link]
related: Optional[Link]
"""A resource object **MAY** contain references to other resource objects (\"relationships\"). Relationships may be to-one or to-many. Relationships can be specified by including a member in a resource's links object."""
self: Optional[Link] = Schema(
...,
description="A link to itself"
)
related: Optional[Link] = Schema(
...,
description="A related resource link"
)

class Linkage(BaseModel):
type: str
id: str
meta: Optional[dict]
"""The \"type\" and \"id\" to non-empty members."""
type: str = Schema(
...,
description="The type of linkage"
)
id: str = Schema(
...,
description="The id of the linkage"
)
meta: Optional[dict] = Schema(
...,
description="The non-standard meta-information about the linkage"
)

class Relationship(BaseModel):
links: Optional[RelationshipLinks]
data: Optional[Union[Linkage, Set[Linkage]]]
meta: Optional[dict]
"""Representation references from the resource object in which it’s defined to other resource objects."""
links: Optional[RelationshipLinks] = Schema(
...,
description="a links object containing at least one of the following: self, related"
)
data: Optional[Union[Linkage, Set[Linkage]]] = Schema(
...,
description="Resource linkage"
)
meta: Optional[dict] = Schema(
...,
description="a meta object that contains non-standard meta-information about the relationship."
)

# class Empty(None):
# """Describes an empty to-one relationship."""
Expand All @@ -79,20 +213,61 @@ class RelationshipToMany(Set[Linkage]):
"""An array of objects each containing \"type\" and \"id\" members for to-many relationships."""

rel_pat_prop = constr(regex=r"^(?!id$|type$)\\w[-\\w_]*$")
class Relationships(BaseModel):
items : Optional[Dict[rel_pat_prop, Relationship]]
class Relationships(Dict[str, Any]):
"""
Members of the relationships object (\"relationships\") represent references from the resource object in which it's defined to other resource objects.
Keys MUST NOT be:
type
id
"""
# items : Optional[Dict[rel_pat_prop, Relationship]]

class Resource(BaseModel):
id: str
type: str
links: Optional[Links]
meta: Optional[dict]
attributes: Optional[Attributes]
relationships: Optional[Relationships]
"""\"Resource objects\" appear in a JSON:API document to represent resources."""
id: str = Schema(
...,
description="Resource ID"
)
type: str = Schema(
...,
description="Resource type"
)
links: Optional[Links] = Schema(
...,
description="a links object containing links related to the resource."
)
meta: Optional[dict] = Schema(
...,
description="a meta object containing non-standard meta-information about a resource that can not be represented as an attribute or relationship."
)
attributes: Optional[Attributes] = Schema(
...,
description="an attributes object representing some of the resource’s data."
)
relationships: Optional[Relationships] = Schema(
...,
description="a relationships object describing relationships between the resource and other JSON:API resources."
)

class Success(BaseModel):
data: Union[None, Resource, Set[Resource]]
included: Optional[Set[Resource]]
meta: Optional[dict]
links: Optional[Union[Links, Pagination]]
jsonapi: Optional[JsonAPI]
"""A Successful response"""
data: Union[None, Resource, Set[Resource]] = Schema(
...,
description="Outputted Data"
)
included: Optional[Set[Resource]] = Schema(
...,
description="A list of resources that are included"
)
meta: Optional[dict] = Schema(
...,
description="A meta object containing non-standard information related to the Success"
)
links: Optional[Union[Links, Pagination]] = Schema(
...,
description="Information about the JSON API used"
)
jsonapi: Optional[JsonAPI] = Schema(
...,
description="Links associated with the failure"
)
36 changes: 29 additions & 7 deletions optimade/server/models/modified_jsonapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,41 @@
"""
from optimade.server.models import jsonapi
from datetime import datetime
from pydantic import UrlStr, BaseModel
from pydantic import UrlStr, BaseModel, Schema
from typing import Optional, Union, Any

class Attributes(jsonapi.Attributes):
local_id: UrlStr
lad_modified: datetime
immutable_id: Optional[UrlStr]
"""Modification of Attributes to include Optimade specified keys"""
local_id: UrlStr = Schema(
...,
description="the entry's local database ID (having no OPTiMaDe requirements/conventions"
)
lad_modified: datetime = Schema(
...,
description="an ISO 8601 representing the entry's last modification time"
)
immutable_id: Optional[UrlStr] = Schema(
...,
description="an OPTIONAL field containing the entry's immutable ID (e.g., an UUID). This is important for databases having preferred IDs that point to \"the latest version\" of a record, but still offer access to older variants. This ID maps to the version-specific record, in case it changes in the future."
)

class ErrorLinks(BaseModel):
about: Union[jsonapi.Link, UrlStr]
"""Links with recast for Errors"""
about: Union[jsonapi.Link, UrlStr] = Schema(
...,
description="a link that leads to further details about this particular occurrence of the problem."
)

class Error(jsonapi.Error):
links: Optional[ErrorLinks]
"""Error where links uses ErrorLinks"""
links: Optional[ErrorLinks] = Schema(
...,
description="A links object containing about"
)

class Links(jsonapi.Links):
base_rul: Optional[Union[jsonapi.Link, UrlStr]]
"""Links now store base_url"""
base_url: Optional[Union[jsonapi.Link, UrlStr]] = Schema(
...,
description="The URL that serves the API."
)