openapi: '3.0.2'
info:
  version: 0.0.5
  title: 日本の学校情報API
  description: |
    - https://school.teraren.com/ にて提供している学校情報に関するAPIの仕様書
  license:
    name: This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
  contact:
    name: Yuki Matsukura
    url: https://x.com/matsubokkuri
servers:
  - url: https://school.teraren.com
    description: Production
paths:
  /schools.json:
    get:
      summary: 学校一覧
      operationId: getSchools
      description: Schoolの配列を取得。クエリパラメータで絞り込み可能。
      tags:
        - School
      parameters:
        - name: s
          in: query
          description: キーワード検索（学校名・住所・学校コードの部分一致）
          required: false
          schema:
            type: string
        - name: prefecture_number
          in: query
          description: 都道府県コード（2桁）で絞り込み
          required: false
          schema:
            type: string
            example: '13'
        - name: school_type
          in: query
          description: 学校種コードで絞り込み（A1=幼稚園, B1=小学校, C1=中学校, D1=高等学校 など）
          required: false
          schema:
            type: string
            example: 'B1'
        - name: establishment_category
          in: query
          description: 設置区分で絞り込み（1=国立, 2=公立, 3=私立 など）
          required: false
          schema:
            type: integer
            example: 2
        - name: main_branch_indicator
          in: query
          description: 本校・分校区分で絞り込み
          required: false
          schema:
            type: integer
        - name: active
          in: query
          description: trueにすると廃校（attribute_info_cancellation_dateあり）を除外
          required: false
          schema:
            type: boolean
        - name: page
          in: query
          description: ページ番号（1ページあたり最大50件）
          required: false
          schema:
            type: integer
            default: 1
      responses:
        '200':
          description: A paged array of School
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/School'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /stats.json:
    get:
      summary: 統計サマリー
      operationId: getStats
      description: |
        収録されている全学校データの集計結果。
        全体KPI、都道府県別、学校種別、設置区分、ランキング、本校/分校、
        過去30年の時系列、都道府県×学校種ヒートマップを返します。
        月次同期に応じて結果がキャッシュされます。
      tags:
        - Stats
      responses:
        '200':
          description: 統計サマリー
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Stats'
  /changes.json:
    get:
      summary: 直近の変動
      operationId: getChanges
      description: |
        指定したウィンドウ（30/90/365日）以内に新設、廃校、またはコード移行が
        行われた学校を返します。`attribute_info_setup_date`、
        `attribute_info_cancellation_date`、`post_transition_school_code` を基に判定。
      tags:
        - Changes
      parameters:
        - name: window
          in: query
          description: ウィンドウ日数。30/90/365 のいずれか。それ以外は90にフォールバック
          required: false
          schema:
            type: integer
            enum: [30, 90, 365]
            default: 90
      responses:
        '200':
          description: 期間内の変動
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Changes'
  /schools/{code}.json:
    get:
      summary: 学校オブジェクトを取得
      operationId: getSchool
      description: Schoolを取得
      tags:
        - School
      parameters:
        - schema:
            type: string
            default: 1
          name: pref_code
          in: path
          description: 学校コード
          required: true
          example: 'F113110102700'
      responses:
        '200':
          description: Expected response to a valid request
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/School'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'




components:
  schemas:
    School:
      title: School
      type: object
      xml:
        name: School
      x-tags:
        - School
      description: 学校
      properties:
        code:
          type: string
          description: 学校コード
          example: F113110102700
        school_type:
          type: string
          description: 学校種別
          example: 'F1'
        prefecture_number:
          type: integer
          description: 都道府県番号
          example: 13
        establishment_category:
          type: integer
          description: 設置区分ド
          example: 13
        main_branch_indicator:
          type: integer
          description: 本分校
          example: 13
        location:
          type: string
          description: 学校所在地
          example: '東京都文京区本郷７－３－１'
        "postal_code":
          type: string
          description: 郵便番号
          example: '1130033'
        attribute_info_setup_date:
          type: string
          format: date
          description:  属性情報設定年月日
          example: '2021-01-20'
        attribute_info_cancellation_date:
          type: string
          format: date
          description: 属性情報廃止年月日
          example: '2021-01-20'
        old_school_survey_number:
          type: string
          format: date
          description: 旧学校調査番号
          example: '0172'
        post_transition_school_code:
          type: string
          format: date
          description: 移行後の学校コード
          example: 'A201333300016'
        url:
          type: string
          description: エンティティのURL
          example: "https://school.teraren.com/schools/F113110102700.json"
        created_at:
          type: string
          format: date-time
          example: '2021-10-15T12:13:26.433+09:00'
        updated_at:
          type: string
          format: date-time
          example: '2021-10-15T12:13:26.433+09:00'
        _links:
          $ref: '#/components/schemas/SchoolLinks'

    SchoolLinks:
      type: object
      description: |
        HATEOAS リンク。各キーは関連リソースへのナビゲーション先を href で持つ。
        `self` と `collection` は常に含まれる。`prefecture`, `school_type`,
        `establishment_category`, `main_branch_indicator` は対応する属性が
        存在すれば含まれる。`post_transition_school` は移行後コードがある場合のみ。
      properties:
        self:
          $ref: '#/components/schemas/HalLink'
        collection:
          $ref: '#/components/schemas/HalLink'
        prefecture:
          $ref: '#/components/schemas/HalLink'
        school_type:
          $ref: '#/components/schemas/HalLink'
        establishment_category:
          $ref: '#/components/schemas/HalLink'
        main_branch_indicator:
          $ref: '#/components/schemas/HalLink'
        post_transition_school:
          $ref: '#/components/schemas/HalLink'

    HalLink:
      type: object
      required: [href]
      properties:
        href:
          type: string
          format: uri
          example: 'https://school.teraren.com/prefectures/13.json'

    Error:
      title: Error
      type: object
      description: A standard error object.
      x-tags:
        - common
      properties:
        code:
          type: string
        message:
          type: string
      required:
        - code
        - message
      x-examples:
        サーバエラー:
          code: '500'
          message: サーバサイドのエラー

    Stats:
      type: object
      description: /stats.json レスポンス
      required: [last_synced_at, totals, by_prefecture, by_school_type, by_establishment_category, cross_school_type_x_establishment, rankings, main_branch_breakdown, time_series, heatmap]
      properties:
        last_synced_at:
          type: string
          format: date-time
        totals:
          type: object
          properties:
            schools_total: { type: integer }
            schools_active: { type: integer }
            schools_abolished: { type: integer }
            prefectures_count: { type: integer }
            school_types_count: { type: integer }
        by_prefecture:
          type: array
          items:
            type: object
            properties:
              prefecture_number: { type: string }
              prefecture_name: { type: string, nullable: true }
              total: { type: integer }
              active: { type: integer }
              abolished: { type: integer }
        by_school_type:
          type: array
          items:
            type: object
            properties:
              school_type: { type: string }
              school_type_name: { type: string, nullable: true }
              total: { type: integer }
              active: { type: integer }
              abolished: { type: integer }
        by_establishment_category:
          type: array
          items:
            type: object
            properties:
              establishment_category: { type: integer }
              name: { type: string, nullable: true }
              total: { type: integer }
              share: { type: number, format: float }
        cross_school_type_x_establishment:
          type: array
          items:
            type: object
            properties:
              school_type: { type: string }
              counts:
                type: array
                items:
                  type: object
                  properties:
                    establishment_category: { type: integer }
                    count: { type: integer }
        rankings:
          type: object
          properties:
            top_by_total: { type: array, items: { $ref: '#/components/schemas/RankingEntry' } }
            top_by_private_ratio: { type: array, items: { $ref: '#/components/schemas/RankingEntry' } }
            top_by_abolished: { type: array, items: { $ref: '#/components/schemas/RankingEntry' } }
        main_branch_breakdown:
          type: object
          properties:
            main: { type: integer }
            branch: { type: integer }
            other: { type: integer }
        time_series:
          type: array
          items:
            type: object
            properties:
              year: { type: integer }
              opened: { type: integer }
              closed: { type: integer }
        heatmap:
          type: object
          properties:
            prefectures:
              type: array
              items:
                type: object
                properties:
                  code: { type: string }
                  name: { type: string, nullable: true }
            school_types:
              type: array
              items: { type: string }
            counts:
              type: array
              items:
                type: array
                items: { type: integer }

    RankingEntry:
      type: object
      properties:
        prefecture_number: { type: string }
        prefecture_name: { type: string, nullable: true }
        value: { type: number }

    Changes:
      type: object
      description: /changes.json レスポンス
      required: [generated_at, window_days, newly_added, abolished, code_transitions]
      properties:
        generated_at: { type: string, format: date-time }
        window_days: { type: integer, enum: [30, 90, 365] }
        newly_added:
          type: array
          items:
            type: object
            properties:
              code: { type: string }
              name: { type: string }
              prefecture_number: { type: string }
              school_type: { type: string }
              attribute_info_setup_date: { type: string, format: date }
        abolished:
          type: array
          items:
            type: object
            properties:
              code: { type: string }
              name: { type: string }
              prefecture_number: { type: string }
              school_type: { type: string }
              attribute_info_cancellation_date: { type: string, format: date }
        code_transitions:
          type: array
          items:
            type: object
            properties:
              code: { type: string }
              name: { type: string }
              post_transition_school_code: { type: string }
              updated_at: { type: string, format: date-time }

