Add an OpenAPI description and some overrides for debug builds to test locally

The CORS stuff allows for testing against the API with swagger-editor on my
machine but is not strictly necessary.

The `dredd.yml` is for use with Dredd (`npm i dredd`) and doesn't _currently_
pass muster
This commit is contained in:
R Tyler Croy 2020-09-20 20:29:48 -07:00
parent 43cae8a372
commit 1ce8bee5a8
3 changed files with 268 additions and 0 deletions

210
api-description.yml Normal file
View File

@ -0,0 +1,210 @@
---
swagger: "2.0"
info:
description: |
Dot dot vote!
version: "1.0.0"
title: Dot dot vote
contact:
email: "rtyler+dotdotvote@brokenco.de"
license:
name: "LGPL v3.0"
url: "https://www.gnu.org/licenses/lgpl-3.0.en.html"
host: "localhost:8000"
basePath: "/api/v1"
tags:
- name: "poll"
description: Poll manipulation APIs
externalDocs:
description: "Find out more"
url: "http://swagger.io"
schemes:
- "http"
- "https"
paths:
/polls:
put:
tags:
- "poll"
summary: "Create a new poll"
description: "Create a new poll"
operationId: "createPoll"
consumes:
- "application/json"
produces:
- "application/json"
parameters:
- in: "body"
name: "body"
description: |
Insertable Poll object that must be provided in order to actually create the poll.
required: true
schema:
$ref: "#/definitions/InsertablePoll"
responses:
'201':
description: |
Poll created successfully
schema:
type: 'object'
properties:
poll:
type: string
description: 'A UUID for the generated poll'
example: '8497479a-9f07-4530-9a5c-2824238d5975'
"422":
description: |
Invalid JSON supplied
'500':
description: |
Some server side error has occurred.
'/polls/{uuid}':
get:
tags:
- poll
summary: 'Fetch the details of the given poll'
description: |
Access the Poll details and metadata, but _not_ the results
parameters:
- in: path
name: uuid
required: true
type: string
format: uuid
responses:
200:
description: Poll found
schema:
$ref: '#/definitions/PollResponse'
400:
description: |
Either the UUID parameter wasn't provided or it did not parse as a legitimate UUIDv4
404:
description: |
Poll not found
'/polls/{uuid}/vote':
post:
tags:
- poll
summary: 'Vote in the specified poll'
parameters:
- in: path
name: uuid
required: true
type: string
format: uuid
responses:
200:
description: Vote submitted
400:
description: |
Either the UUID parameter wasn't provided or it did not parse as a legitimate UUIDv4
404:
description: |
Poll not found
'/polls/{uuid}/results':
get:
tags:
- poll
summary: 'Fetch the results for the specified poll'
parameters:
- in: path
name: uuid
required: true
type: string
format: uuid
responses:
200:
description: Poll found
schema:
$ref: '#/definitions/PollResults'
400:
description: |
Either the UUID parameter wasn't provided or it did not parse as a legitimate UUIDv4
404:
description: |
Poll not found
definitions:
PollResponse:
type: object
properties:
poll:
$ref: '#/definitions/RawPoll'
choices:
type: array
items:
$ref: '#/definitions/RawChoice'
PollResults:
type: object
properties:
poll:
$ref: '#/definitions/RawPoll'
choices:
type: array
items:
$ref: '#/definitions/RawChoice'
votes:
type: array
items:
$ref: '#/definitions/RawVote'
RawPoll:
type: object
properties:
id:
type: number
format: int32
uuid:
type: string
format: uuid
title:
type: string
created_at:
type: string
format: date-time
RawChoice:
type: object
properties:
id:
type: number
format: int32
poll_id:
type: number
format: int32
details:
type: string
created_at:
type: string
format: date-time
RawVote:
type: object
properties:
id:
type: number
format: int32
poll_id:
type: number
format: int32
choice_id:
type: number
format: int32
dots:
type: number
format: in32
voter:
type: string
created_at:
type: string
format: date-time
InsertablePoll:
type: "object"
properties:
title:
type: "string"
example: 'My amazing poll!'
choices:
type: "array"
items:
type: "string"
example: 'Choice 1'

32
dredd.yml Normal file
View File

@ -0,0 +1,32 @@
color: true
header: true
dry-run: null
hookfiles: null
language: nodejs
require: null
server: cargo run
server-wait: 3
init: false
custom: {}
names: false
only: []
reporter: []
output: []
sorted: false
user: null
inline-errors: false
details: false
method: []
loglevel: warning
path: []
hooks-worker-timeout: 5000
hooks-worker-connect-timeout: 1500
hooks-worker-connect-retry: 500
hooks-worker-after-connect-wait: 100
hooks-worker-term-timeout: 5000
hooks-worker-term-retry: 500
hooks-worker-handler-host: 127.0.0.1
hooks-worker-handler-port: 61321
config: ./dredd.yml
blueprint: api-description.yml
endpoint: 'http://localhost:8000'

View File

@ -55,6 +55,18 @@ mod dao {
}
impl Poll {
/*
pub async fn create(title: &str, tx: &mut (impl sqlx::Connection + Copy + sqlx::executor::RefExecutor<'_>)) -> Result<Poll, sqlx::Error> {
sqlx::query_as!(Poll,
"INSERT INTO polls (title, uuid) VALUES ($1, $2) RETURNING *",
title,
Uuid::new_v4()
)
.fetch_one(tx)
.await
}
*/
pub async fn from_uuid(uuid: uuid::Uuid, db: &crate::DbPool) -> Result<Poll, sqlx::Error> {
sqlx::query_as!(Poll, "SELECT * FROM polls WHERE uuid = $1", uuid)
.fetch_one(db)
@ -343,6 +355,20 @@ async fn main() -> Result<(), std::io::Error> {
Ok(db) => {
let state = AppState { db };
let mut app = tide::with_state(state);
#[cfg(debug_assertions)]
{
info!("Enabling a very liberal CORS policy for debug purposes");
use tide::security::{CorsMiddleware, Origin};
let cors = CorsMiddleware::new()
.allow_methods("GET, POST, PUT, OPTIONS".parse::<tide::http::headers::HeaderValue>().unwrap())
.allow_origin(Origin::from("*"))
.allow_credentials(false);
app.with(cors);
}
debug!("Configuring routes");
app.at("/").get(routes::index);
app.at("/api/v1/polls").put(routes::polls::create);
app.at("/api/v1/polls/:uuid").get(routes::polls::get);