Created
September 23, 2024 00:51
-
-
Save alexcheng1982/a46f782b1d2201c962862fb038aa458a to your computer and use it in GitHub Desktop.
HTTP status code SVG generation
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
import json | |
import math | |
from xml.etree.ElementTree import Element, SubElement, tostring | |
from xml.dom import minidom | |
def create_svg_element(tag, attrib={}, **extra): | |
element = Element(tag, attrib) | |
for name, value in extra.items(): | |
if name in ["font_size", "font_family", "font_weight", "text_anchor", "stroke_width"]: | |
element.set(name.replace("_", "-"), str(value)) | |
else: | |
element.set(name, str(value)) | |
return element | |
def create_text_element(x, y, text, font_size, font_family, font_weight="normal", text_anchor="middle"): | |
text_elem = create_svg_element("text", x=x, y=y, fill="black", | |
font_size=font_size, font_family=font_family, | |
font_weight=font_weight, text_anchor=text_anchor) | |
text_elem.text = text | |
return text_elem | |
def wrap_text(text, max_width, font_size): | |
words = text.split() | |
lines = [] | |
current_line = [] | |
current_width = 0 | |
for word in words: | |
word_width = len(word) * font_size * 0.6 # Approximate width | |
if current_width + word_width > max_width: | |
lines.append(" ".join(current_line)) | |
current_line = [word] | |
current_width = word_width | |
else: | |
current_line.append(word) | |
current_width += word_width | |
lines.append(" ".join(current_line)) | |
return lines | |
def create_card(x, y, width, height, code, name, description, color): | |
group = create_svg_element("g") | |
rect = create_svg_element("rect", x=x, y=y, width=width, height=height, fill=color, rx=10, ry=10) | |
group.append(rect) | |
# Code | |
group.append(create_text_element(x + width / 2, y + 35, str(code), 24, "Courier New", "bold")) | |
# Divider 1 | |
group.append( | |
create_svg_element("line", x1=x + 10, y1=y + 50, x2=x + width - 10, y2=y + 50, stroke="black", stroke_width=1)) | |
# Name | |
name_lines = wrap_text(name, width - 20, 18) | |
for i, line in enumerate(name_lines): | |
group.append(create_text_element(x + width / 2, y + 80 + i * 22, line, 18, "Roboto", "bold")) | |
# Divider 2 | |
group.append( | |
create_svg_element("line", x1=x + 10, y1=y + 110, x2=x + width - 10, y2=y + 110, stroke="black", stroke_width=1)) | |
# Description | |
description_lines = wrap_text(description, width - 20, 16) | |
for i, line in enumerate(description_lines[:5]): # Limit to 5 lines | |
group.append(create_text_element(x + width / 2, y + 135 + i * 20, line, 16, "Arial")) | |
return group | |
def generate_svg(data): | |
card_width = 320 | |
card_height = 240 | |
cards_per_row = 4 | |
group_padding = 50 | |
svg_width = card_width * cards_per_row + 100 | |
header_height = 60 | |
colors = { | |
"1xx": "#E6F3FF", | |
"2xx": "#E6FFE6", | |
"3xx": "#FFFFE6", | |
"4xx": "#FFE6E6", | |
"5xx": "#F3E6FF" | |
} | |
svg = create_svg_element("svg", width=svg_width, xmlns="http://www.w3.org/2000/svg") | |
# Add font definitions | |
defs = SubElement(svg, "defs") | |
style = SubElement(defs, "style") | |
style.text = "@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');" | |
# Add header | |
header = create_text_element(svg_width / 2, header_height / 2, "HTTP Status Codes", 36, "Arial", "bold") | |
svg.append(header) | |
y_offset = header_height + 30 | |
for group, codes in data.items(): | |
group_element = create_svg_element("g") | |
group_title = create_text_element(svg_width / 2, y_offset, group, 24, "Arial", "bold") | |
group_element.append(group_title) | |
y_offset += 40 | |
for i, code in enumerate(codes): | |
x = (i % cards_per_row) * card_width + 50 | |
y = (i // cards_per_row) * card_height + y_offset | |
card = create_card(x, y, card_width - 10, card_height - 10, | |
code["code"], code["name"], code["description"], colors[group]) | |
group_element.append(card) | |
svg.append(group_element) | |
y_offset += math.ceil(len(codes) / cards_per_row) * card_height + group_padding | |
svg.set("height", str(y_offset)) | |
return svg | |
def main(): | |
with open("http_status_codes.json", "r") as f: | |
data = json.load(f) | |
svg = generate_svg(data) | |
xml_str = minidom.parseString(tostring(svg)).toprettyxml(indent=" ") | |
with open("http_status_codes.svg", "w") as f: | |
f.write(xml_str) | |
if __name__ == "__main__": | |
main() |
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
{ | |
"1xx": [ | |
{ | |
"code": 100, | |
"name": "Continue", | |
"description": "The server has received the request headers and the client should proceed to send the request body." | |
}, | |
{ | |
"code": 101, | |
"name": "Switching Protocols", | |
"description": "The requester has asked the server to switch protocols and the server has agreed to do so." | |
}, | |
{ | |
"code": 102, | |
"name": "Processing", | |
"description": "The server has received and is processing the request, but no response is available yet." | |
}, | |
{ | |
"code": 103, | |
"name": "Early Hints", | |
"description": "Used to return some response headers before final HTTP message." | |
} | |
], | |
"2xx": [ | |
{ | |
"code": 200, | |
"name": "OK", | |
"description": "The request was successful and the server has returned the requested data." | |
}, | |
{ | |
"code": 201, | |
"name": "Created", | |
"description": "The request was successful and a new resource was created as a result." | |
}, | |
{ | |
"code": 202, | |
"name": "Accepted", | |
"description": "The request has been accepted for processing, but the processing has not been completed." | |
}, | |
{ | |
"code": 203, | |
"name": "Non-Authoritative Information", | |
"description": "The server successfully processed the request but is returning information that may be from another source." | |
}, | |
{ | |
"code": 204, | |
"name": "No Content", | |
"description": "The server successfully processed the request but is not returning any content." | |
}, | |
{ | |
"code": 205, | |
"name": "Reset Content", | |
"description": "The server successfully processed the request, but is not returning any content. Unlike a 204 response, this response requires that the requester reset the document view." | |
}, | |
{ | |
"code": 206, | |
"name": "Partial Content", | |
"description": "The server is delivering only part of the resource due to a range header sent by the client." | |
}, | |
{ | |
"code": 207, | |
"name": "Multi-Status", | |
"description": "The message body that follows is an XML message and can contain a number of separate response codes." | |
}, | |
{ | |
"code": 208, | |
"name": "Already Reported", | |
"description": "The members of a DAV binding have already been enumerated in a previous reply to this request, and are not being included again." | |
}, | |
{ | |
"code": 226, | |
"name": "IM Used", | |
"description": "The server has fulfilled a request for the resource, and the response is a representation of the result of one or more instance-manipulations applied to the current instance." | |
} | |
], | |
"3xx": [ | |
{ | |
"code": 300, | |
"name": "Multiple Choices", | |
"description": "The requested resource has multiple representations available." | |
}, | |
{ | |
"code": 301, | |
"name": "Moved Permanently", | |
"description": "The requested resource has been permanently moved to a new URL." | |
}, | |
{ | |
"code": 302, | |
"name": "Found", | |
"description": "The requested resource has been temporarily moved to a different URL." | |
}, | |
{ | |
"code": 303, | |
"name": "See Other", | |
"description": "The response to the request can be found under a different URI using a GET method." | |
}, | |
{ | |
"code": 304, | |
"name": "Not Modified", | |
"description": "The client's cached version of the requested resource is up to date." | |
}, | |
{ | |
"code": 305, | |
"name": "Use Proxy", | |
"description": "The requested resource must be accessed through the proxy given by the Location field." | |
}, | |
{ | |
"code": 307, | |
"name": "Temporary Redirect", | |
"description": "The requested resource resides temporarily under a different URI." | |
}, | |
{ | |
"code": 308, | |
"name": "Permanent Redirect", | |
"description": "The requested resource has been permanently moved to another URI." | |
} | |
], | |
"4xx": [ | |
{ | |
"code": 400, | |
"name": "Bad Request", | |
"description": "The server cannot process the request due to a client error." | |
}, | |
{ | |
"code": 401, | |
"name": "Unauthorized", | |
"description": "The request requires user authentication." | |
}, | |
{ | |
"code": 402, | |
"name": "Payment Required", | |
"description": "Reserved for future use. The original intention was that this code might be used as part of some form of digital cash or micropayment scheme." | |
}, | |
{ | |
"code": 403, | |
"name": "Forbidden", | |
"description": "The server understood the request but refuses to authorize it." | |
}, | |
{ | |
"code": 404, | |
"name": "Not Found", | |
"description": "The requested resource could not be found on the server." | |
}, | |
{ | |
"code": 405, | |
"name": "Method Not Allowed", | |
"description": "The request method is not supported for the requested resource." | |
}, | |
{ | |
"code": 406, | |
"name": "Not Acceptable", | |
"description": "The requested resource is capable of generating only content not acceptable according to the Accept headers sent in the request." | |
}, | |
{ | |
"code": 407, | |
"name": "Proxy Authentication Required", | |
"description": "The client must first authenticate itself with the proxy." | |
}, | |
{ | |
"code": 408, | |
"name": "Request Timeout", | |
"description": "The server timed out waiting for the request." | |
}, | |
{ | |
"code": 409, | |
"name": "Conflict", | |
"description": "The request could not be completed due to a conflict with the current state of the resource." | |
}, | |
{ | |
"code": 410, | |
"name": "Gone", | |
"description": "The requested resource is no longer available and will not be available again." | |
}, | |
{ | |
"code": 411, | |
"name": "Length Required", | |
"description": "The request did not specify the length of its content, which is required by the requested resource." | |
}, | |
{ | |
"code": 412, | |
"name": "Precondition Failed", | |
"description": "The server does not meet one of the preconditions that the requester put on the request." | |
}, | |
{ | |
"code": 413, | |
"name": "Payload Too Large", | |
"description": "The request is larger than the server is willing or able to process." | |
}, | |
{ | |
"code": 414, | |
"name": "URI Too Long", | |
"description": "The URI provided was too long for the server to process." | |
}, | |
{ | |
"code": 415, | |
"name": "Unsupported Media Type", | |
"description": "The request entity has a media type which the server or resource does not support." | |
}, | |
{ | |
"code": 416, | |
"name": "Range Not Satisfiable", | |
"description": "The client has asked for a portion of the file, but the server cannot supply that portion." | |
}, | |
{ | |
"code": 417, | |
"name": "Expectation Failed", | |
"description": "The server cannot meet the requirements of the Expect request-header field." | |
}, | |
{ | |
"code": 418, | |
"name": "I'm a teapot", | |
"description": "Any attempt to brew coffee with a teapot should result in this error." | |
}, | |
{ | |
"code": 421, | |
"name": "Misdirected Request", | |
"description": "The request was directed at a server that is not able to produce a response." | |
}, | |
{ | |
"code": 422, | |
"name": "Unprocessable Entity", | |
"description": "The request was well-formed but was unable to be followed due to semantic errors." | |
}, | |
{ | |
"code": 423, | |
"name": "Locked", | |
"description": "The resource that is being accessed is locked." | |
}, | |
{ | |
"code": 424, | |
"name": "Failed Dependency", | |
"description": "The request failed due to failure of a previous request." | |
}, | |
{ | |
"code": 425, | |
"name": "Too Early", | |
"description": "Indicates that the server is unwilling to risk processing a request that might be replayed." | |
}, | |
{ | |
"code": 426, | |
"name": "Upgrade Required", | |
"description": "The client should switch to a different protocol such as TLS/1.0." | |
}, | |
{ | |
"code": 428, | |
"name": "Precondition Required", | |
"description": "The origin server requires the request to be conditional." | |
}, | |
{ | |
"code": 429, | |
"name": "Too Many Requests", | |
"description": "The user has sent too many requests in a given amount of time." | |
}, | |
{ | |
"code": 431, | |
"name": "Request Header Fields Too Large", | |
"description": "The server is unwilling to process the request because its header fields are too large." | |
}, | |
{ | |
"code": 451, | |
"name": "Unavailable For Legal Reasons", | |
"description": "The user-agent requested a resource that cannot legally be provided." | |
} | |
], | |
"5xx": [ | |
{ | |
"code": 500, | |
"name": "Internal Server Error", | |
"description": "A generic error message when the server encounters an unexpected condition." | |
}, | |
{ | |
"code": 501, | |
"name": "Not Implemented", | |
"description": "The server does not support the functionality required to fulfill the request." | |
}, | |
{ | |
"code": 502, | |
"name": "Bad Gateway", | |
"description": "The server acting as a gateway or proxy received an invalid response from an upstream server." | |
}, | |
{ | |
"code": 503, | |
"name": "Service Unavailable", | |
"description": "The server is currently unable to handle the request due to temporary overloading or maintenance." | |
}, | |
{ | |
"code": 504, | |
"name": "Gateway Timeout", | |
"description": "The server acting as a gateway or proxy did not receive a timely response from an upstream server." | |
}, | |
{ | |
"code": 505, | |
"name": "HTTP Version Not Supported", | |
"description": "The server does not support the HTTP protocol version used in the request." | |
}, | |
{ | |
"code": 506, | |
"name": "Variant Also Negotiates", | |
"description": "Transparent content negotiation for the request results in a circular reference." | |
}, | |
{ | |
"code": 507, | |
"name": "Insufficient Storage", | |
"description": "The server is unable to store the representation needed to complete the request." | |
}, | |
{ | |
"code": 508, | |
"name": "Loop Detected", | |
"description": "The server detected an infinite loop while processing the request." | |
}, | |
{ | |
"code": 510, | |
"name": "Not Extended", | |
"description": "Further extensions to the request are required for the server to fulfill it." | |
}, | |
{ | |
"code": 511, | |
"name": "Network Authentication Required", | |
"description": "The client needs to authenticate to gain network access." | |
} | |
] | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment