wip(backend): more OpenAPI docs
This commit is contained in:
parent
86c088f7c4
commit
53a0316b39
6 changed files with 1476 additions and 241 deletions
|
@ -1,14 +1,46 @@
|
|||
export const jwt = [{ jwt: [] }]
|
||||
export const key = [{ key: [] }]
|
||||
|
||||
export const errors = {
|
||||
accountStatusLacking:
|
||||
'The account is in a status that does not allow this action (eg: it is not active or disabled).',
|
||||
confirmationIdMissing: 'The confirmation ID was not specified in the URL',
|
||||
consentRequired: 'Consent is required to perform this action',
|
||||
dataNotAnObject: 'The `data` field in the POST body does not contain a value of type `object`',
|
||||
designMissing: 'The request lacks a `design` value the POST body',
|
||||
designNotStringy: 'The `design` field in the POST body is not of type `string`',
|
||||
emailExists: 'There is already an User account with this email address',
|
||||
emailMissing: 'The `email` field was missing from the request body',
|
||||
expiresInMissing: 'The `expiresIn` field was missing from the request body',
|
||||
expiresInNotNumeric: 'The `expiresIn` field in the request body was not a number',
|
||||
expiresIsHigherThanMaximum:
|
||||
'The `expiresIn` field in the request body is higher than allowed by the `apikeys.maxExpirySeconds` configuration',
|
||||
failedToFindConfirmationId: `The confirmation ID could not be found`,
|
||||
insufficientAccessLevel:
|
||||
'The credentials used to make this API call are insufficient for this operation.',
|
||||
invalidLevel: 'The `level` field in the request body was not a valid permission level',
|
||||
keyLevelExceedsRoleLevel:
|
||||
'The `level` field in the request body is higher than the `level` of the user creating the key. This is not allowed.',
|
||||
languageMissing: 'The `langauge` field was missing from the request body',
|
||||
levelMissing: 'The `level` field was missing from the request body',
|
||||
levelNotNumeric: 'The `level` field in the request body was a number',
|
||||
mfaActive: 'MFA is already activated on the account',
|
||||
mfaTokenMissing: 'The `token` field is missing from the request body',
|
||||
nameMissing: 'The `name` field was missing from the request body',
|
||||
passwordMissing: 'The `password` field is missing from the request body',
|
||||
personMissing: 'The request lacks a `person` value in the POST body',
|
||||
personNotNumeric: 'The `person` field in the POST body is not of type `integer`',
|
||||
postBodyMissing: 'The request lacks a POST body',
|
||||
settingsNotAnObject:
|
||||
'The `settings` field in the POST body does not contain a value of type `object`',
|
||||
unsupportedLanguageMissing: 'The `langauge` field holds a language code that we do no support',
|
||||
usernameMissing: 'The `username` field is missing from the request body',
|
||||
}
|
||||
|
||||
export const errorExamples = (errs) =>
|
||||
errs.map((err) => `\n - \`${err}\` : ${errors[err]}`).join(' ')
|
||||
|
||||
export const fields = {
|
||||
expiresIn: {
|
||||
description: `
|
||||
nds the API key will remain valid before expiring.
|
||||
igher than the \`apikeys.maxExpirySeconds\` configuration setting.`,
|
||||
type: 'number',
|
||||
example: 3600,
|
||||
},
|
||||
level: {
|
||||
description: `
|
||||
One of the [API permission
|
||||
|
@ -17,12 +49,6 @@ is an integer between (and including) \`0\` and \`8\`.`,
|
|||
type: 'number',
|
||||
example: 5,
|
||||
},
|
||||
name: {
|
||||
description: `
|
||||
The name of the API key exists solely to help you differentiate between your API keys.`,
|
||||
type: 'string',
|
||||
example: 'My first API key',
|
||||
},
|
||||
result: {
|
||||
description: 'Textual description of the result of the API call',
|
||||
type: 'string',
|
||||
|
@ -49,3 +75,429 @@ export const parameters = {
|
|||
'want to authentication with a JSON Web Token (`jwt`) or an API key (`key`)',
|
||||
},
|
||||
}
|
||||
|
||||
export const response = {
|
||||
status: {
|
||||
201: {
|
||||
description:
|
||||
'**Success - Resource created**\n\n' +
|
||||
'Status code `201` indicates that the resource was created successfully.',
|
||||
},
|
||||
204: {
|
||||
description:
|
||||
'**Success - Resource removed**\n\n' +
|
||||
'Status code `204` indicates that the resource was removed successfully.' +
|
||||
'<br>**Note:** _There is no response body for a `204` status code_.',
|
||||
},
|
||||
400: {
|
||||
description:
|
||||
'**Client error - Invalid request**\n\n' +
|
||||
'Status code `400` indicates that the request was invalid.<br>' +
|
||||
'The return body will have an `error` field which holds a string value that indicates the nature of the problem:\n\n',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
result: { ...fields.result, example: 'error' },
|
||||
error: { ...fields.error, example: 'postBodyMissing' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
401: {
|
||||
description:
|
||||
'**Unauthorized - Authentication failed**\n\n' +
|
||||
'Status code `401` indicates that the request could not be authenticated.' +
|
||||
'This typically means that authentication failed.<br>\n' +
|
||||
'**Note:** _There is no response body for a `401` status code_.',
|
||||
},
|
||||
403: {
|
||||
description:
|
||||
'**Forbidden - Permissions problem**\n\n' +
|
||||
'Status code `403` indicates that the request was forbidden.<br>' +
|
||||
'The return body will have an `error` field which can hold:\n\n',
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
result: fields.result,
|
||||
error: {
|
||||
...fields.error,
|
||||
example: 'accountStatusLacking',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
404: {
|
||||
description:
|
||||
'**Not found - Resource not found**\n\n' +
|
||||
'Status code `404` indicates that the resource could not be found.' +
|
||||
'This typically means that it does not or no longer exist.<br>' +
|
||||
'**Note:** _There is no response body for a `404` status code_.',
|
||||
},
|
||||
500: {
|
||||
description:
|
||||
'**Server error - API call failed**\n\n' +
|
||||
'Status code `500` indicates that the request could not be handled ' +
|
||||
'due to an unforseen error.',
|
||||
},
|
||||
},
|
||||
body: {
|
||||
apikey: {
|
||||
description: 'Object holding the data of the created API key',
|
||||
type: 'object',
|
||||
properties: {
|
||||
createdAt: {
|
||||
description: 'UTC Timestamp in ISO 8601 format.',
|
||||
type: 'string',
|
||||
example: '2022-12-18T17:14:30.460Z',
|
||||
},
|
||||
expiresAt: {
|
||||
description: 'UTC Timestamp in ISO 8601 format.',
|
||||
type: 'string',
|
||||
example: '2022-12-18T18:14:30.460Z',
|
||||
},
|
||||
key: {
|
||||
description: 'The _key_ part of the API key serves as the username',
|
||||
type: 'string',
|
||||
example: 'c00475bd-3002-4baa-80ad-0145cd6a646c',
|
||||
},
|
||||
level: fields.level,
|
||||
name: fields.name,
|
||||
secret: {
|
||||
description: `
|
||||
The _secret_ part of the API key serves as the password.
|
||||
It is only revealed in the response of the API key creation.`,
|
||||
type: 'string',
|
||||
example: '56b74b5dc2da7a4f37b3c9a6172e840cf4912dc37cbc55c87485f2e0abf59245',
|
||||
},
|
||||
userId: {
|
||||
description: `The unique ID of the user who owns this resource.`,
|
||||
type: 'number',
|
||||
example: 4,
|
||||
},
|
||||
},
|
||||
},
|
||||
pattern: {
|
||||
description: 'Object holding the data of the pattern',
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
description: `The Pattern's unique ID`,
|
||||
type: 'integer',
|
||||
example: 666,
|
||||
},
|
||||
createdAt: {
|
||||
description: 'Timestamp of when the Pattern was created, in ISO 8601 format.',
|
||||
type: 'string',
|
||||
example: '2022-12-18T18:14:30.460Z',
|
||||
},
|
||||
data: {
|
||||
description: `Additional data for the Pattern`,
|
||||
type: 'object',
|
||||
},
|
||||
design: {
|
||||
description: `Name of the design this Pattern is an instance of`,
|
||||
type: 'string',
|
||||
example: 'aaron',
|
||||
},
|
||||
img: {
|
||||
description: `An image [data-uri](https://en.wikipedia.org/wiki/Data_URI_scheme) to store with this pattern`,
|
||||
type: 'string',
|
||||
example: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEU...truncated',
|
||||
},
|
||||
name: {
|
||||
description: `The name of the Pattern exists solely to help you differentiate between your patterns.`,
|
||||
type: 'string',
|
||||
example: 'My favourite shirt',
|
||||
},
|
||||
notes: {
|
||||
description: `Any notes to be stored with the pattern`,
|
||||
type: 'string',
|
||||
example: 'These are my notes. I can keep them alongside the pattern. Handy!',
|
||||
},
|
||||
personId: {
|
||||
description: `The unique ID of the Person this pattern was drafted for`,
|
||||
type: 'integer',
|
||||
example: 33,
|
||||
},
|
||||
public: {
|
||||
description: `Whether or not this pattern can be viewed/used by others`,
|
||||
type: 'boolean',
|
||||
example: false,
|
||||
},
|
||||
settings: {
|
||||
description: `The settings used to draft/render this pattern`,
|
||||
type: 'object',
|
||||
example: { sa: 30 },
|
||||
},
|
||||
userId: {
|
||||
description: `The unique ID of the User who created this pattern`,
|
||||
type: 'integer',
|
||||
example: 66,
|
||||
},
|
||||
updatedAt: {
|
||||
description: 'Timestamp of when the Pattern was last updated, in ISO 8601 format.',
|
||||
type: 'string',
|
||||
example: '2022-12-18T18:14:30.460Z',
|
||||
},
|
||||
},
|
||||
},
|
||||
person: {
|
||||
description: 'Object holding the data of the person',
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: {
|
||||
description: `The Person's unique ID`,
|
||||
type: 'integer',
|
||||
example: 666,
|
||||
},
|
||||
createdAt: {
|
||||
description: 'Timestamp of when the Person was created, in ISO 8601 format.',
|
||||
type: 'string',
|
||||
example: '2022-12-18T18:14:30.460Z',
|
||||
},
|
||||
img: {
|
||||
description: `An image that was stored with this person`,
|
||||
type: 'string',
|
||||
example: 'https://freesewing.org/avatar.svg',
|
||||
},
|
||||
imperial: {
|
||||
description: `Whether or not to use imperial units for this person`,
|
||||
type: 'boolean',
|
||||
example: false,
|
||||
},
|
||||
name: {
|
||||
description: `The name of the Person exists solely to help you differentiate between your people.`,
|
||||
type: 'string',
|
||||
example: 'My bestie Ronda',
|
||||
},
|
||||
notes: {
|
||||
description: `Any notes to be stored with the person`,
|
||||
type: 'string',
|
||||
example: 'These are my notes. I can keep them alongside the person. Handy!',
|
||||
},
|
||||
public: {
|
||||
description: `Whether or not this pattern can be viewed/used by others`,
|
||||
type: 'boolean',
|
||||
example: false,
|
||||
},
|
||||
measies: {
|
||||
description: `The measurements for this person`,
|
||||
type: 'object',
|
||||
example: { neck: 420 },
|
||||
},
|
||||
userId: {
|
||||
description: `The unique ID of the User who created this pattern`,
|
||||
type: 'integer',
|
||||
example: 66,
|
||||
},
|
||||
updatedAt: {
|
||||
description: 'Timestamp of when the Pattern was last updated, in ISO 8601 format.',
|
||||
type: 'string',
|
||||
example: '2022-12-18T18:14:30.460Z',
|
||||
},
|
||||
},
|
||||
},
|
||||
userAccount: {
|
||||
description: 'Object holding the data of the user',
|
||||
type: 'object',
|
||||
properties: {
|
||||
/*
|
||||
apikeys Apikey[]
|
||||
confirmations Confirmation[]
|
||||
ehash String @unique
|
||||
ihash String
|
||||
patterns Pattern[]
|
||||
people Person[]
|
||||
*/
|
||||
id: {
|
||||
description: `The User's unique ID`,
|
||||
type: 'integer',
|
||||
example: 666,
|
||||
},
|
||||
bio: {
|
||||
description: `The bio is the information about the user that they want to make available to others`,
|
||||
type: 'text',
|
||||
example: `I make clothes and shoes. I design sewing patterns. I write code. I run http://freesewing.org
|
||||
|
||||
我也在学中文
|
||||
|
||||
Also: Introvert 🙊
|
||||
|
||||
(he/him) or (they/them)`,
|
||||
},
|
||||
consent: {
|
||||
description: `This field is about data protection. It indicates the level of consent the user has given to process their data.
|
||||
- \`0\`: No consent given
|
||||
- \`1\`: Consent given to process account data
|
||||
- \`2\`: Consent given to process account data and person data
|
||||
- \`3\`: Consent given to process account data and person data, and use anonymized data for research
|
||||
`,
|
||||
type: 'integer',
|
||||
enum: [0, 1, 2, 3],
|
||||
example: 3,
|
||||
},
|
||||
control: {
|
||||
description: `This field is about keeping it simple. It indicates the level of control the user wants over the user experience.
|
||||
- \`1\`: Hide all but the most crucial features. Make it as simple as possible.
|
||||
- \`2\`: Hide the majority of features. Make it simple, but not too much.
|
||||
- \`3\`: Reveal the majority of features, but not all. Balance simplicity with power.
|
||||
- \`4\`: Reveal everything, but keep handrails and safety checks. Only intervene when I’m about to do something dangerous.
|
||||
- \`5\`: Reveal everything, remove the handrails and safety checks. Get out of my way, I know what I’m doing.
|
||||
`,
|
||||
type: 'integer',
|
||||
example: 4,
|
||||
enum: [1, 2, 3, 4, 5],
|
||||
},
|
||||
createdAt: {
|
||||
description: 'Timestamp of when the User was created, in ISO 8601 format.',
|
||||
type: 'string',
|
||||
example: '2022-12-18T18:14:30.460Z',
|
||||
},
|
||||
email: {
|
||||
description: `The email address of the User`,
|
||||
type: 'string',
|
||||
example: 'joost@joost.at',
|
||||
},
|
||||
github: {
|
||||
description: `The github username of the User`,
|
||||
type: 'string',
|
||||
example: 'joostdecock',
|
||||
},
|
||||
img: {
|
||||
description: `An image that was stored with this person`,
|
||||
type: 'string',
|
||||
example: 'https://freesewing.org/avatar.svg',
|
||||
},
|
||||
imperial: {
|
||||
description: `Whether or not to use imperial units for this user`,
|
||||
type: 'boolean',
|
||||
example: false,
|
||||
},
|
||||
initial: {
|
||||
description: `The email address this User account was registered with`,
|
||||
type: 'string',
|
||||
example: 'joost@decock.org',
|
||||
},
|
||||
language: {
|
||||
description: `Language code of the language preferred by the user`,
|
||||
type: 'string',
|
||||
example: 'en',
|
||||
enum: ['en', 'es', 'de', 'fr', 'nl'],
|
||||
},
|
||||
lastLogin: {
|
||||
description: 'Timestamp of when the User last authenticated, in ISO 8601 format.',
|
||||
type: 'string',
|
||||
example: '2022-12-18T18:14:30.460Z',
|
||||
},
|
||||
lusername: {
|
||||
description: `A lowercased version of the user's username`,
|
||||
type: 'string',
|
||||
example: 'joostdecock',
|
||||
},
|
||||
mfaEnabled: {
|
||||
description: `Whether or not multi-factor authentication (MFA) is enabled for this user`,
|
||||
type: 'boolean',
|
||||
example: 'true',
|
||||
},
|
||||
newsletter: {
|
||||
description: `Whether or not this user is subscribed to the newsletter (via the account subscription feature)`,
|
||||
type: 'boolean',
|
||||
example: 'false',
|
||||
},
|
||||
patron: {
|
||||
description: `The patron tier of the user`,
|
||||
type: 'integer',
|
||||
example: 8,
|
||||
enum: [0, 2, 4, 8],
|
||||
},
|
||||
role: {
|
||||
description: `The role of the user`,
|
||||
type: 'string',
|
||||
example: 'user',
|
||||
enum: ['user', 'bughunter', 'support', 'admin'],
|
||||
},
|
||||
patron: {
|
||||
description: `The status of the user's account
|
||||
- \`0\`: The account is not active (yet)
|
||||
- \`1\`: The account is active
|
||||
- \`-1\`: The account was disabled by the user
|
||||
- \`-2\`: The account was administratively disabled
|
||||
`,
|
||||
type: 'integer',
|
||||
example: 8,
|
||||
enum: [0, 1, -1, -2],
|
||||
},
|
||||
updatedAt: {
|
||||
description: 'Timestamp of when the User was last updated, in ISO 8601 format.',
|
||||
type: 'string',
|
||||
example: '2022-12-18T18:14:30.460Z',
|
||||
},
|
||||
username: {
|
||||
description: `The User's username`,
|
||||
type: 'string',
|
||||
example: 'JoostDeCock',
|
||||
},
|
||||
},
|
||||
},
|
||||
userProfile: {
|
||||
description: 'Object holding the profile of the user',
|
||||
type: 'object',
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
response.body.userProfile.properties = { ...response.body.userAccount.properties }
|
||||
for (const remove of [
|
||||
'consent',
|
||||
'control',
|
||||
'createdAt',
|
||||
'email',
|
||||
'github',
|
||||
'initial',
|
||||
'lastLogin',
|
||||
'lusername',
|
||||
'mfaEnabled',
|
||||
'newsletter',
|
||||
'updatedAd',
|
||||
])
|
||||
delete response.body.userProfile.properties[remove]
|
||||
|
||||
export const uploadImg = {
|
||||
description: `An image [data-uri](https://en.wikipedia.org/wiki/Data_URI_scheme) to store with this resource`,
|
||||
type: 'string',
|
||||
example: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEU...truncated',
|
||||
}
|
||||
|
||||
export const token = {
|
||||
description: `A JWT token`,
|
||||
type: 'string',
|
||||
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ...truncated',
|
||||
}
|
||||
|
||||
// Schemas
|
||||
export const schemas = {
|
||||
apikey: response.body.apikey,
|
||||
pattern: response.body.pattern,
|
||||
person: response.body.person,
|
||||
userAccount: response.body.userAccount,
|
||||
userProfile: response.body.userProfile,
|
||||
}
|
||||
|
||||
export const jsonResponse = (properties) => ({
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue