mirror of
https://gitlab.com/2-chainz/2chainz.git
synced 2025-06-16 01:46:39 +00:00
Compare commits
3 Commits
08c4b96918
...
49d023b229
Author | SHA1 | Date | |
---|---|---|---|
49d023b229 | |||
130a9354cb | |||
8421d7092f |
@ -28,8 +28,8 @@ class TestApi:
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"mocked_time,start_time,expected",
|
"mocked_time,start_time,expected",
|
||||||
[
|
[
|
||||||
(100, 50, 50), # 100 - 50 = 50 seconds uptime
|
(100, 50, "50"), # 100 - 50 = 50 seconds uptime
|
||||||
(200, 100, 100), # 200 - 100 = 100 seconds uptime
|
(200, 100, "100"), # 200 - 100 = 100 seconds uptime
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_api_uptime_calculation(self, mocked_time, start_time, expected):
|
def test_api_uptime_calculation(self, mocked_time, start_time, expected):
|
||||||
|
@ -3,18 +3,19 @@ import time
|
|||||||
import tomllib
|
import tomllib
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import logging
|
|
||||||
from fastapi import FastAPI, Request
|
from fastapi import FastAPI
|
||||||
from fastapi.middleware.trustedhost import TrustedHostMiddleware
|
from fastapi.middleware.trustedhost import TrustedHostMiddleware
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
|
||||||
app = FastAPI()
|
app = FastAPI(
|
||||||
|
title="2 Chainz REST",
|
||||||
|
description="A simple API to get 2 Chainz quotes and aliases. See <a href=https://2chainz.ansonbiggs.com>2chainz.ansonbiggs.com</a> for a full explanation.",
|
||||||
|
)
|
||||||
app.add_middleware(
|
app.add_middleware(
|
||||||
TrustedHostMiddleware,
|
TrustedHostMiddleware,
|
||||||
allowed_hosts=["*"],
|
allowed_hosts=["*"],
|
||||||
)
|
)
|
||||||
logging.basicConfig(level=logging.INFO)
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
|
|
||||||
@ -31,37 +32,80 @@ def read_data() -> dict[str, str]:
|
|||||||
data = read_data()
|
data = read_data()
|
||||||
|
|
||||||
|
|
||||||
# Log all requests to debug issues
|
@app.get(
|
||||||
@app.middleware("http")
|
"/api/",
|
||||||
async def log_requests(request: Request, call_next):
|
summary="Health Check",
|
||||||
# Log what's coming in
|
description="Check API health status and uptime",
|
||||||
logger.info(f"Request: {request.method} {request.url.path}")
|
response_description="Health status with timestamp and uptime",
|
||||||
logger.info(f"Host header: {request.headers.get('host')}")
|
tags=["Health"],
|
||||||
logger.info(f"CF-Ray: {request.headers.get('cf-ray', 'Not from Cloudflare')}")
|
responses={
|
||||||
|
200: {
|
||||||
|
"description": "Successful health check",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"example": {
|
||||||
|
"status": "ok",
|
||||||
|
"timestamp": "2025-05-24T10:30:00",
|
||||||
|
"uptime_seconds": "3600.5",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
async def ping() -> dict[str, str]:
|
||||||
|
"""
|
||||||
|
Endpoint to check on the health of the API and to help diagnose issues.
|
||||||
|
|
||||||
try:
|
Returns current status, timestamp, and uptime information.
|
||||||
response = await call_next(request)
|
"""
|
||||||
return response
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Request processing failed: {e}")
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/")
|
|
||||||
async def ping():
|
|
||||||
return {
|
return {
|
||||||
"status": "ok",
|
"status": "ok",
|
||||||
"timestamp": datetime.now().isoformat(),
|
"timestamp": datetime.now().isoformat(),
|
||||||
"uptime_seconds": round(time.time() - start_time, 2),
|
"uptime_seconds": str(round(time.time() - start_time, 2)),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/quote")
|
@app.get(
|
||||||
|
"/api/quote",
|
||||||
|
summary="2 Chainz Quote",
|
||||||
|
description="Get a quote from 2 Chainz",
|
||||||
|
tags=["Data"],
|
||||||
|
responses={
|
||||||
|
200: {
|
||||||
|
"description": "Successful quote",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"example": {
|
||||||
|
"quote": "Wood grain chestnut, titty fuck chest nut",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
async def quote():
|
async def quote():
|
||||||
return {"quote": random.choice(data["quotes"])}
|
return {"quote": random.choice(data["quotes"])}
|
||||||
|
|
||||||
|
|
||||||
@app.get("/api/alias")
|
@app.get(
|
||||||
|
"/api/alias",
|
||||||
|
summary="2 Chainz Alias",
|
||||||
|
description="Get one of 2 Chainz many aliases",
|
||||||
|
tags=["Data"],
|
||||||
|
responses={
|
||||||
|
200: {
|
||||||
|
"description": "Successful alias",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"example": {
|
||||||
|
"alias": "2 Chainz",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
async def alias():
|
async def alias():
|
||||||
return {"alias": random.choice(data["aliases"])}
|
return {"alias": random.choice(data["aliases"])}
|
||||||
|
|
||||||
|
@ -40,106 +40,67 @@
|
|||||||
:root {
|
:root {
|
||||||
--color: darkviolet;
|
--color: darkviolet;
|
||||||
--color-bg-secondary: black;
|
--color-bg-secondary: black;
|
||||||
}
|
--color-link: darkviolet;
|
||||||
|
|
||||||
@media screen and (max-width: 400px) {
|
|
||||||
#scroll-icon {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<header style="height: 70vh;">
|
<header style="height: 90vh">
|
||||||
<nav>
|
<nav>
|
||||||
<ul>
|
<a href="https://2chainz.ansonbiggs.com">2chainz.ansonbiggs.com</a>
|
||||||
<li>
|
<p>A REST API for 2 Chainz Quotes</p>
|
||||||
<a href="https://2chainz.ansonbiggs.com">2chainz.ansonbiggs.com</a> - A REST API for 2
|
<a href="https://gitlab.com/2-chainz/2chainz">Source Code</a>
|
||||||
Chainz Quotes
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
</nav>
|
||||||
<section>
|
<section style="height: 50vh">
|
||||||
<blockquote>
|
<blockquote style="margin: auto">
|
||||||
<span id="quote"></span>
|
<span id="quote">TRUUUUUUUU</span>
|
||||||
<footer><i id="alias">- 2 Chainz</i></footer>
|
<footer><i id="alias">- 2 Chainz</i></footer>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
</section>
|
</section>
|
||||||
<p>
|
<section>
|
||||||
<a onclick="getQuote()" href="#"
|
<a onclick="getQuote()" href="#"
|
||||||
><b>
|
><b style="width: 20vw">
|
||||||
<ion-icon size="large" name="refresh-circle"></ion-icon><br />
|
<ion-icon size="large" name="refresh-circle"></ion-icon>
|
||||||
New Quote</b
|
<span style="display: grid; place-items: center">New Quote</span>
|
||||||
></a
|
</b>
|
||||||
>
|
</a>
|
||||||
<a id="tweet" href="#"
|
</section>
|
||||||
><b
|
<a href="#scroll" id="scroll-icon" style="padding-top: 10vh"
|
||||||
><ion-icon size="large" name="logo-twitter"></ion-icon> <br />
|
|
||||||
Tweet Quote
|
|
||||||
</b></a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
<a href="#scroll" id="scroll-icon" style="padding-top: 10vh;"
|
|
||||||
><ion-icon size="large" name="arrow-down-sharp"></ion-icon
|
><ion-icon size="large" name="arrow-down-sharp"></ion-icon
|
||||||
></a>
|
></a>
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
<hr style="padding-top: 0;" />
|
<hr style="padding-top: 0" />
|
||||||
<header id="scroll">
|
<header id="scroll">
|
||||||
<h2>Usage</h2>
|
<h2>Usage</h2>
|
||||||
|
<p>
|
||||||
|
For exhaustive and up to date documentation see
|
||||||
|
<a href="/docs">/docs</a>
|
||||||
|
</p>
|
||||||
</header>
|
</header>
|
||||||
<details open>
|
<details open>
|
||||||
<summary>Quote</summary>
|
<summary>Quote</summary>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Returns a random 2 Chainz Quote in <code>json</code> format like the
|
Returns a random 2 Chainz Quote in <code>json</code> format like the
|
||||||
following example:
|
following example:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
send a <code>get</code> request to
|
send a <code>get</code> request to
|
||||||
<code
|
<code
|
||||||
><a href="https://chainz.ansonbiggs.com/api/quote"
|
><a href="https://2chainz.ansonbiggs.com/api/quote"
|
||||||
>https://chainz.ansonbiggs.com/api/quote</a
|
>https://2chainz.ansonbiggs.com/api/quote</a
|
||||||
></code
|
></code
|
||||||
>
|
>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre><code>{
|
<pre><code>{
|
||||||
"quote": "I got a pocket full of money, it got me walking all slew-foot"
|
"quote": "I got a pocket full of money, it got me walking all slew-foot"
|
||||||
}</code></pre>
|
}</code></pre>
|
||||||
|
|
||||||
<details style="margin-left: 5%;">
|
|
||||||
<summary>Parameters</summary>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
This endpoint also supports an optional <code>batch</code> parameter
|
|
||||||
to get more than one quote per request. Maximum quotes that the
|
|
||||||
endpoint will return is the amount of quotes in
|
|
||||||
<a
|
|
||||||
href="https://gitlab.com/2-chainz/2-chainz-rest/-/blob/master/quote/quotes.py"
|
|
||||||
>quotes.py</a
|
|
||||||
>
|
|
||||||
and is subject to change. An example return from
|
|
||||||
<code>
|
|
||||||
<a href="https://chainz.ansonbiggs.com/api/quote?batch=2"
|
|
||||||
>https://chainz.ansonbiggs.com/api/quote?batch=2</a
|
|
||||||
></code
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<pre><code class="json">{
|
|
||||||
"quotes": [
|
|
||||||
"I'm in the kitchen. Yams errrrrwhere.",
|
|
||||||
"Started from the trap, now I rap"
|
|
||||||
]
|
|
||||||
}</code></pre>
|
|
||||||
</details>
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<details
|
<details>
|
||||||
><summary>Alias</summary>
|
<summary>Alias</summary>
|
||||||
<p>
|
<p>
|
||||||
Returns a random 2 Chainz alias in <code>json</code> format. The
|
Returns a random 2 Chainz alias in <code>json</code> format. The
|
||||||
return values are weighted and a full list can be seen in
|
return values are weighted and a full list can be seen in
|
||||||
@ -151,20 +112,21 @@
|
|||||||
<p>
|
<p>
|
||||||
send a <code>get</code> request to
|
send a <code>get</code> request to
|
||||||
<code
|
<code
|
||||||
><a href="https://chainz.ansonbiggs.com/api/alias"
|
><a href="https://2chainz.ansonbiggs.com/api/alias"
|
||||||
>https://chainz.ansonbiggs.com/api/alias</a
|
>https://2chainz.ansonbiggs.com/api/alias</a
|
||||||
></code
|
></code
|
||||||
>
|
>
|
||||||
</p>
|
</p>
|
||||||
<pre><code>{
|
<pre><code>{
|
||||||
"alias": "Dos Cadenas"
|
"alias": "Dos Cadenas"
|
||||||
}</code></pre>
|
}</code></pre>
|
||||||
</details>
|
</details>
|
||||||
<hr />
|
<hr />
|
||||||
<section>
|
<section>
|
||||||
<header>
|
<header>
|
||||||
<h2>
|
<h2>
|
||||||
Projects built using 2chainz.ansonbiggs.com (Your project could be here!)
|
Projects built using 2chainz.ansonbiggs.com (Your project could be
|
||||||
|
here!)
|
||||||
</h2>
|
</h2>
|
||||||
</header>
|
</header>
|
||||||
<aside>
|
<aside>
|
||||||
@ -214,7 +176,7 @@
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<small
|
<small
|
||||||
><a href="https://twitter.com/Anson_3D"
|
><a href="https://ansonbiggs.com/#connect"
|
||||||
>Please let me know if you use it though!</a
|
>Please let me know if you use it though!</a
|
||||||
></small
|
></small
|
||||||
>
|
>
|
||||||
@ -224,43 +186,31 @@
|
|||||||
<h3>Do I need an API key or is this API rate limited?</h3>
|
<h3>Do I need an API key or is this API rate limited?</h3>
|
||||||
<p>
|
<p>
|
||||||
No, the API is totally free and unlimited. However, its being hosted
|
No, the API is totally free and unlimited. However, its being hosted
|
||||||
by a college student so be nice.
|
on a tiny machine that is overburdened by docker containers.
|
||||||
</p>
|
</p>
|
||||||
</aside>
|
</aside>
|
||||||
<aside>
|
<aside>
|
||||||
<h3>Is this project open source? Can I contribute?</h3>
|
<h3>Is this project open source? Can I contribute?</h3>
|
||||||
<p>
|
<p>
|
||||||
Yes and Yes! Check out the
|
Yes and Yes! Check out the
|
||||||
<a href="https://gitlab.com/2-chainz">Project on GitLab.</a>
|
<a href="https://gitlab.com/2-chainz/2chainz">Project on GitLab.</a>
|
||||||
</p>
|
</p>
|
||||||
</aside>
|
</aside>
|
||||||
<aside>
|
<aside>
|
||||||
<h3>Does 2 Chainz know about this?</h3>
|
<h3>Does 2 Chainz know about this?</h3>
|
||||||
<p>
|
<p>Probably not.</p>
|
||||||
Probably not.
|
|
||||||
</p>
|
|
||||||
</aside>
|
</aside>
|
||||||
<aside>
|
<aside>
|
||||||
<h3>Why?</h3>
|
<h3>Why?</h3>
|
||||||
<p>
|
<p>Because 2 Chainz has some of the best lines in the rap game.</p>
|
||||||
Because 2 Chainz has some of the best lines in the rap game.
|
|
||||||
</p>
|
|
||||||
</aside>
|
</aside>
|
||||||
</section>
|
</section>
|
||||||
</main>
|
</main>
|
||||||
<footer>
|
<footer>
|
||||||
<hr />
|
<hr />
|
||||||
<p>
|
<p>Made by <a href="https://ansonbiggs.com">Anson</a></p>
|
||||||
Made by <a href="https://gitlab.com/MisterBiggs">Anson Biggs</a>,
|
<p>Inspired By <a href="https://kanye.rest/">kanye.rest</a>.</p>
|
||||||
<a href="https://twitter.com/Anson_3D">@Anson_3D </a>
|
<p><small>Truuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu</small></p>
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Inspired By <a href="https://kanye.rest/">kanye.rest</a> which was
|
|
||||||
created by:
|
|
||||||
<a href="https://ajzbc.com" target="_blank">Andrew Jazbec</a>,
|
|
||||||
<a href="https://twitter.com/ajzbc" target="_blank">@ajzbc</a>
|
|
||||||
</p>
|
|
||||||
<p><small>Truuuuuuuu</small></p>
|
|
||||||
</footer>
|
</footer>
|
||||||
<script>
|
<script>
|
||||||
getQuote();
|
getQuote();
|
||||||
@ -270,13 +220,6 @@
|
|||||||
.then((resp) => resp.json())
|
.then((resp) => resp.json())
|
||||||
.then(function (data) {
|
.then(function (data) {
|
||||||
document.getElementById("quote").innerHTML = data.quote;
|
document.getElementById("quote").innerHTML = data.quote;
|
||||||
|
|
||||||
const tweet = encodeURIComponent(
|
|
||||||
`"${data.quote}" -@2chainz via https://2chainz.ansonbiggs.com`
|
|
||||||
);
|
|
||||||
document.getElementById(
|
|
||||||
"tweet"
|
|
||||||
).href = `https://twitter.com/intent/tweet?text=${tweet}`;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
fetch("/api/alias", { method: "GET" })
|
fetch("/api/alias", { method: "GET" })
|
||||||
@ -286,6 +229,13 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script src="https://unpkg.com/ionicons@5.0.0/dist/ionicons.js"></script>
|
<script
|
||||||
|
type="module"
|
||||||
|
src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.esm.js"
|
||||||
|
></script>
|
||||||
|
<script
|
||||||
|
nomodule
|
||||||
|
src="https://unpkg.com/ionicons@7.1.0/dist/ionicons/ionicons.js"
|
||||||
|
></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user