This Django Project currently consists of two Apps: an API wrapper and a Stats API
In order to protect credentials & API keys when using data from public APIs like Flickr and Blogger, this service makes an authenticated call to the original endpoint and only forwards the necessary fields (JSON) in a "wrapper" call used by the frontend.
Additionally, because all the sensitive information is kept in a separate JSON file outside of source control, the Django code can be safely commited to GitHub.
Currently, only one API (Blogger) is configured but there are plans to incude more like Flickr, Twitter, etc. This call fetches the Latest Blog Post from https://roadtripsandhikes.blogspot.com/.
Latest Blog Post: https://api.roadtripsandhikes.org/wrapper/bloggerApiGetLatestPost/
This App is an instance of the Django Rest Framework. It was initially conceived as a way to store my own hiking stats and be able to share the details on other pages.
There are two Models: Person, Hike
A Person consists of:
- "first_name"
- "last_name"
- "slug": (autogenerated)
- "join_date": (autogenerated)
- "email"
- "profile_img"
A Hike consists of:
- "hike_date"
- "location"
- "state"
- "distance_mi"
- "elevation_gain_ft"
- "highest_elev_ft"
- "alltrails_url"
- "blogger_url"
- "hiker" (foreign key)
Overall Stats are calculated for each user and included in the the Person endpoint.
- "total_hikes"
- "total_miles"
- "total_elev_feet"
- "highest_elev_feet"
- "total_hikes_percentage" (based on 75)
- "total_miles_percentage" (based on 500)
- "total_elev_percentage" (based on 100,000)
The Overall Stats are surfaced in a web view:
-
Full page
- By Slug https://api.roadtripsandhikes.org/hiking-stats/for/larry-moiola/?2021&full - Full page view w/ capsule CSS
- By Slug https://api.roadtripsandhikes.org/hiking-stats/for/larry-moiola/?2021&full&flat - Full page view w/ capsule CSS without drop-shadow
- By Id https://api.roadtripsandhikes.org/hiking-stats/for/1/?2021&full - Full page view w/ capsule CSS
- By Shortened URL https://rtah.xyz/h/?y=2021 - redirects to https://api.roadtripsandhikes.org/hiking-stats/for/larry-moiola/?2021&full
-
Widget
- By Slug https://api.roadtripsandhikes.org/hiking-stats/for/larry-moiola/?2021 - Default: black bg, white text
- By Id https://api.roadtripsandhikes.org/hiking-stats/for/1/?2021 - Default: black bg, white text
- By Slug https://api.roadtripsandhikes.org/hiking-stats/for/larry-moiola/?rgba(255,33,0,0.7) - (custom colors: dark-orange bg, white text)
- By Id https://api.roadtripsandhikes.org/hiking-stats/for/1/?2021&rgba(255,33,0,0.7) - (custom colors: dark-orange bg, white text)
- By Slug https://api.roadtripsandhikes.org/hiking-stats/for/larry-moiola/?linear-gradient(45deg,%20blue,%20red) - (custom gradient: blue-to-red)
The URL args are used to toggle Widget vs Full Page via when the page is loaded (JavaScript).
- If no args, the widget view with default colors is returned; summary of all years
- If a valid RGBA code, e.g. "rgba(0,0,0,1)", the widget view is return with custom colors
- If "full" is included after year, the full-page view is returned, *no custom colors
- If invalid args, the widget view with default colors is returned; summary of all years
Note: The widget is currently used on https://roadtripsandhikes.blogspot.com, shown under the header.
The Stats API requires an API-Key or you have to be logged in as a Django Admin.
- An "Authorization" header can be set with value "Api-Key aA1bB2cC3.dD4eE5fF6gG7hH8iI9jJ0kK1lL2mM3nN4oO5" in Postman
- Do not use the Authorization > API-Key field
This interface supports the CRUD operations via the DRF web form and JSON. (need to verify new Hikes are created with JSON - was having issue with foreign key assignment)
In order to allow the widget to be embedded (iframe) on Blogger, I'm using "@xframe_options_exempt" decorator. The major browsers have increased security protections (to address clickjacking), and block content from being loaded in frames/iframes by default. The decorator gives exemption to this particular view.
More Info: https://www.hackersfriend.com/articles/how-does-django-prevents-clickjacking
-
By year (this filters Hikes, hikes[], aggregates values):
-
By start_date & end_date (this filters Hikes only):
This app runs on a DreamHost VPS using Gunicorn with systemd user services (Linger) for automatic startup and restart.
The systemd service file is located at ~/.config/systemd/user/gunicorn-api.service:
[Unit]
Description=Gunicorn instance for api.roadtripsandhikes.org
After=network.target
[Service]
WorkingDirectory=/home/lar_mo/api.roadtripsandhikes.org/rtah_apis
Environment="PATH=/home/lar_mo/api.roadtripsandhikes.org/rtah_apis/.venv/bin"
ExecStart=/home/lar_mo/api.roadtripsandhikes.org/rtah_apis/.venv/bin/gunicorn --bind=api.roadtripsandhikes.org:8080 --timeout 120 --workers=1 --threads=3 --keep-alive 2 rtah_apis.wsgi
Restart=always
[Install]
WantedBy=default.target# Check status
systemctl --user status gunicorn-api
# Restart service
systemctl --user restart gunicorn-api
# View logs
journalctl --user -u gunicorn-api -f
# Stop service
systemctl --user stop gunicorn-api- Add more fields to Hike
- Map coordinates
- Rating: 1 - 5 stars
- Difficulty (easy, moderate, difficult, 1, 2, 3)
- Conditions (rocky, muddy, windy, great) (many-to-one)
- Activity Type (hiking, running, horseback, mtn bike) (many-to-one)
- Photos (many-to-one)
- Notes
- More fields from AllTrails
- Moving Time
- Total Time
- Average Pace
- Calories
- Add more fields to Person (tbd)
- Add more calculations in Overall Stats
- Average length (miles)
- Average elevations gain (feet)
- Add field for Footpath URLs