Skip to content

Commit

Permalink
Simplify law response type
Browse files Browse the repository at this point in the history
  • Loading branch information
nfelger committed Oct 15, 2020
1 parent 16477a8 commit 4623eda
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 58 deletions.
12 changes: 7 additions & 5 deletions rip_api/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class ListLawsIncludeOptions(Enum):
tags=["Laws"],
summary="List all laws",
response_model=api_schemas.LawsResponse,
response_model_exclude_unset=True,
)
def list_laws(
include: Optional[ListLawsIncludeOptions] = None,
Expand Down Expand Up @@ -117,6 +118,7 @@ class GetLawIncludeOptions(Enum):
tags=["Laws"],
summary="Get a single law",
response_model=api_schemas.LawResponse,
response_model_exclude_unset=True,
)
def get_law(
slug: str = Path(..., description="URL-safe lowercased abbreviation of the law."),
Expand Down Expand Up @@ -162,18 +164,18 @@ def get_law(
parent['children'].append(item)
```
"""
schema_class = api_schemas.LawAllFields
if include == GetLawIncludeOptions.contents:
schema_class = api_schemas.LawAllFieldsWithContents

with db.session_scope() as session:
law = db.find_law_by_slug(session, slug)
if not law:
raise ApiException(
status_code=404, title="Resource not found", detail="Could not find a law for this slug."
)

return {"data": schema_class.from_orm_model(law)}
law_data = api_schemas.LawAllFields.from_orm_model(
law,
include_contents=(include == GetLawIncludeOptions.contents)
)
return api_schemas.LawResponse(data=law_data)


@v1.get(
Expand Down
100 changes: 50 additions & 50 deletions rip_api/api_schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class ContentItemBasicFields(BaseModel):
def _attrs_dict_from_item(cls, item):
return {
"id": item.doknr,
"type": humps.camelize(item.item_type),
"url": urls.get_article(item.law.slug, item.doknr),
"name": item.name,
"title": item.title,
Expand Down Expand Up @@ -101,6 +102,7 @@ class LawBasicFields(BaseModel):
def _attrs_dict_from_law(cls, law):
return dict(
id=law.doknr,
type="law",
url=urls.get_law(law.slug),
abbreviation=law.abbreviation,
slug=law.slug,
Expand All @@ -115,48 +117,6 @@ def from_orm_model(cls, law):
return cls(**cls._attrs_dict_from_law(law))


class LawAllFields(LawBasicFields):
extraAbbreviations: List[str]
publicationInfo: List[create_model(
'PublicationInfoItem', # noqa
reference=(str, ...),
periodical=(str, ...)
)]
statusInfo: List[create_model(
'StatusInfoItem', # noqa
comment=(str, ...),
category=(str, ...)
)]
notes: create_model(
'TextContent', # noqa
body=(Optional[str], ...),
footnotes=(Optional[str], ...),
documentaryFootnotes=(Optional[str], ...)
)
attachments: dict

@classmethod
def _attrs_dict_from_law(cls, law):
attrs = super()._attrs_dict_from_law(law)

attrs["extraAbbreviations"] = law.extra_abbreviations
attrs["publicationInfo"] = law.publication_info
attrs["statusInfo"] = law.status_info

attrs["notes"] = {
"body": law.notes_body,
"footnotes": law.notes_footnotes,
"documentaryFootnotes": law.notes_documentary_footnotes
}

attrs["attachments"] = {
name: f"{PUBLIC_ASSET_ROOT}/gesetze_im_internet/{law.gii_slug}/{name}"
for name in law.attachment_names
}

return attrs


class ContentItemBasicFieldsWithLaw(ContentItemBasicFields):
law: LawBasicFields

Expand Down Expand Up @@ -212,21 +172,59 @@ class HeadingArticleAllFields(ContentItemWithBodyAndFootnotes):
type: str = "headingArticle"


class LawAllFieldsWithContents(LawAllFields):
# Ordering in the Union matters, cf. LawResponse.
contents: List[Union[ArticleAllFields, HeadingAllFields, HeadingArticleAllFields]]
class LawAllFields(LawBasicFields):
extraAbbreviations: List[str]
publicationInfo: List[create_model(
'PublicationInfoItem', # noqa
reference=(str, ...),
periodical=(str, ...)
)]
statusInfo: List[create_model(
'StatusInfoItem', # noqa
comment=(str, ...),
category=(str, ...)
)]
notes: create_model(
'TextContent', # noqa
body=(Optional[str], ...),
footnotes=(Optional[str], ...),
documentaryFootnotes=(Optional[str], ...)
)
attachments: dict
# Order in the Union matters: FastAPI tries one after the other and only skips types if there's a validation error.
contents: Optional[List[Union[ArticleAllFields, HeadingAllFields, HeadingArticleAllFields]]]

@classmethod
def _attrs_dict_from_law(cls, law):
def _attrs_dict_from_law(cls, law, include_contents=False):
attrs = super()._attrs_dict_from_law(law)
attrs["contents"] = [ContentItemAllFields.from_orm_model(ci) for ci in law.contents]

attrs["extraAbbreviations"] = law.extra_abbreviations
attrs["publicationInfo"] = law.publication_info
attrs["statusInfo"] = law.status_info

attrs["notes"] = {
"body": law.notes_body,
"footnotes": law.notes_footnotes,
"documentaryFootnotes": law.notes_documentary_footnotes
}

attrs["attachments"] = {
name: f"{PUBLIC_ASSET_ROOT}/gesetze_im_internet/{law.gii_slug}/{name}"
for name in law.attachment_names
}

if include_contents:
attrs["contents"] = [ContentItemAllFields.from_orm_model(ci) for ci in law.contents]

return attrs

@classmethod
def from_orm_model(cls, law, include_contents=False):
return cls(**cls._attrs_dict_from_law(law, include_contents=include_contents))


class LawResponse(BaseModel):
# LawWithContents must come first in the Union: FastAPI tries them in order and only skips
# types if there's a validation error.
data: Union[LawAllFieldsWithContents, LawAllFields]
data: LawAllFields

@classmethod
def from_orm_model(cls, law):
Expand All @@ -251,10 +249,12 @@ class LawsResponse(BaseModel):


class ContentItemResponse(BaseModel):
# Order in the Union matters: FastAPI tries one after the other and only skips types if there's a validation error.
data: Union[LawAllFields, ArticleAllFields, HeadingArticleAllFields]


class SearchResultsResponse(BaseModel):
# Order in the Union matters: FastAPI tries one after the other and only skips types if there's a validation error.
data: List[Union[
LawBasicFields,
ArticleBasicFieldsWithLaw, ArticleBasicFields,
Expand Down
4 changes: 2 additions & 2 deletions rip_api/gesetze_im_internet/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ def write_all_law_json_files(session, dir_path):
all_laws = []

for law in db.all_laws(session):
law_api_model = api_schemas.LawAllFieldsWithContents.from_orm_model(law)
law_api_model = api_schemas.LawAllFields.from_orm_model(law, include_contents=True)
single_law_response = api_schemas.LawResponse(data=law_api_model)
_write_file(f"{laws_path}/{law.slug}.json", single_law_response.json(indent=2))

Expand All @@ -165,7 +165,7 @@ def write_all_law_json_files(session, dir_path):

def write_law_json_file(session, law, dir_path):
filepath = f"{dir_path}/{law.slug}.json"
law_schema = api_schemas.LawAllFieldsWithContents.from_orm_model(law)
law_schema = api_schemas.LawAllFields.from_orm_model(law, include_contents=True)
response = api_schemas.LawResponse(data=law_schema)
_write_file(filepath, response.json(indent=2))

Expand Down
2 changes: 1 addition & 1 deletion tests/test_json_generation_e2e.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def test_examples(slug):

with db.session_scope() as session:
law = db.find_law_by_slug(session, slug)
parsed = json.loads(api_schemas.LawAllFieldsWithContents.from_orm_model(law).json(indent=2))
parsed = json.loads(api_schemas.LawAllFields.from_orm_model(law, include_contents=True).json(indent=2))

expected = load_example_json(slug)["data"]
assert parsed == expected

0 comments on commit 4623eda

Please sign in to comment.