Skip to content

Instantly share code, notes, and snippets.

@alexcheng1982
Created September 23, 2024 00:51
Show Gist options
  • Save alexcheng1982/a46f782b1d2201c962862fb038aa458a to your computer and use it in GitHub Desktop.
Save alexcheng1982/a46f782b1d2201c962862fb038aa458a to your computer and use it in GitHub Desktop.
HTTP status code SVG generation
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()
{
"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."
}
]
}
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment