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

feat: add code examples #11

Merged
merged 1 commit into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
21 changes: 17 additions & 4 deletions deforestation_api/__main__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import pathlib
from contextlib import asynccontextmanager
import logging

from fastapi import FastAPI

from fastapi.openapi.docs import get_redoc_html
from deforestation_api.openapi import openapi
from deforestation_api.dependencies.deforestationdata import (
fetch_deforestation_data,
deforestation_data_fetcher,
Expand All @@ -21,17 +23,28 @@ async def lifespan(deforestation_app: FastAPI):


app = FastAPI(
title="Deforestation API",
lifespan=lifespan,
version=settings.version,
root_path=settings.api_root_path,
description=settings.api_description,
redoc_url=None,
)
app.include_router(deforestation.router)
app.include_router(healthcheck.router)

logging.basicConfig(level=logging.INFO)

example_code_dir = pathlib.Path(__file__).parent / "example_code"
app.openapi_schema = openapi.custom_openapi(app, example_code_dir)


@app.get("/redoc", include_in_schema=False)
def redoc():
return get_redoc_html(
openapi_url="/openapi.json",
title="Deforestation API",
redoc_favicon_url="https://www.openepi.io/favicon.ico",
)


if __name__ == "__main__":
import uvicorn

Expand Down
1 change: 1 addition & 0 deletions deforestation_api/example_code/curl/liveness.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
curl -i -X GET $endpoint_url
6 changes: 6 additions & 0 deletions deforestation_api/example_code/curl/lossyear.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Get yearly forest cover loss for the river basin at the given point
curl -i -X GET $endpoint_url?lon=30.0619&lat=-1.9441

# Get yearly forest cover loss for all river basins within the given bounding box
curl -i -X GET $endpoint_url?min_lon=28.850951&min_lat=30.909622&max_lon=-2.840114&max_lat=-1.041395

1 change: 1 addition & 0 deletions deforestation_api/example_code/curl/ready.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
curl -i -X GET $endpoint_url
7 changes: 7 additions & 0 deletions deforestation_api/example_code/javascript/liveness.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const response = await fetch(
"$endpoint_url"
);
const json = await response.json();
const message = json.message;

console.log(`Message: ${message}`);
26 changes: 26 additions & 0 deletions deforestation_api/example_code/javascript/lossyear.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Get yearly forest cover loss for the river basin at the given point
const response_point = await fetch(
"$endpoint_url?" + new URLSearchParams({
lat: -1.9441,
lon: 30.0619
})
);
const data_point = await response_point.json();

// Print the total forest cover loss within the returned river basin
console.log(data_point.features[0].properties.daterange_tot_treeloss);


// Get yearly forest cover loss for all river basins within the given bounding box
const response_bbox = await fetch(
"$endpoint_url?" + new URLSearchParams({
min_lon: 28.850951,
min_lat: -2.840114,
max_lon: 30.909622,
max_lat: -1.041395
})
);
const data_bbox = await response_bbox.json();

// Print the total forest cover loss within the first returned river basin
console.log(data_bbox.features[0].properties.daterange_tot_treeloss);
7 changes: 7 additions & 0 deletions deforestation_api/example_code/javascript/ready.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const response = await fetch(
"$endpoint_url"
);
const json = await response.json();
const status = json.status;

console.log(`Status: ${status}`);
5 changes: 5 additions & 0 deletions deforestation_api/example_code/python/liveness.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from httpx import Client

with Client() as client:
response = client.get(url="$endpoint_url")
print(response.json()["message"])
29 changes: 29 additions & 0 deletions deforestation_api/example_code/python/lossyear.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from httpx import Client

with Client() as client:
# Get yearly forest cover loss for the river basin at the given point
response_point = client.get(
url="$endpoint_url",
params={"lon": 30.0619, "lat": -1.9441},
)

data_point = response_point.json()

# Print the total forest cover loss within the returned river basin
print(data_point["features"][0]["properties"]["daterange_tot_treeloss"])

# Get yearly forest cover loss for all river basins within the given bounding box
response_bbox = client.get(
url="$endpoint_url",
params={
"min_lon": 28.850951,
"min_lat": -2.840114,
"max_lon": 30.909622,
"max_lat": -1.041395,
},
)

data_bbox = response_bbox.json()

# Print the total forest cover loss within the first returned river basin
print(data_bbox["features"][0]["properties"]["daterange_tot_treeloss"])
5 changes: 5 additions & 0 deletions deforestation_api/example_code/python/ready.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from httpx import Client

with Client() as client:
response = client.get(url="$endpoint_url")
print(response.json()["status"])
Empty file.
62 changes: 62 additions & 0 deletions deforestation_api/openapi/openapi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import logging
import os
from pathlib import Path
from string import Template

from fastapi import FastAPI
from fastapi.openapi.utils import get_openapi
from fastapi.routing import APIRoute

from deforestation_api.settings import settings

supported_languages = {"cURL": "sh", "JavaScript": "js", "Python": "py"}


def custom_openapi(app: FastAPI, example_code_dir: Path):
if app.openapi_schema:
return app.openapi_schema

openapi_schema = get_openapi(
title="Deforestation API",
version=settings.version,
description=settings.api_description,
routes=app.routes,
)

openapi_schema["info"]["x-logo"] = {
"url": f"https://{settings.api_domain}/assets/icons/open-epi-logo.svg"
}

routes_that_need_doc = [
route for route in app.routes if isinstance(route, APIRoute)
]
for route in routes_that_need_doc:
code_samples = []
for lang in supported_languages:
file_with_code_sample = (
example_code_dir
/ lang.lower()
/ f"{route.name}.{supported_languages[lang]}"
)
if os.path.isfile(file_with_code_sample):
with open(file_with_code_sample) as f:
code_template = Template(f.read())
code_samples.append(
{
"lang": lang,
"source": code_template.safe_substitute(
endpoint_url=f"{settings.api_url}{route.path}",
),
}
)
else:
logging.warning(
"No code sample found for route %s and language %s",
route.path,
lang,
)

if code_samples:
openapi_schema["paths"][route.path]["get"]["x-codeSamples"] = code_samples

return openapi_schema
9 changes: 9 additions & 0 deletions deforestation_api/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,14 @@ class Settings(BaseSettings):
api_root_path: str = "/"
api_description: str = 'This is a RESTful service that provides aggregated deforestation data over the period from 2001 to 2022 based on data provided by <a href="https://glad.umd.edu/">Global Land Analysis and Discovery (GLAD)</a> laboratory at the University of Maryland, in partnership with <a href="https://www.globalforestwatch.org/">Global Forest Watch (GFW)</a>. The data are freely available for use under a <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br/><i>Citation: Hansen, M. C., P. V. Potapov, R. Moore, M. Hancher, S. A. Turubanova, A. Tyukavina, D. Thau, S. V. Stehman, S. J. Goetz, T. R. Loveland, A. Kommareddy, A. Egorov, L. Chini, C. O. Justice, and J. R. G. Townshend. 2013. High-Resolution Global Maps of 21st-Century Forest Cover Change. Science 342 (15 November): 850-53. Data available on-line from: <a href="https://glad.earthengine.app/view/global-forest-change">https://glad.earthengine.app/view/global-forest-change</a></i>.<br/><br/>The data provided by the `basin` endpoint are aggregated over river basin polygons provided by <a href="https://www.hydrosheds.org/products/hydrobasins">HydroSHEDS</a>. The basin data are feely available for non-commercial and commercial use under a licence agreement included in the <a href="https://data.hydrosheds.org/file/technical-documentation/HydroSHEDS_TechDoc_v1_4.pdf">HydroSHEDS Technical Documentation</a>.'

api_domain: str = "localhost"

@property
def api_url(self):
if self.api_domain == "localhost":
return f"http://{self.api_domain}:{self.uvicorn_port}"
else:
return f"https://{self.api_domain}{self.api_root_path}"


settings = Settings()
4 changes: 2 additions & 2 deletions deployment/kubernetes/deforestation-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ spec:
app: deforestation-api
spec:
containers:
- image: ghcr.io/openearthplatforminitiative/deforestation-api:0.1.3
- image: ghcr.io/openearthplatforminitiative/deforestation-api:0.2.0
name: deforestation-api
ports:
- containerPort: 8080
env:
- name: API_ROOT_PATH
value: "/deforestation"
- name: VERSION
value: 0.1.3
value: 0.2.0
---
apiVersion: v1
kind: Service
Expand Down
Loading