diff --git a/scripts/openapi-codegen/bun.lockb b/scripts/openapi-codegen/bun.lockb new file mode 100755 index 0000000..de970fa Binary files /dev/null and b/scripts/openapi-codegen/bun.lockb differ diff --git a/scripts/openapi-codegen/package.json b/scripts/openapi-codegen/package.json new file mode 100644 index 0000000..9b19d7d --- /dev/null +++ b/scripts/openapi-codegen/package.json @@ -0,0 +1,16 @@ +{ + "name": "openapi-codegen", + "module": "src/app.ts", + "type": "module", + "scripts": { + "start": "openapi-typescript src/openapi/openapi.json --output src/openapi/openapi.ts && bun src/app.ts" + }, + "devDependencies": { + "bun-types": "latest", + "openapi-typescript": "^6.7.3", + "typescript": "^5.3.3" + }, + "peerDependencies": { + "typescript": "^5.0.0" + } +} diff --git a/scripts/openapi-codegen/src/app.ts b/scripts/openapi-codegen/src/app.ts new file mode 100644 index 0000000..0255634 --- /dev/null +++ b/scripts/openapi-codegen/src/app.ts @@ -0,0 +1,371 @@ +import * as ts from 'typescript' +import * as fs from 'fs/promises' +import { join } from 'path' + +import apidocs from './openapi/openapi.json' + +type EndpointData = { + meta: { + methodName: string + controller: string + } + + method: 'get' | 'post' | 'put' | 'delete' + path: string + + query?: { [index: string | number | symbol]: string } + pathVariables?: { [index: string | number | symbol]: string } + body?: { + required: boolean + type: string + } + response?: string +} + +const apiBaseURL = apidocs.servers[0].url +const interfaceNames = Object.keys(apidocs.components.schemas) + +const outputDirectory = join('dist', 'api') +const outputModelsFile = 'models.ts' +const outputEndpointsFile = 'endpoints.ts' +const outputIndexFile = 'index.ts' + +const inputFilePath = 'src/openapi/openapi.ts' +const program = ts.createProgram([inputFilePath], {}) + +const source = program.getSourceFile(inputFilePath) +let outputBuffer = '' + +async function writeBufferToFile(file: string) { + try { + await fs.mkdir(outputDirectory, { recursive: true }) + } catch (_) { + /* Directory already exists */ + } + await fs.writeFile(join(outputDirectory, file), outputBuffer) + outputBuffer = '' +} + +function convertValue(type: string): string { + if (type === 'integer') return 'number' + return type +} + +function parseSchema(value: any): string { + // { type: "type or array or undefined", $ref: "undefined or points to schema", items: "present when type=array, presumably has type or ref" } + if (value.oneOf) + return value.oneOf.map(({ $ref }: { $ref: string }) => parse$Ref($ref)).join(' | ') + if (value.enum && value.type === 'string') + return value.enum.map((value: string) => `'${value}'`).join(' | ') + if (value.items && value.type !== 'array') return parseSchema(value.items) + if (value.type === 'array') { + if (value.items.type) return convertValue(value.items.type) + '[]' + return parseSchema(value.items).replaceAll(/(\w+)/g, '$1[]') + } + + return convertValue(value.type) ?? parse$Ref(value.$ref) +} + +function parse$Ref(value: string): string { + return value?.replace('#/components/schemas/', '') +} + +function bufferModels() { + outputBuffer = 'export type WithRequired = T & { [P in K]-?: T[P] }\n' + + const componentsInterface = source!.statements.find( + (statement) => + ts.isInterfaceDeclaration(statement) && + statement.name && + statement.name.text === 'components', + ) as ts.InterfaceDeclaration | undefined + if (componentsInterface) { + const schemasProperty = componentsInterface.members.find( + (statement) => + ts.isPropertySignature(statement) && statement.name?.getText(source) === 'schemas', + ) as ts.PropertySignature | undefined + if (schemasProperty) { + schemasProperty.forEachChild((node) => { + if (ts.isTypeLiteralNode(node)) { + node.forEachChild((node) => { + const components = node.getText(source).split(':') + const name = components.shift() + const declaration = components + .join(':') + .trim() + .replace(/components\["schemas"\]\["(\w+)"\]/gi, '$1') + .replaceAll(/ {2,}/g, ' ') + .replaceAll(/^ \}/gm, '}') + const type = `export type ${name} = ${declaration}`.replaceAll(';', '') + outputBuffer += `\n${type}\n` + }) + } + }) + } + } +} + +function bufferEndpoints() { + outputBuffer = `import {\n` + interfaceNames.forEach((name) => (outputBuffer += ` ${name},\n`)) + outputBuffer += `} from './models'\n\n` + outputBuffer += `type Fetch = (input: URL | RequestInfo, init?: RequestInit) => Promise\n\n` + + outputBuffer += `export const BASE_URL = '${apiBaseURL}'\n\n` + + outputBuffer += `function resolveURL(url: URL, { query, path }: { query?: {[index: string]: any}, path?: {[index: string]: any}}): string {\n` + outputBuffer += ` let resolvedURL = url.toString()\n` + outputBuffer += ` \n` + outputBuffer += ` if (path) {\n` + outputBuffer += ` for (const [key, value] of Object.entries(path)) {\n` + outputBuffer += ` const variablePattern = new RegExp(\`{\s*\${key}\s*}\`, 'g')\n` + outputBuffer += ` resolvedURL = resolvedURL.replace(variablePattern, value)\n` + outputBuffer += ` }\n` + outputBuffer += ` }\n` + outputBuffer += `\n` + outputBuffer += ` if (query) {\n` + outputBuffer += ` const searchParams = new URLSearchParams(query)\n` + outputBuffer += ` const queryString = searchParams.toString()\n` + outputBuffer += `\n` + outputBuffer += ` if (queryString) {\n` + outputBuffer += ` resolvedURL += resolvedURL.includes('?') ? \`&\${queryString}\` : \`?\${queryString}\`\n` + outputBuffer += ` }\n` + outputBuffer += ` }\n` + outputBuffer += `\n` + outputBuffer += ` return resolvedURL\n` + outputBuffer += `}\n\n` + + const endpoints = getEndpoints() + const endpointMethods = endpoints.map(createEndpointMethod) + endpointMethods.forEach((method) => (outputBuffer += method + '\n\n')) +} + +function getEndpoints(): EndpointData[] { + const endpoints = [] + for (const path in apidocs.paths) { + // @ts-expect-error typescript for whatever reason does not recognize path as a valid key of apidocs.paths + const allOperations = apidocs.paths[path] + for (const httpMethod in allOperations) { + const details = allOperations[httpMethod] + const query = (details.parameters?.filter((parameter: any) => parameter.in === 'query') ?? + []) as any[] + const pathVariables = (details.parameters?.filter( + (parameter: any) => parameter.in === 'path', + ) ?? []) as any[] + const hasBody = !!details.requestBody + + const endpoint = { + meta: { + methodName: details.operationId, + controller: details.tags[0], + }, + method: httpMethod, + path, + } as any + + if (query.length > 0) { + endpoint.query = {} + query.forEach((parameter) => { + endpoint.query[`${parameter.name}${parameter.required ? '' : '?'}`] = parseSchema( + parameter.schema, + ) + }) + } + + if (pathVariables.length > 0) { + endpoint.pathVariables = {} + pathVariables.forEach((parameter) => { + endpoint.pathVariables[`${parameter.name}${parameter.required ? '' : '?'}`] = parseSchema( + parameter.schema, + ) + }) + } + + if (hasBody) { + endpoint.body = { + type: parseSchema(details.requestBody.content['application/json'].schema), + required: details.requestBody.required, + } + } + + if (details.responses['200'].content) { + endpoint.response = parseSchema(details.responses['200'].content['*/*'].schema) + } + + endpoints.push(endpoint) + } + } + return endpoints +} + +const tsStringify = ( + obj: { [index: string | number | symbol]: any }, + addWhitespace = false, + indentCount = 2, +): string => { + const transform = JSON.stringify( + obj, + null, + addWhitespace ? ''.padStart(indentCount, ' ') : undefined, + ) + .replaceAll('"', '') + .replaceAll(':', ': ') + .replaceAll(',', ', ') + .replace(/^}$/m, '}'.padStart(indentCount - 1, ' ')) + if (!addWhitespace) return transform.replace(/^{/m, '{ ').replace(/}$/m, ' }') + return transform +} + +function createFunctionSignature(endpoint: EndpointData): string[] { + const hasQuery = 'query' in endpoint + const hasVariables = 'pathVariables' in endpoint + const hasBody = 'body' in endpoint + + const sum: number = [hasQuery, hasVariables, hasBody] + .map((truthy) => (truthy ? 1 : 0) as number) + .reduce((acc: number, next) => acc + next) + + let fnArguments: string[] = [] + + if (sum === 1) { + if (hasQuery) + fnArguments.push( + ' query: ' + tsStringify(endpoint.query!, Object.keys(endpoint.query!).length > 2, 4), + ) + if (hasVariables) + fnArguments.push( + ' path: ' + + tsStringify(endpoint.pathVariables!, Object.keys(endpoint.pathVariables!).length > 2, 4), + ) + if (hasBody) + fnArguments.push(` body${endpoint.body!.required ? '' : '?'}: ` + endpoint.body!.type) + } else if (sum > 1) { + fnArguments.push( + ' { ' + + [hasQuery ? 'query' : null, hasVariables ? 'path' : null, hasBody ? 'body' : null] + .filter((x) => !!x) + .join(', ') + + ' }: {', + ) + + if (hasQuery) { + const typedef = + Object.keys(endpoint.query!).length > 1 + ? tsStringify(endpoint.query!, true, 6).split('\n') + : [tsStringify(endpoint.query!)] + fnArguments.push(' query: ' + typedef.shift() + (typedef.length > 0 ? '' : ', ')) + if (typedef.length > 0) + typedef.forEach((line, index) => + fnArguments.push(line + (index === typedef.length - 1 ? ', ' : '')), + ) + } + + if (hasVariables) { + const typedef = + Object.keys(endpoint.pathVariables!).length > 1 + ? tsStringify(endpoint.pathVariables!, true, 6).split('\n') + : [tsStringify(endpoint.pathVariables!)] + fnArguments.push( + ' path: ' + typedef.shift() + (typedef.length === 0 && hasBody ? ', ' : ''), + ) + if (typedef.length > 0) + typedef.forEach((line, index) => + fnArguments.push(line + (index === typedef.length - 1 && hasBody ? ', ' : '')), + ) + } + + if (hasBody) { + fnArguments.push(` body${endpoint.body!.required ? '' : '?'}: ` + endpoint.body!.type) + } + + fnArguments.push(' }') + } + + return [ + `export async function ${endpoint.meta.methodName}(`, + ' fetch: Fetch,', + ...fnArguments, + `): Promise<${endpoint?.response ? endpoint.response + ' | undefined' : 'void'}> {`, + ] +} + +function createEndpointMethod(endpoint: EndpointData) { + const hasQuery = 'query' in endpoint + const hasVariables = 'pathVariables' in endpoint + const hasBody = 'body' in endpoint + + const functionSignature = createFunctionSignature(endpoint) + const pathOptions = + hasQuery && hasVariables + ? `{ query, path }` + : hasQuery + ? `{ query }` + : hasVariables + ? `{ path }` + : null + + const declareURL = !!pathOptions + ? [ + `const url = resolveURL(`, + ` new URL('${endpoint.path}', BASE_URL),`, + ` ${pathOptions},`, + `)`, + ] + : [`const url = new URL('${endpoint.path}', BASE_URL).toString()`] + + return [ + ...functionSignature, + ...declareURL.map((text) => ` ${text}`), + ` const options: RequestInit = {`, + ` method: '${endpoint.method}',`, + ` headers: { 'Content-Type': 'application/json' },`, + endpoint.body && endpoint.body.required ? ` body: JSON.stringify(body),` : null, + ` }`, + ...(endpoint.body && !endpoint.body.required + ? ['', ` if(body) options.body = JSON.stringify(body)`] + : [null]), + '', + ` try {`, + ` const response = await fetch(url, options)`, + ` if (!response.ok)`, + ` throw new Error(\`Request failed with status: \${ response.status }\`)`, + endpoint.response ? ` return await response.json() as ${endpoint.response}` : ` return`, + ` } catch(error) {`, + ...(hasBody && endpoint.body!.required + ? [ + ` console.error(\`received error while fetching url("\${ url }") with data(\${ JSON.stringify(body) })\`, error)`, + ] + : hasBody + ? [ + ` if(body) console.error(\`received error while fetching url("\${ url }") with data(\${ JSON.stringify(body) })\`, error)`, + ` else console.error(\`received error while fetching url: \${ url }\`, error)`, + ] + : [` console.error(\`received error while fetching url: \${ url }\`, error)`]), + ` return undefined`, + ` }`, + `}`, + ] + .filter((x) => x !== null) + .join('\n') +} + +function bufferIndex() { + outputBuffer = `export * from './models' +export * from './endpoints' +` +} + +if (source) { + bufferModels() + await writeBufferToFile(outputModelsFile) + + bufferEndpoints() + await writeBufferToFile(outputEndpointsFile) + + bufferIndex() + await writeBufferToFile(outputIndexFile) + + console.log(`Finished Processing`) +} else { + console.error(`Error: Source file ${inputFilePath} not found.`) +} diff --git a/scripts/openapi-codegen/src/openapi/openapi.json b/scripts/openapi-codegen/src/openapi/openapi.json new file mode 100644 index 0000000..25426f8 --- /dev/null +++ b/scripts/openapi-codegen/src/openapi/openapi.json @@ -0,0 +1,1368 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenAPI definition", + "version": "v0" + }, + "servers": [ + { + "url": "http://localhost:8080", + "description": "Generated server url" + } + ], + "paths": { + "/updateShipment": { + "put": { + "tags": ["shipment-controller"], + "operationId": "updateShipment", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Shipment" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/Shipment" + } + } + } + } + } + } + }, + "/updateRecipient": { + "put": { + "tags": ["recipient-controller"], + "operationId": "updateRecipient", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Recipient" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/Recipient" + } + } + } + } + } + } + }, + "/updateFacility": { + "put": { + "tags": ["facility-controller"], + "operationId": "updateFacility", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Facility" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/Facility" + } + } + } + } + } + } + }, + "/updateContent": { + "put": { + "tags": ["package-content-controller"], + "operationId": "updateContent", + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/Book" + }, + { + "$ref": "#/components/schemas/Zine" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/Book" + }, + { + "$ref": "#/components/schemas/Zine" + } + ] + } + } + } + } + } + } + }, + "/addSpecialRequest": { + "post": { + "tags": ["special-request-controller"], + "operationId": "addSpecialRequest", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SpecialRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/SpecialRequest" + } + } + } + } + } + } + }, + "/addShipment": { + "post": { + "tags": ["shipment-controller"], + "operationId": "addShipment", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Shipment" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/Shipment" + } + } + } + } + } + } + }, + "/addRecipient": { + "post": { + "tags": ["recipient-controller"], + "operationId": "addRecipient", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Recipient" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/Recipient" + } + } + } + } + } + } + }, + "/addNote": { + "post": { + "tags": ["note-controller"], + "operationId": "addNote", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Note" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/Note" + } + } + } + } + } + } + }, + "/addFacility": { + "post": { + "tags": ["facility-controller"], + "operationId": "addFacility", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Facility" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/Facility" + } + } + } + } + } + } + }, + "/addContent": { + "post": { + "tags": ["package-content-controller"], + "operationId": "addContent", + "requestBody": { + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/Book" + }, + { + "$ref": "#/components/schemas/Zine" + } + ] + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/Book" + }, + { + "$ref": "#/components/schemas/Zine" + } + ] + } + } + } + } + } + } + }, + "/searchBooks": { + "get": { + "tags": ["package-content-controller"], + "operationId": "searchBooksByTitleAndAuthor", + "parameters": [ + { + "name": "title", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "author", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Book" + } + } + } + } + } + } + } + }, + "/queryGoogle": { + "get": { + "tags": ["package-content-controller"], + "operationId": "queryGoogleByTitleAndAuthor", + "parameters": [ + { + "name": "title", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "author", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Book" + } + } + } + } + } + } + } + }, + "/getZineByCode": { + "get": { + "tags": ["package-content-controller"], + "operationId": "getZineByCode", + "parameters": [ + { + "name": "code", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/Zine" + } + } + } + } + } + } + }, + "/getShipmentsByDate": { + "get": { + "tags": ["shipment-controller"], + "operationId": "getShipmentsByDate", + "parameters": [ + { + "name": "date", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Shipment" + } + } + } + } + } + } + } + }, + "/getShipment": { + "get": { + "tags": ["shipment-controller"], + "operationId": "getShipment", + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/Shipment" + } + } + } + } + } + } + }, + "/getShipmentCountBetweenDates": { + "get": { + "tags": ["shipment-controller"], + "operationId": "getShipmentCountBetweenDates", + "parameters": [ + { + "name": "date1", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "date2", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "integer", + "format": "int64" + } + } + } + } + } + } + }, + "/getRecipients": { + "get": { + "tags": ["recipient-controller"], + "operationId": "getRecipients", + "parameters": [ + { + "name": "firstName", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "lastName", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Recipient" + } + } + } + } + } + } + } + }, + "/getRecipient": { + "get": { + "tags": ["recipient-controller"], + "operationId": "getRecipient", + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/Recipient" + } + } + } + } + } + } + }, + "/getRecipientLocation": { + "get": { + "tags": ["recipient-controller"], + "operationId": "getRecipientLocation", + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/getRecipientByAssignedId": { + "get": { + "tags": ["recipient-controller"], + "operationId": "getRecipientByAssignedId", + "parameters": [ + { + "name": "assignedId", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/Recipient" + } + } + } + } + } + } + }, + "/getNoIsbnBooks": { + "get": { + "tags": ["package-content-controller"], + "operationId": "getBooksWithNoIsbn", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Book" + } + } + } + } + } + } + } + }, + "/getFacility": { + "get": { + "tags": ["facility-controller"], + "operationId": "getFacilityById", + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/Facility" + } + } + } + } + } + } + }, + "/getFacilityByName": { + "get": { + "tags": ["facility-controller"], + "operationId": "getFacilityByNameAndState", + "parameters": [ + { + "name": "name", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "state", + "in": "query", + "required": true, + "schema": { + "type": "string", + "enum": ["NC", "AL", "TN", "WV", "KY", "MD", "VA", "DE"] + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Facility" + } + } + } + } + } + } + } + }, + "/getContent": { + "get": { + "tags": ["package-content-controller"], + "operationId": "getContent", + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/Book" + }, + { + "$ref": "#/components/schemas/Zine" + } + ] + } + } + } + } + } + } + }, + "/getContentByTitle": { + "get": { + "tags": ["package-content-controller"], + "operationId": "getContentByTitle", + "parameters": [ + { + "name": "title", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/Book" + }, + { + "$ref": "#/components/schemas/Zine" + } + ] + } + } + } + } + } + } + } + }, + "/getBookByISBN": { + "get": { + "tags": ["package-content-controller"], + "operationId": "getBookByISBN", + "parameters": [ + { + "name": "isbn", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/Book" + } + } + } + } + } + } + }, + "/getAllZines": { + "get": { + "tags": ["package-content-controller"], + "operationId": "getAllZines", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Zine" + } + } + } + } + } + } + } + }, + "/getAllSpecialRequests": { + "get": { + "tags": ["special-request-controller"], + "operationId": "getAllSpecialRequests", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpecialRequest" + } + } + } + } + } + } + } + }, + "/getAllShipmentsByRecipient": { + "get": { + "tags": ["shipment-controller"], + "operationId": "getAllShipmentsByRecipient", + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Shipment" + } + } + } + } + } + } + } + }, + "/getAllRecipients": { + "get": { + "tags": ["recipient-controller"], + "operationId": "getAllRecipients", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Recipient" + } + } + } + } + } + } + } + }, + "/getAllFacilities": { + "get": { + "tags": ["facility-controller"], + "operationId": "getAllFacilities", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Facility" + } + } + } + } + } + } + } + }, + "/getAllContent": { + "get": { + "tags": ["package-content-controller"], + "operationId": "getAllContent", + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/Book" + }, + { + "$ref": "#/components/schemas/Zine" + } + ] + } + } + } + } + } + } + } + }, + "/content": { + "get": { + "tags": ["package-content-controller"], + "operationId": "getContentByTitleAndAuthor", + "parameters": [ + { + "name": "title", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "author", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "*/*": { + "schema": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/Book" + }, + { + "$ref": "#/components/schemas/Zine" + } + ] + } + } + } + } + } + } + } + }, + "/deleteShipment": { + "delete": { + "tags": ["shipment-controller"], + "operationId": "deleteShipment", + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/deleteRecipient": { + "delete": { + "tags": ["recipient-controller"], + "operationId": "deleteRecipient", + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/deleteFacility": { + "delete": { + "tags": ["facility-controller"], + "operationId": "deleteFacility", + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/deleteContent": { + "delete": { + "tags": ["package-content-controller"], + "operationId": "deleteContent", + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, + "/deleteAllShipmentsByRecipientId": { + "delete": { + "tags": ["shipment-controller"], + "operationId": "deleteShipmentsByRecipient", + "parameters": [ + { + "name": "id", + "in": "query", + "required": true, + "schema": { + "type": "integer", + "format": "int64" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + } + }, + "components": { + "schemas": { + "Book": { + "required": ["title"], + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/PackageContent" + }, + { + "type": "object", + "properties": { + "authors": { + "type": "string" + }, + "isbn10": { + "type": "string" + }, + "isbn13": { + "type": "string" + } + } + } + ] + }, + "Facility": { + "required": ["city", "name", "state", "street", "zip"], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "name": { + "type": "string" + }, + "additionalInfo": { + "type": "string" + }, + "street": { + "type": "string" + }, + "city": { + "type": "string" + }, + "state": { + "type": "string", + "enum": ["NC", "AL", "TN", "WV", "KY", "MD", "VA", "DE"] + }, + "zip": { + "type": "string" + } + } + }, + "Note": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "content": { + "type": "string" + }, + "date": { + "type": "string", + "format": "date" + } + } + }, + "PackageContent": { + "required": ["title", "type"], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "title": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "discriminator": { + "propertyName": "type" + } + }, + "Recipient": { + "required": ["firstName", "lastName"], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "firstName": { + "type": "string" + }, + "middleName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "assignedId": { + "type": "string" + }, + "facility": { + "$ref": "#/components/schemas/Facility" + }, + "shipments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Shipment" + } + }, + "specialRequests": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SpecialRequest" + } + } + } + }, + "Shipment": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "date": { + "type": "string", + "format": "date" + }, + "facility": { + "$ref": "#/components/schemas/Facility" + }, + "recipient": { + "$ref": "#/components/schemas/Recipient" + }, + "notes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Note" + } + }, + "content": { + "uniqueItems": true, + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/Book" + }, + { + "$ref": "#/components/schemas/Zine" + } + ] + } + } + } + }, + "SpecialRequest": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int64" + }, + "volunteerName": { + "type": "string" + }, + "request": { + "type": "string" + }, + "specialRequestDate": { + "type": "string", + "format": "date" + }, + "letterMailedDate": { + "type": "string", + "format": "date" + }, + "category": { + "type": "string", + "enum": [ + "VOCATIONAL", + "EDUCATIONAL", + "CAREER_GROWTH", + "FOREIGN_LANGUAGE", + "LEGAL", + "SPIRITUAL_RELIGIOUS", + "OTHER" + ] + }, + "status": { + "type": "string", + "enum": ["OPEN", "COMPLETED", "CANCELLED"] + }, + "recipient": { + "$ref": "#/components/schemas/Recipient" + } + } + }, + "Zine": { + "required": ["code", "title"], + "type": "object", + "allOf": [ + { + "$ref": "#/components/schemas/PackageContent" + }, + { + "type": "object", + "properties": { + "code": { + "type": "string" + } + } + } + ] + } + } + } +} diff --git a/scripts/openapi-codegen/src/openapi/openapi.ts b/scripts/openapi-codegen/src/openapi/openapi.ts new file mode 100644 index 0000000..0e4f2c3 --- /dev/null +++ b/scripts/openapi-codegen/src/openapi/openapi.ts @@ -0,0 +1,764 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ + +/** WithRequired type helpers */ +type WithRequired = T & { [P in K]-?: T[P] } + +export interface paths { + '/updateShipment': { + put: operations['updateShipment'] + } + '/updateRecipient': { + put: operations['updateRecipient'] + } + '/updateFacility': { + put: operations['updateFacility'] + } + '/updateContent': { + put: operations['updateContent'] + } + '/addSpecialRequest': { + post: operations['addSpecialRequest'] + } + '/addShipment': { + post: operations['addShipment'] + } + '/addRecipient': { + post: operations['addRecipient'] + } + '/addNote': { + post: operations['addNote'] + } + '/addFacility': { + post: operations['addFacility'] + } + '/addContent': { + post: operations['addContent'] + } + '/searchBooks': { + get: operations['searchBooksByTitleAndAuthor'] + } + '/queryGoogle': { + get: operations['queryGoogleByTitleAndAuthor'] + } + '/getZineByCode': { + get: operations['getZineByCode'] + } + '/getShipmentsByDate': { + get: operations['getShipmentsByDate'] + } + '/getShipment': { + get: operations['getShipment'] + } + '/getShipmentCountBetweenDates': { + get: operations['getShipmentCountBetweenDates'] + } + '/getRecipients': { + get: operations['getRecipients'] + } + '/getRecipient': { + get: operations['getRecipient'] + } + '/getRecipientLocation': { + get: operations['getRecipientLocation'] + } + '/getRecipientByAssignedId': { + get: operations['getRecipientByAssignedId'] + } + '/getNoIsbnBooks': { + get: operations['getBooksWithNoIsbn'] + } + '/getFacility': { + get: operations['getFacilityById'] + } + '/getFacilityByName': { + get: operations['getFacilityByNameAndState'] + } + '/getContent': { + get: operations['getContent'] + } + '/getContentByTitle': { + get: operations['getContentByTitle'] + } + '/getBookByISBN': { + get: operations['getBookByISBN'] + } + '/getAllZines': { + get: operations['getAllZines'] + } + '/getAllSpecialRequests': { + get: operations['getAllSpecialRequests'] + } + '/getAllShipmentsByRecipient': { + get: operations['getAllShipmentsByRecipient'] + } + '/getAllRecipients': { + get: operations['getAllRecipients'] + } + '/getAllFacilities': { + get: operations['getAllFacilities'] + } + '/getAllContent': { + get: operations['getAllContent'] + } + '/content': { + get: operations['getContentByTitleAndAuthor'] + } + '/deleteShipment': { + delete: operations['deleteShipment'] + } + '/deleteRecipient': { + delete: operations['deleteRecipient'] + } + '/deleteFacility': { + delete: operations['deleteFacility'] + } + '/deleteContent': { + delete: operations['deleteContent'] + } + '/deleteAllShipmentsByRecipientId': { + delete: operations['deleteShipmentsByRecipient'] + } +} + +export type webhooks = Record + +export interface components { + schemas: { + Book: WithRequired< + { + type: 'Book' + } & Omit & { + authors?: string + isbn10?: string + isbn13?: string + }, + 'title' + > + Facility: { + /** Format: int64 */ + id?: number + name: string + additionalInfo?: string + street: string + city: string + /** @enum {string} */ + state: 'NC' | 'AL' | 'TN' | 'WV' | 'KY' | 'MD' | 'VA' | 'DE' + zip: string + } + Note: { + /** Format: int64 */ + id?: number + content?: string + /** Format: date */ + date?: string + } + PackageContent: { + /** Format: int64 */ + id?: number + title: string + type: string + } + Recipient: { + /** Format: int64 */ + id?: number + firstName: string + middleName?: string + lastName: string + assignedId?: string + facility?: components['schemas']['Facility'] + shipments?: components['schemas']['Shipment'][] + specialRequests?: components['schemas']['SpecialRequest'][] + } + Shipment: { + /** Format: int64 */ + id?: number + /** Format: date */ + date?: string + facility?: components['schemas']['Facility'] + recipient?: components['schemas']['Recipient'] + notes?: components['schemas']['Note'][] + content?: (components['schemas']['Book'] | components['schemas']['Zine'])[] + } + SpecialRequest: { + /** Format: int64 */ + id?: number + volunteerName?: string + request?: string + /** Format: date */ + specialRequestDate?: string + /** Format: date */ + letterMailedDate?: string + /** @enum {string} */ + category?: + | 'VOCATIONAL' + | 'EDUCATIONAL' + | 'CAREER_GROWTH' + | 'FOREIGN_LANGUAGE' + | 'LEGAL' + | 'SPIRITUAL_RELIGIOUS' + | 'OTHER' + /** @enum {string} */ + status?: 'OPEN' | 'COMPLETED' | 'CANCELLED' + recipient?: components['schemas']['Recipient'] + } + Zine: WithRequired< + { + type: 'Zine' + } & Omit & { + code?: string + }, + 'code' | 'title' + > + } + responses: never + parameters: never + requestBodies: never + headers: never + pathItems: never +} + +export type $defs = Record + +export type external = Record + +export interface operations { + updateShipment: { + requestBody: { + content: { + 'application/json': components['schemas']['Shipment'] + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Shipment'] + } + } + } + } + updateRecipient: { + requestBody: { + content: { + 'application/json': components['schemas']['Recipient'] + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Recipient'] + } + } + } + } + updateFacility: { + requestBody: { + content: { + 'application/json': components['schemas']['Facility'] + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Facility'] + } + } + } + } + updateContent: { + requestBody: { + content: { + 'application/json': components['schemas']['Book'] | components['schemas']['Zine'] + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Book'] | components['schemas']['Zine'] + } + } + } + } + addSpecialRequest: { + requestBody: { + content: { + 'application/json': components['schemas']['SpecialRequest'] + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['SpecialRequest'] + } + } + } + } + addShipment: { + requestBody: { + content: { + 'application/json': components['schemas']['Shipment'] + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Shipment'] + } + } + } + } + addRecipient: { + requestBody: { + content: { + 'application/json': components['schemas']['Recipient'] + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Recipient'] + } + } + } + } + addNote: { + requestBody: { + content: { + 'application/json': components['schemas']['Note'] + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Note'] + } + } + } + } + addFacility: { + requestBody: { + content: { + 'application/json': components['schemas']['Facility'] + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Facility'] + } + } + } + } + addContent: { + requestBody: { + content: { + 'application/json': components['schemas']['Book'] | components['schemas']['Zine'] + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Book'] | components['schemas']['Zine'] + } + } + } + } + searchBooksByTitleAndAuthor: { + parameters: { + query: { + title: string + author?: string + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Book'][] + } + } + } + } + queryGoogleByTitleAndAuthor: { + parameters: { + query: { + title: string + author?: string + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Book'][] + } + } + } + } + getZineByCode: { + parameters: { + query: { + code: string + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Zine'] + } + } + } + } + getShipmentsByDate: { + parameters: { + query: { + date: string + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Shipment'][] + } + } + } + } + getShipment: { + parameters: { + query: { + id: number + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Shipment'] + } + } + } + } + getShipmentCountBetweenDates: { + parameters: { + query: { + date1: string + date2: string + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': number + } + } + } + } + getRecipients: { + parameters: { + query: { + firstName: string + lastName: string + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Recipient'][] + } + } + } + } + getRecipient: { + parameters: { + query: { + id: number + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Recipient'] + } + } + } + } + getRecipientLocation: { + parameters: { + query: { + id: string + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': string + } + } + } + } + getRecipientByAssignedId: { + parameters: { + query: { + assignedId: string + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Recipient'] + } + } + } + } + getBooksWithNoIsbn: { + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Book'][] + } + } + } + } + getFacilityById: { + parameters: { + query: { + id: number + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Facility'] + } + } + } + } + getFacilityByNameAndState: { + parameters: { + query: { + name: string + state: 'NC' | 'AL' | 'TN' | 'WV' | 'KY' | 'MD' | 'VA' | 'DE' + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Facility'][] + } + } + } + } + getContent: { + parameters: { + query: { + id: number + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Book'] | components['schemas']['Zine'] + } + } + } + } + getContentByTitle: { + parameters: { + query: { + title: string + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': (components['schemas']['Book'] | components['schemas']['Zine'])[] + } + } + } + } + getBookByISBN: { + parameters: { + query: { + isbn: string + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Book'] + } + } + } + } + getAllZines: { + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Zine'][] + } + } + } + } + getAllSpecialRequests: { + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['SpecialRequest'][] + } + } + } + } + getAllShipmentsByRecipient: { + parameters: { + query: { + id: number + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Shipment'][] + } + } + } + } + getAllRecipients: { + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Recipient'][] + } + } + } + } + getAllFacilities: { + responses: { + /** @description OK */ + 200: { + content: { + '*/*': components['schemas']['Facility'][] + } + } + } + } + getAllContent: { + responses: { + /** @description OK */ + 200: { + content: { + '*/*': (components['schemas']['Book'] | components['schemas']['Zine'])[] + } + } + } + } + getContentByTitleAndAuthor: { + parameters: { + query: { + title: string + author?: string + } + } + responses: { + /** @description OK */ + 200: { + content: { + '*/*': (components['schemas']['Book'] | components['schemas']['Zine'])[] + } + } + } + } + deleteShipment: { + parameters: { + query: { + id: number + } + } + responses: { + /** @description OK */ + 200: { + content: never + } + } + } + deleteRecipient: { + parameters: { + query: { + id: number + } + } + responses: { + /** @description OK */ + 200: { + content: never + } + } + } + deleteFacility: { + parameters: { + query: { + id: number + } + } + responses: { + /** @description OK */ + 200: { + content: never + } + } + } + deleteContent: { + parameters: { + query: { + id: number + } + } + responses: { + /** @description OK */ + 200: { + content: never + } + } + } + deleteShipmentsByRecipient: { + parameters: { + query: { + id: number + } + } + responses: { + /** @description OK */ + 200: { + content: never + } + } + } +}