{
  "openapi": "3.1.0",
  "info": {
    "title": "eduardstal.com API",
    "version": "1.0.0",
    "description": "A small public, read-only JSON API for eduardstal.com: profile, work, projects and posts. No authentication; CORS is open.",
    "contact": {
      "name": "Eduard Stere",
      "url": "https://eduardstal.com/contact"
    }
  },
  "servers": [
    {
      "url": "https://eduardstal.com/api/v1"
    }
  ],
  "tags": [
    {
      "name": "About",
      "description": "Who I am"
    },
    {
      "name": "Work",
      "description": "Jobs and projects"
    },
    {
      "name": "Blog",
      "description": "Posts"
    },
    {
      "name": "Activity",
      "description": "Site traffic"
    }
  ],
  "paths": {
    "/": {
      "get": {
        "operationId": "getIndex",
        "summary": "Index",
        "description": "The API name and version, and a link to every endpoint.",
        "tags": [
          "About"
        ],
        "responses": {
          "200": {
            "description": "The index",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Index"
                }
              }
            }
          }
        }
      }
    },
    "/profile": {
      "get": {
        "operationId": "getProfile",
        "summary": "Profile",
        "description": "Name, role, bio, education and skills, with links to my profiles, resume and calendar.",
        "tags": [
          "About"
        ],
        "responses": {
          "200": {
            "description": "The profile",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Profile"
                }
              }
            }
          }
        }
      }
    },
    "/experience": {
      "get": {
        "operationId": "listExperience",
        "summary": "Experience",
        "description": "Every job, newest first, with its highlights.",
        "tags": [
          "Work"
        ],
        "responses": {
          "200": {
            "description": "The jobs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Job"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/projects": {
      "get": {
        "operationId": "listProjects",
        "summary": "Projects",
        "description": "Things I have built or am building.",
        "tags": [
          "Work"
        ],
        "responses": {
          "200": {
            "description": "The projects",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Project"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/posts": {
      "get": {
        "operationId": "listPosts",
        "summary": "Posts",
        "description": "Every published post, newest first, without its content.",
        "tags": [
          "Blog"
        ],
        "responses": {
          "200": {
            "description": "The posts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PostSummary"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/posts/{slug}": {
      "get": {
        "operationId": "getPost",
        "summary": "Post",
        "description": "One post, with its content as Markdown.",
        "tags": [
          "Blog"
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "The post’s slug, as in /blog/{slug}",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The post",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Post"
                }
              }
            }
          },
          "404": {
            "description": "There is nothing at this path",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/stats": {
      "get": {
        "operationId": "getStats",
        "summary": "Stats",
        "description": "The site’s traffic, summarized every hour: humans and bots, visitors, top pages, posts, countries and crawlers for the last 24 hours, 7, 30 and 90 days. Pages, posts and countries with fewer than 5 visits are left out.",
        "tags": [
          "Activity"
        ],
        "responses": {
          "200": {
            "description": "The summary",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Stats"
                }
              }
            }
          },
          "503": {
            "description": "The summary is not available right now",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "getOpenApi",
        "summary": "OpenAPI",
        "description": "This description of the API, as OpenAPI 3.1.",
        "tags": [
          "About"
        ],
        "responses": {
          "200": {
            "description": "The OpenAPI document"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Index": {
        "type": "object",
        "required": [
          "name",
          "version",
          "docs",
          "openapi",
          "endpoints"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "docs": {
            "type": "string",
            "format": "uri"
          },
          "openapi": {
            "type": "string",
            "format": "uri"
          },
          "endpoints": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Profile": {
        "type": "object",
        "required": [
          "name",
          "role",
          "company",
          "url",
          "bio",
          "education",
          "skills",
          "links"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "role": {
            "type": "string"
          },
          "company": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "photo": {
            "type": "string",
            "format": "uri"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "bio": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "education": {
            "type": "object",
            "properties": {
              "school": {
                "type": "string"
              },
              "degree": {
                "type": "string"
              },
              "honours": {
                "type": "string"
              },
              "start": {
                "type": "string"
              },
              "end": {
                "type": "string"
              }
            }
          },
          "skills": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "category": {
                  "type": "string"
                },
                "skills": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "links": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "format": "uri"
            }
          }
        }
      },
      "Job": {
        "type": "object",
        "required": [
          "id",
          "company",
          "role",
          "start",
          "end",
          "current",
          "type",
          "highlights"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "company": {
            "type": "string"
          },
          "role": {
            "type": "string"
          },
          "start": {
            "type": "string",
            "description": "YYYY-MM"
          },
          "end": {
            "type": [
              "string",
              "null"
            ],
            "description": "YYYY-MM, or null for the current job"
          },
          "current": {
            "type": "boolean"
          },
          "type": {
            "type": "string",
            "enum": [
              "full-time",
              "freelance"
            ]
          },
          "highlights": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Project": {
        "type": "object",
        "required": [
          "id",
          "name",
          "tagline",
          "description",
          "tags",
          "stats",
          "status"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "tagline": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "stats": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "label": {
                  "type": "string"
                },
                "value": {
                  "type": "string"
                }
              }
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "live",
              "building",
              "here"
            ]
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "github": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "image": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        }
      },
      "PostSummary": {
        "type": "object",
        "required": [
          "slug",
          "title",
          "summary",
          "publishedAt",
          "readingMinutes",
          "url"
        ],
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          },
          "publishedAt": {
            "type": "string",
            "format": "date"
          },
          "readingMinutes": {
            "type": "integer"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "image": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "Post": {
        "allOf": [
          {
            "$ref": "#/components/schemas/PostSummary"
          },
          {
            "type": "object",
            "required": [
              "content"
            ],
            "properties": {
              "content": {
                "type": "string",
                "description": "Markdown"
              }
            }
          }
        ]
      },
      "Stats": {
        "type": "object",
        "required": [
          "generatedAt",
          "ranges"
        ],
        "properties": {
          "generatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "ranges": {
            "type": "object",
            "properties": {
              "24h": {
                "$ref": "#/components/schemas/StatsRange"
              },
              "7d": {
                "$ref": "#/components/schemas/StatsRange"
              },
              "30d": {
                "$ref": "#/components/schemas/StatsRange"
              },
              "90d": {
                "$ref": "#/components/schemas/StatsRange"
              }
            }
          }
        }
      },
      "StatsRange": {
        "type": "object",
        "properties": {
          "from": {
            "type": "string",
            "format": "date-time"
          },
          "to": {
            "type": "string",
            "format": "date-time"
          },
          "totals": {
            "type": "object",
            "description": "requests, humans, suspicious, bots, visitors, postViews and apiCalls",
            "additionalProperties": {
              "type": "integer"
            }
          },
          "previous": {
            "type": "object",
            "description": "requests and humans in the same length of time before",
            "additionalProperties": {
              "type": "integer"
            }
          },
          "series": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "start": {
                  "type": "string",
                  "format": "date-time"
                },
                "requests": {
                  "type": "integer"
                },
                "humans": {
                  "type": "integer"
                }
              }
            }
          },
          "pages": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "path": {
                  "type": "string"
                },
                "requests": {
                  "type": "integer"
                },
                "humans": {
                  "type": "integer"
                }
              }
            }
          },
          "posts": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "slug": {
                  "type": "string"
                },
                "title": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "humans": {
                  "type": "integer"
                }
              }
            }
          },
          "countries": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string",
                  "description": "ISO 3166-1 alpha-2"
                },
                "humans": {
                  "type": "integer"
                }
              }
            }
          },
          "statuses": {
            "type": "object",
            "description": "ok, redirect, notFound and error",
            "additionalProperties": {
              "type": "integer"
            }
          },
          "crawlers": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "requests": {
                  "type": "integer"
                },
                "verified": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "status": {
                "type": "integer"
              },
              "message": {
                "type": "string"
              }
            }
          },
          "docs": {
            "type": "string",
            "format": "uri"
          }
        }
      }
    }
  }
}
