Skip to content

Instantly share code, notes, and snippets.

@helmturner
Last active March 9, 2024 05:28
Show Gist options
  • Save helmturner/8cd1f67d54506f03f7e95e8c28bbf519 to your computer and use it in GitHub Desktop.
Save helmturner/8cd1f67d54506f03f7e95e8c28bbf519 to your computer and use it in GitHub Desktop.
Tulsa WebDevs Voting API Spec
# What is my vote if I don't vote at all? Is it a `null` vote, or is 0 the
# automatic default vote for non-voters?
# If `null` vote is the default: After I vote, but before the deadline, I can
# change my vote—including changing it to 0. Can I un-vote by setting it to `null`?
# Are vote windows limited in duration? i.e. do questions have an expiration
# (or vote-by) date? Or, is it more of a 'ranking' system where vote windows are
# unlimited in duration and a 'snapshot' of the votes is taken at some point
# (or multiple points) in time?
openapi: 3.0.0
info:
title: Voting and Proposal API
description: API for casting votes on various topics/projects and submitting and managing proposals with a ranking and voting system.
version: 2.0.0
servers:
- url: http://api.example.com/v1
description: Main production server
paths:
/topics:
get:
summary: "Get a paginated list of all topics"
parameters:
- name: cursor
in: query
required: false
schema:
type: string
format: uuid
description: "Cursor for paginating through a list of votes"
- name: limit
in: query
required: false
schema:
default: 10
type: integer
format: int32
description: "Maximum number of votes to return"
responses:
'200':
description: "OK"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Paginated'
- type: object
required:
- list
properties:
list:
type: array
items:
allOf:
- $ref: '#/components/schemas/Topic'
- $ref: '#/components/schemas/DatabaseObject'
- $ref: '#/components/schemas/TimeStamped'
'404':
description: "Not Found"
content:
application/json:
schema:
$ref: '#/components/schemas/404Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
summary: "Create a new topic"
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Topic'
- $ref: '#/components/schemas/Authored'
responses:
'201':
description: "Created"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Topic'
- $ref: '#/components/schemas/DatabaseObject'
- $ref: '#/components/schemas/TimeStamped'
'401':
description: "Unauthorized"
content:
application/json:
schema:
$ref: '#/components/schemas/401Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/topics/{id}:
summary: "Get, update, or delete a specific topic by ID"
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
description: "ID of the topic to get, update, or delete"
get:
summary: "Get a specific topic by ID"
responses:
'200':
description: "OK"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Topic'
- $ref: '#/components/schemas/DatabaseObject'
- $ref: '#/components/schemas/TimeStamped'
'404':
description: "Not Found"
content:
application/json:
schema:
$ref: '#/components/schemas/404Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
summary: "Update a specific topic by ID"
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/InitiativeData'
- $ref: '#/components/schemas/DatabaseObject'
responses:
'200':
description: "OK"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Topic'
- $ref: '#/components/schemas/DatabaseObject'
- $ref: '#/components/schemas/TimeStamped'
'401':
description: "Unauthorized"
content:
application/json:
schema:
$ref: '#/components/schemas/401Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
summary: "Delete a specific topic by ID"
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
format: uuid
responses:
'204':
description: "No Content"
'401':
description: "Unauthorized"
content:
application/json:
schema:
$ref: '#/components/schemas/401Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/topics/proposals:
get:
summary: "Get a paginated list of all proposals for topics"
parameters:
- name: cursor
in: query
required: false
schema:
type: string
format: uuid
description: "Cursor for paginating through a list of votes"
- name: limit
in: query
required: false
schema:
default: 10
type: integer
format: int32
description: "Maximum number of votes to return"
responses:
'200':
description: "OK"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Paginated'
- type: object
required:
- list
properties:
list:
type: array
items:
allOf:
- $ref: '#/components/schemas/Topic'
- $ref: '#/components/schemas/Proposal'
- $ref: '#/components/schemas/DatabaseObject'
- $ref: '#/components/schemas/TimeStamped'
'404':
description: "Not Found"
content:
application/json:
schema:
$ref: '#/components/schemas/404Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
summary: "Create a new proposal for a topic"
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Topic'
- $ref: '#/components/schemas/Proposal'
- $ref: '#/components/schemas/Authored'
responses:
'201':
description: "Created"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Topic'
- $ref: '#/components/schemas/Proposal'
- $ref: '#/components/schemas/DatabaseObject'
- $ref: '#/components/schemas/TimeStamped'
'401':
description: "Unauthorized"
content:
application/json:
schema:
$ref: '#/components/schemas/401Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/projects:
get:
summary: "Get a paginated list of all projects"
parameters:
- name: cursor
in: query
required: false
schema:
type: string
format: uuid
description: "Cursor for paginating through a list of votes"
- name: limit
in: query
required: false
schema:
default: 10
type: integer
format: int32
description: "Maximum number of votes to return"
responses:
'200':
description: "OK"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Paginated'
- type: object
required:
- list
properties:
list:
type: array
items:
allOf:
- $ref: '#/components/schemas/Project'
- $ref: '#/components/schemas/DatabaseObject'
- $ref: '#/components/schemas/TimeStamped'
'404':
description: "Not Found"
content:
application/json:
schema:
$ref: '#/components/schemas/404Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
summary: "Create a new project"
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Project'
- $ref: '#/components/schemas/Authored'
responses:
'201':
description: "Created"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Project'
- $ref: '#/components/schemas/DatabaseObject'
- $ref: '#/components/schemas/TimeStamped'
'401':
description: "Unauthorized"
content:
application/json:
schema:
$ref: '#/components/schemas/401Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/projects/{id}:
summary: "Get, update, or delete a specific project by ID"
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
description: "ID of the project to get, update, or delete"
get:
summary: "Get a specific project by ID"
responses:
'200':
description: "OK"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Project'
- $ref: '#/components/schemas/DatabaseObject'
- $ref: '#/components/schemas/TimeStamped'
'404':
description: "Not Found"
content:
application/json:
schema:
$ref: '#/components/schemas/404Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
summary: "Update a specific project by ID"
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Project'
- $ref: '#/components/schemas/DatabaseObject'
responses:
'200':
description: "OK"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Project'
- $ref: '#/components/schemas/DatabaseObject'
- $ref: '#/components/schemas/TimeStamped'
'401':
description: "Unauthorized"
content:
application/json:
schema:
$ref: '#/components/schemas/401Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
summary: "Delete a specific project by ID"
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
format: uuid
responses:
'204':
description: "No Content"
'401':
description: "Unauthorized"
content:
application/json:
schema:
$ref: '#/components/schemas/401Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/projects/proposals:
get:
summary: "Get a paginated list of all proposals for projects"
parameters:
- name: cursor
in: query
required: false
schema:
type: string
format: uuid
description: "Cursor for paginating through a list of votes"
- name: limit
in: query
required: false
schema:
default: 10
type: integer
format: int32
description: "Maximum number of votes to return"
responses:
'200':
description: "OK"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Paginated'
- type: object
required:
- list
properties:
list:
type: array
items:
allOf:
- $ref: '#/components/schemas/Project'
- $ref: '#/components/schemas/Proposal'
- $ref: '#/components/schemas/DatabaseObject'
- $ref: '#/components/schemas/TimeStamped'
'404':
description: "Not Found"
content:
application/json:
schema:
$ref: '#/components/schemas/404Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
summary: "Create a new proposal for a project"
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Project'
- $ref: '#/components/schemas/Proposal'
- $ref: '#/components/schemas/Authored'
responses:
'201':
description: "Created"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Project'
- $ref: '#/components/schemas/Proposal'
- $ref: '#/components/schemas/DatabaseObject'
- $ref: '#/components/schemas/TimeStamped'
'401':
description: "Unauthorized"
content:
application/json:
schema:
$ref: '#/components/schemas/401Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/proposals:
get:
summary: "Get a paginated list of all proposals"
parameters:
- name: cursor
in: query
required: false
schema:
type: string
format: uuid
description: "Cursor for paginating through a list of votes"
- name: limit
in: query
required: false
schema:
default: 10
type: integer
format: int32
description: "Maximum number of votes to return"
responses:
'200':
description: "OK"
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Paginated'
- type: object
required:
- list
properties:
list:
type: array
items:
allOf:
- oneOf:
- $ref: '#/components/schemas/Topic'
- $ref: '#/components/schemas/Project'
- $ref: '#/components/schemas/Proposal'
- $ref: '#/components/schemas/DatabaseObject'
- $ref: '#/components/schemas/TimeStamped'
'404':
description: "Not Found"
content:
application/json:
schema:
$ref: '#/components/schemas/404Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
summary: "Create a new proposal"
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
allOf:
- oneOf:
- $ref: '#/components/schemas/Topic'
- $ref: '#/components/schemas/Project'
- $ref: '#/components/schemas/Proposal'
- $ref: '#/components/schemas/Authored'
- type: object
required:
- type
responses:
'201':
description: "Created"
content:
application/json:
schema:
allOf:
- oneOf:
- $ref: '#/components/schemas/Topic'
- $ref: '#/components/schemas/Project'
- $ref: '#/components/schemas/Proposal'
- $ref: '#/components/schemas/DatabaseObject'
- $ref: '#/components/schemas/TimeStamped'
'401':
description: "Unauthorized"
content:
application/json:
schema:
$ref: '#/components/schemas/401Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/proposals/{id}:
summary: "Get, update, or delete a specific proposal by ID"
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
description: "ID of the proposal to get, update, or delete"
get:
summary: "Get a specific proposal by ID"
responses:
'200':
description: "OK"
content:
application/json:
schema:
allOf:
- oneOf:
- $ref: '#/components/schemas/Topic'
- $ref: '#/components/schemas/Project'
- $ref: '#/components/schemas/Proposal'
- $ref: '#/components/schemas/DatabaseObject'
- $ref: '#/components/schemas/TimeStamped'
'404':
description: "Not Found"
content:
application/json:
schema:
$ref: '#/components/schemas/404Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
summary: "Update a specific proposal by ID"
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/DatabaseObject'
- oneOf:
- $ref: '#/components/schemas/Proposal'
- $ref: '#/components/schemas/InitiativeData'
responses:
'200':
description: "OK"
content:
application/json:
schema:
allOf:
- oneOf:
- $ref: '#/components/schemas/Topic'
- $ref: '#/components/schemas/Project'
- $ref: '#/components/schemas/Proposal'
- $ref: '#/components/schemas/DatabaseObject'
- $ref: '#/components/schemas/TimeStamped'
'401':
description: "Unauthorized"
content:
application/json:
schema:
$ref: '#/components/schemas/401Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
summary: "Delete a specific proposal by ID"
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
format: uuid
responses:
'204':
description: "No Content"
'401':
description: "Unauthorized"
content:
application/json:
schema:
$ref: '#/components/schemas/401Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/proposals/{id}/votes:
summary: "Get, update, or delete votes for a specific proposal by ID"
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
description: "ID of the proposal to get, update, or delete votes for"
get:
summary: "Get the vote totals for a specific proposal by ID. If a cursor is provided, a paginated list of vote details will be returned."
parameters:
- name: cursor
in: query
required: false
schema:
type: string
format: uuid
description: "Cursor for paginating through a list of votes"
- name: limit
in: query
required: false
schema:
type: integer
format: int32
description: "Maximum number of votes to return"
responses:
'200':
description: "OK"
content:
application/json:
schema:
allOf:
- type: object
required:
- tally
properties:
tally:
description: "Total tally of all votes, including those not returned in the response"
type: integer
format: int32
votes:
allOf:
- $ref: '#/components/schemas/Paginated'
- type: object
required:
- list
properties:
list:
type: array
items:
$ref: '#/components/schemas/Vote'
'404':
description: "Not Found"
content:
application/json:
schema:
$ref: '#/components/schemas/404Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
summary: "Create or update a vote for a proposal"
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
allOf:
- $ref: '#/components/schemas/Vote'
- $ref: '#/components/schemas/Authored'
responses:
'201':
description: "Created"
content:
application/json:
schema:
$ref: '#/components/schemas/Vote'
'401':
description: "Unauthorized"
content:
application/json:
schema:
$ref: '#/components/schemas/401Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
summary: "Delete a specific vote by ID"
parameters:
- name: Authorization
in: header
required: true
schema:
type: string
format: uuid
responses:
'204':
description: "No Content"
'401':
description: "Unauthorized"
content:
application/json:
schema:
$ref: '#/components/schemas/401Error'
default:
description: "Unexpected error"
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
DatabaseObject:
type: object
required:
- id
properties:
id:
type: string
format: uuid
TimeStamped:
type: object
required:
- created
- updated
properties:
created:
type: string
format: date-time
updated:
type: string
format: date-time
InitiativeData:
type: object
properties:
title:
type: string
maxLength: 48
summary:
type: string
maxLength: 255
description:
type: string
Topic:
allOf:
- $ref: '#/components/schemas/InitiativeData'
- type: object
required:
- title
- summary
- description
properties:
type:
type: string
enum:
- topic
Project:
allOf:
- $ref: '#/components/schemas/InitiativeData'
- type: object
required:
- title
- summary
- description
properties:
type:
type: string
enum:
- project
Proposal:
type: object
required:
- status
properties:
status:
type: string
enum:
- draft
- rfc
- open
- closed
Vote:
type: object
required:
- initiativeId
- vote
properties:
initiativeId:
type: string
format: uuid
vote:
description: "Ranking values: -2 (strongly disinterested), -1 (slightly disinterested), 0 (neutral), 1 (slightly interested), 2 (strongly interested)"
type: string
enum:
- "-2"
- "-1"
- "0"
- "1"
- "2"
comment:
type: string
maxLength: 255
Authored:
type: object
required:
- authorId
- authorEmail
properties:
authorId:
type: string
format: uuid
authorName:
type: string
maxLength: 48
authorEmail:
type: string
Expirable:
type: object
required:
- expires
properties:
expires:
type: string
format: date-time
Paginated:
type: object
required:
- cursor
properties:
cursor:
type: string
format: uuid
total:
description: "Total number of items of this type in the database, if known"
type: integer
format: int32
Error:
type: object
required:
- message
properties:
message:
type: string
404Error:
allOf:
- $ref: '#/components/schemas/Error'
- type: object
properties:
message:
type: string
default: "Not Found"
401Error:
allOf:
- $ref: '#/components/schemas/Error'
- type: object
properties:
message:
type: string
default: "Unauthorized"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment