Created
May 12, 2024 23:07
-
-
Save helmturner/2f0c98a090c8ca819b80d7a65551b189 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
{ | |
"openapi": "3.1.0", | |
"info": { | |
"title": "Tulsa WebDevs Voting Service", | |
"description": "API for casting votes on various topics/projects and submitting and managing proposals with a ranking and voting system.", | |
"version": "0.0.2" | |
}, | |
"servers": [ | |
{ | |
"url": "http://vote.tulsawebdevs. org", | |
"description": "Voting Service API" | |
}, | |
{ | |
"url": "http://localhost:8080", | |
"description": "Local development server" | |
} | |
], | |
"paths": { | |
"/drafts": { | |
"summary": "Manage the current user's proposal drafts", | |
"parameters": [ | |
{ "$ref": "#/components/parameters/AuthorizationRequired" } | |
], | |
"get": { | |
"operationId": "listDrafts", | |
"summary": "Get a list of the current user's drafts with pagination, filtering, and sorting", | |
"parameters": [ | |
{ "$ref": "#/components/parameters/PaginationParams" }, | |
{ "$ref": "#/components/parameters/ProposalTypeFilter" } | |
], | |
"responses": { | |
"200": { | |
"description": "OK", | |
"content": { | |
"application/json": { | |
"schema": { "$ref": "#/components/schemas/DraftIndex" } | |
} | |
} | |
}, | |
"401": { "$ref": "#/components/responses/401" }, | |
"404": { "$ref": "#/components/responses/404" }, | |
"default": { "$ref": "#/components/responses/500" } | |
} | |
}, | |
"post": { | |
"summary": "Create a new draft", | |
"requestBody": { | |
"required": true, | |
"content": { | |
"application/json": { | |
"schema": { "$ref": "#/components/schemas/Draft" } | |
} | |
} | |
}, | |
"responses": { | |
"201": { | |
"description": "Created", | |
"content": { | |
"application/json": { | |
"schema": { | |
"allOf": [ | |
{ "$ref": "#/components/schemas/Draft" }, | |
{ "$ref": "#/components/schemas/DatabaseObject" } | |
] | |
} | |
} | |
} | |
}, | |
"401": { "$ref": "#/components/responses/401" }, | |
"default": { "$ref": "#/components/responses/500" } | |
} | |
}, | |
"put": { | |
"summary": "Replace an existing draft", | |
"parameters": [{ "$ref": "#/components/parameters/RecordId" }], | |
"requestBody": { | |
"required": true, | |
"content": { | |
"application/json": { | |
"schema": { "$ref": "#/components/schemas/Draft" } | |
} | |
} | |
}, | |
"responses": { | |
"200": { | |
"description": "OK", | |
"content": { | |
"application/json": { | |
"schema": { | |
"allOf": [ | |
{ "$ref": "#/components/schemas/Draft" }, | |
{ "$ref": "#/components/schemas/DatabaseObject" } | |
] | |
} | |
} | |
} | |
}, | |
"401": { "$ref": "#/components/responses/401" }, | |
"404": { "$ref": "#/components/responses/404" }, | |
"default": { "$ref": "#/components/responses/500" } | |
} | |
}, | |
"patch": { | |
"summary": "Update an existing draft", | |
"parameters": [{ "$ref": "#/components/parameters/RecordId" }], | |
"requestBody": { | |
"required": true, | |
"content": { | |
"application/json": { | |
"schema": { "$ref": "#/components/schemas/Draft" } | |
} | |
} | |
}, | |
"responses": { | |
"200": { | |
"description": "OK", | |
"content": { | |
"application/json": { | |
"schema": { | |
"allOf": [ | |
{ "$ref": "#/components/schemas/Draft" }, | |
{ "$ref": "#/components/schemas/DatabaseObject" } | |
] | |
} | |
} | |
} | |
}, | |
"401": { "$ref": "#/components/responses/401" }, | |
"404": { "$ref": "#/components/responses/404" }, | |
"default": { "$ref": "#/components/responses/500" } | |
} | |
}, | |
"delete": { | |
"summary": "Delete a draft by ID", | |
"parameters": [{ "$ref": "#/components/parameters/RecordId" }], | |
"responses": { | |
"204": { "description": "No Content" }, | |
"401": { "$ref": "#/components/responses/401" }, | |
"404": { "$ref": "#/components/responses/404" }, | |
"default": { "$ref": "#/components/responses/500" } | |
} | |
} | |
}, | |
"/proposals": { | |
"summary": "Create or list proposals", | |
"get": { | |
"summary": "Get a list of the proposals with pagination, filtering, and sorting", | |
"parameters": [ | |
{ "$ref": "#/components/parameters/AuthorizationOptional" }, | |
{ "$ref": "#/components/parameters/PaginationParams" }, | |
{ "$ref": "#/components/parameters/ProposalTypeFilter" }, | |
{ "$ref": "#/components/parameters/ProposalStatusFilter" } | |
], | |
"responses": { | |
"200": { | |
"description": "OK", | |
"content": { | |
"application/json": { | |
"schema": { "$ref": "#/components/schemas/ProposalIndex" } | |
} | |
} | |
}, | |
"404": { "$ref": "#/components/responses/404" }, | |
"default": { "$ref": "#/components/responses/500" } | |
} | |
}, | |
"post": { | |
"summary": "Create a new proposal", | |
"parameters": [ | |
{ "$ref": "#/components/parameters/AuthorizationRequired" } | |
], | |
"requestBody": { | |
"required": true, | |
"content": { | |
"application/json": { | |
"schema": { "$ref": "#/components/schemas/Proposal" } | |
} | |
} | |
}, | |
"responses": { | |
"201": { | |
"description": "Created", | |
"content": { | |
"application/json": { | |
"schema": { | |
"allOf": [ | |
{ "$ref": "#/components/schemas/Proposal" }, | |
{ "$ref": "#/components/schemas/ProposalState" }, | |
{ "$ref": "#/components/schemas/DatabaseObject" } | |
] | |
} | |
} | |
} | |
}, | |
"401": { "$ref": "#/components/responses/401" }, | |
"default": { "$ref": "#/components/responses/500" } | |
} | |
} | |
}, | |
"/{recordId}": { | |
"summary": "Manage a user's vote on a proposal", | |
"parameters": [ | |
{ "$ref": "#/components/parameters/AuthorizationRequired" }, | |
{ "$ref": "#/components/parameters/RecordId" } | |
], | |
"post": { | |
"summary": "Submit (or update) a vote on a proposal", | |
"requestBody": { | |
"required": true, | |
"content": { | |
"application/json": { | |
"schema": { "$ref": "#/components/schemas/Vote" } | |
} | |
} | |
}, | |
"responses": { | |
"201": { | |
"description": "Created", | |
"content": { | |
"application/json": { | |
"schema": { | |
"allOf": [ | |
{ "$ref": "#/components/schemas/Vote" }, | |
{ "$ref": "#/components/schemas/DatabaseObject" } | |
] | |
} | |
} | |
} | |
}, | |
"401": { "$ref": "#/components/responses/401" }, | |
"default": { "$ref": "#/components/responses/500" } | |
} | |
}, | |
"delete": { | |
"summary": "Delete a user's proposal vote", | |
"responses": { | |
"204": { "description": "No Content" }, | |
"401": { "$ref": "#/components/responses/401" }, | |
"404": { "$ref": "#/components/responses/404" }, | |
"default": { "$ref": "#/components/responses/500" } | |
} | |
} | |
} | |
}, | |
"components": { | |
"parameters": { | |
"PaginationParams": { | |
"name": "pagination", | |
"in": "query", | |
"required": false, | |
"schema": { "$ref": "#/components/schemas/Paginated" } | |
}, | |
"ProposalTypeFilter": { | |
"name": "type", | |
"in": "query", | |
"required": false, | |
"schema": { | |
"type": "string", | |
"enum": ["topic", "project"] | |
}, | |
"description": "Filter items by type" | |
}, | |
"ProposalStatusFilter": { | |
"name": "status", | |
"in": "query", | |
"required": false, | |
"schema": { | |
"type": "string", | |
"enum": ["open", "closed"] | |
}, | |
"description": "Filter items by status" | |
}, | |
"AuthorizationRequired": { | |
"name": "Authorization", | |
"in": "header", | |
"required": true, | |
"schema": { | |
"type": "string" | |
} | |
}, | |
"AuthorizationOptional": { | |
"name": "Authorization", | |
"in": "header", | |
"required": false, | |
"schema": { | |
"type": "string" | |
} | |
}, | |
"RecordId": { | |
"name": "recordId", | |
"in": "query", | |
"required": true, | |
"description": "ID of the record to get, update, or delete", | |
"schema": { | |
"type": "integer", | |
"format": "int32" | |
} | |
} | |
}, | |
"responses": { | |
"401": { | |
"description": "Unauthorized", | |
"content": { | |
"application/json": { | |
"schema": { "$ref": "#/components/schemas/Error" } | |
} | |
} | |
}, | |
"404": { | |
"description": "Not Found", | |
"content": { | |
"application/json": { | |
"schema": { "$ref": "#/components/schemas/Error" } | |
} | |
} | |
}, | |
"500": { | |
"description": "Internal Server Error", | |
"content": { | |
"application/json": { | |
"schema": { "$ref": "#/components/schemas/Error" } | |
} | |
} | |
} | |
}, | |
"schemas": { | |
"DatabaseObject": { | |
"type": "object", | |
"required": ["id", "created"], | |
"properties": { | |
"id": { | |
"type": "integer", | |
"format": "int32" | |
}, | |
"created": { | |
"type": "string", | |
"format": "date-time" | |
}, | |
"updated": { | |
"type": "string", | |
"format": "date-time" | |
} | |
} | |
}, | |
"Draft": { | |
"type": "object", | |
"properties": { | |
"title": { | |
"type": "string", | |
"maxLength": 48 | |
}, | |
"summary": { | |
"type": "string", | |
"maxLength": 255 | |
}, | |
"description": { | |
"type": "string", | |
"maxLength": 2048 | |
}, | |
"type": { | |
"type": "string", | |
"enum": ["topic", "project"] | |
} | |
} | |
}, | |
"DraftIndex": { | |
"allOf": [ | |
{ "$ref": "#/components/schemas/Paginated" }, | |
{ | |
"type": "object", | |
"required": ["drafts"], | |
"properties": { | |
"drafts": { | |
"type": "array", | |
"items": { | |
"allOf": [ | |
{ "$ref": "#/components/schemas/Draft" }, | |
{ "$ref": "#/components/schemas/DatabaseObject" } | |
] | |
} | |
} | |
} | |
} | |
] | |
}, | |
"Proposal": { | |
"allOf": [ | |
{ "$ref": "#/components/schemas/Draft" }, | |
{ | |
"type": "object", | |
"required": ["type", "title", "summary"], | |
"properties": { | |
"title": { | |
"type": "string", | |
"minLength": 8 | |
}, | |
"summary": { | |
"type": "string", | |
"minLength": 30 | |
} | |
} | |
} | |
] | |
}, | |
"ProposalState": { | |
"oneOf": [ | |
{ | |
"type": "object", | |
"required": ["status", "results", "authorName"], | |
"properties": { | |
"authorName": { "type": "string" }, | |
"status": { "type": "string", "enum": ["closed"] }, | |
"userVote": { "$ref": "#/components/schemas/Vote" }, | |
"results": { | |
"type": "array", | |
"items": { "$ref": "#/components/schemas/Vote" } | |
} | |
} | |
}, | |
{ | |
"type": "object", | |
"required": ["status", "authorName"], | |
"properties": { | |
"authorName": { "type": "string", "minLength": 4 }, | |
"status": { "type": "string", "enum": ["open"] }, | |
"userVote": { "$ref": "#/components/schemas/Vote" } | |
} | |
} | |
] | |
}, | |
"ProposalIndex": { | |
"allOf": [ | |
{ "$ref": "#/components/schemas/Paginated" }, | |
{ | |
"type": "object", | |
"required": ["proposals"], | |
"properties": { | |
"proposals": { | |
"type": "array", | |
"items": { | |
"allOf": [ | |
{ "$ref": "#/components/schemas/Proposal" }, | |
{ "$ref": "#/components/schemas/ProposalState" }, | |
{ "$ref": "#/components/schemas/DatabaseObject" } | |
] | |
} | |
} | |
} | |
} | |
] | |
}, | |
"Vote": { | |
"type": "object", | |
"required": ["value"], | |
"properties": { | |
"value": { | |
"description": "Ranking values: -2 (strong disinterest), -1 (slight disinterest), 0 (neutral), 1 (slight interest), 2 (strong interest)", | |
"type": "string", | |
"enum": ["-2", "-1", "0", "1", "2"] | |
}, | |
"comment": { | |
"type": "string", | |
"maxLength": 255 | |
} | |
} | |
}, | |
"Expirable": { | |
"type": "object", | |
"required": ["expires"], | |
"properties": { | |
"expires": { | |
"type": "string", | |
"format": "date-time" | |
} | |
} | |
}, | |
"Paginated": { | |
"type": "object", | |
"description": "Controls pagination of results", | |
"properties": { | |
"cursor": { | |
"description": "Cursor for paginating through a list of items", | |
"type": "integer", | |
"format": "int32" | |
}, | |
"limit": { | |
"description": "In a request, the maximum number of items to return. In a response, the total number of items available, if known.", | |
"type": "integer", | |
"format": "int32" | |
} | |
} | |
}, | |
"Error": { | |
"type": "object", | |
"required": ["message"], | |
"properties": { | |
"message": { | |
"type": "string" | |
} | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment