-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1650 from weather-gov/jt/json-api
JSON:API
- Loading branch information
Showing
27 changed files
with
980 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
#!/usr/bin/env python | ||
|
||
import requests # https://pypi.org/project/requests/ | ||
import subprocess | ||
import base64 | ||
import os | ||
import sys | ||
|
||
# This is a sample python script to demonstrate how to upload a WFO daily | ||
# situation report, which is produced as a PDF. This script is for educational | ||
# purposes only and is intended to aid as a helper for integration. | ||
|
||
# configuration options | ||
endpoint = 'http://localhost:8080' | ||
user = 'uploader' | ||
password = 'uploader' | ||
pdf_filename = 'test.pdf' | ||
|
||
# if we don't have one already, create a pdf for uploading; requires magick | ||
if not os.path.exists(pdf_filename): | ||
_ = subprocess.run(['magick', 'xc:none', '-page', 'Letter', pdf_filename]) | ||
|
||
pdf_data = open(pdf_filename, 'rb').read() | ||
|
||
# first step: upload the pdf file | ||
headers = { | ||
'Accept': 'application/vnd.api+json', | ||
'Content-Type': 'application/octet-stream', | ||
'Content-Disposition': f'file; filename="{pdf_filename}"', | ||
} | ||
resp = requests.post(f'{endpoint}/jsonapi/node/wfo_pdf_upload/field_wfo_sitrep', | ||
data=pdf_data, | ||
headers=headers, | ||
auth=(user, password)) | ||
if resp.status_code != 201: | ||
print(f'could not upload pdf: {resp.text}') | ||
sys.exit(1) | ||
print(f'successfully uploaded pdf: {resp.json()}') | ||
|
||
# second step: grab the ID of the file we just uploaded | ||
uploaded_file_id = resp.json()['data']['id'] | ||
|
||
# last step: create the wfo_pdf_upload type | ||
payload = { | ||
'data': { | ||
'type': 'node--wfo_pdf_upload', | ||
'attributes': { | ||
'title': pdf_filename, | ||
}, | ||
'relationships': { | ||
'field_wfo_sitrep': { | ||
'data': { | ||
'type': 'file--file', | ||
'id': uploaded_file_id, | ||
} | ||
} | ||
} | ||
} | ||
} | ||
headers = { | ||
'Accept': 'application/vnd.api+json', | ||
'Content-Type': 'application/vnd.api+json', | ||
} | ||
resp = requests.post(f'{endpoint}/jsonapi/node/wfo_pdf_upload', json=payload, headers=headers, auth=(user, password)) | ||
if resp.status_code != 201: | ||
print(f'could not finish wfo pdf upload: {resp.text}') | ||
sys.exit(1) | ||
|
||
print(f'created a new WFO daily situation report: {resp.json()}') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
# JSON:API | ||
|
||
## Modules | ||
|
||
We have enabled and configured the core Drupal [`jsonapi`](https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/api-overview) module specifically to allow uploading of WFO daily situation reports, which are produced as PDFs. | ||
|
||
We are also enabling the following core Drupal modules: | ||
|
||
- [`basic_auth`](https://www.drupal.org/docs/8/core/modules/basic_auth/overview) for authentication | ||
- [`jsonapi_extras`](https://www.drupal.org/project/jsonapi_extras) by default, prevent resources (and resource fields) from being accessible via the API | ||
- `jsonapi_defaults` is a submodule of the above which adds defaults to API resource types | ||
- [`serialization`](https://www.drupal.org/docs/8/core/modules/serialization/overview) for JSON support | ||
|
||
## Configuration | ||
|
||
A new content type, `wfo_pdf_upload` was created for WFO daily situation reports. The `field_wfo_sitrep` field holds the PDF file. | ||
|
||
We have configured JSON:API to only display `wfo_pdf_upload`s and `file`s. (The latter is needed because we need to upload the PDF and then link the PDF to the `wfo_pdf_upload`.) Furthermore, `wfo_pdf_upload` is configured to only allow the `title` and `field_wfo_sitrep` fields to be shown or set. `file` is configured to only allow the `uri` field to be shown. | ||
|
||
We have also configured a new user type, `uploader`, which has no permissions except to create new `wfo_pdf_upload`s. | ||
|
||
Because JSON:API follows Drupal entity permissions, JSON:API also respects the user permissions for that entity type. This permission system is not sufficient in and of itself (for example, `anonymous` users could browse the JSON API, including viewing `file`s and `wfo_pdf_upload`s, because `anonymous` users can `view published content`.). So, to further restrict access, we have added a `JsonApiLimitingRouteSubscriber` that mandates an `uploader` role for the API. All other users will get a `403` response. | ||
|
||
# Example | ||
|
||
Uploading a WFO sitrep is a two step process. Here, we use `curl` as an example. We also assume an `uploader` user type is used with the password `uploader` (please do not create this example user for any public site). | ||
|
||
First, we upload the PDF itself to the `wfo_pdf_upload/field_wfo_sitrep` field (note: you can create a blank PDF by using [`imagemagick`](https://imagemagick.org/index.php): `magick xc:none -page Letter test.pdf`): | ||
|
||
curl -sL \ | ||
--user uploader:uploader \ | ||
-H 'Accept: application/vnd.api+json' \ | ||
-H 'Content-Type: application/octet-stream' \ | ||
-H 'Content-Disposition: file; filename="test.pdf"' \ | ||
-d @test.pdf \ | ||
http://localhost:8080/jsonapi/node/wfo_pdf_upload/field_wfo_sitrep | ||
|
||
The response should be a 201 with JSON information about the newly uploaded file attributes. We want the `id` of the newly uploaded file for the next step. (You can use `jq` and add a pipe: `| jq "data.id"` above to more easily retrieve the resulting `id`.) | ||
|
||
Let's assume the newly created PDF `id` is `9986844e-c190-428a-b152-7c3a03244b71`. | ||
|
||
Second, we create the `wfo_pdf_upload` entity itself and link the PDF `id`: | ||
|
||
curl -sL \ | ||
--user uploader:uploader \ | ||
-H 'Accept: application/vnd.api+json' \ | ||
-H 'Content-Type: application/vnd.api+json' \ | ||
-d '{"data": { | ||
"type": "node--wfo_pdf_upload", | ||
"attributes": { | ||
"title": "test.pdf" | ||
}, | ||
"relationships": { | ||
"field_wfo_sitrep": { | ||
"data": { | ||
"type": "file--file", | ||
"id": "9986844e-c190-428a-b152-7c3a03244b71" | ||
} | ||
} | ||
} | ||
} | ||
}' \ | ||
http://localhost:8080/jsonapi/node/wfo_pdf_upload | ||
|
||
The response should also be a 201 with JSON information about the newly created `wfo_pdf_upload` entity. | ||
|
||
# Integration Example | ||
|
||
A sample [Python script](../json-api-upload-example.py) is provided to help to aid in integration. Note that this script depends on the [requests](https://pypi.org/project/requests/) library. |
9 changes: 9 additions & 0 deletions
9
web/config/sync/auto_entitylabel.settings.node.wfo_pdf_upload.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
status: 0 | ||
pattern: '' | ||
escape: false | ||
preserve_titles: false | ||
save: false | ||
chunk: 50 | ||
dependencies: | ||
config: | ||
- node.type.wfo_pdf_upload |
22 changes: 22 additions & 0 deletions
22
web/config/sync/core.base_field_override.node.wfo_pdf_upload.promote.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
uuid: 6431aada-45e3-41ed-a433-2099e55ce421 | ||
langcode: en | ||
status: true | ||
dependencies: | ||
config: | ||
- node.type.wfo_pdf_upload | ||
id: node.wfo_pdf_upload.promote | ||
field_name: promote | ||
entity_type: node | ||
bundle: wfo_pdf_upload | ||
label: 'Promoted to front page' | ||
description: '' | ||
required: false | ||
translatable: true | ||
default_value: | ||
- | ||
value: 0 | ||
default_value_callback: '' | ||
settings: | ||
on_label: 'On' | ||
off_label: 'Off' | ||
field_type: boolean |
Oops, something went wrong.