@@ -0,0 +1,26 @@ | |||||
meta { | |||||
name: Create Resource | |||||
type: http | |||||
seq: 5 | |||||
} | |||||
post { | |||||
url: http://localhost:3000/api/users | |||||
body: json | |||||
auth: none | |||||
} | |||||
headers { | |||||
Content-Type: application/json | |||||
} | |||||
body:json { | |||||
{ | |||||
"firstName": "John", | |||||
"middleName": "Smith", | |||||
"lastName": "Doe", | |||||
"birthday": "1986-04-20", | |||||
"bio": "This is my profile!" | |||||
} | |||||
} |
@@ -0,0 +1,11 @@ | |||||
meta { | |||||
name: Delete Resource | |||||
type: http | |||||
seq: 8 | |||||
} | |||||
delete { | |||||
url: http://localhost:3000/api/users/2 | |||||
body: none | |||||
auth: none | |||||
} |
@@ -0,0 +1,23 @@ | |||||
meta { | |||||
name: Emplace Resource | |||||
type: http | |||||
seq: 6 | |||||
} | |||||
put { | |||||
url: http://localhost:3000/api/users/2 | |||||
body: json | |||||
auth: none | |||||
} | |||||
body:json { | |||||
{ | |||||
"firstName": "John", | |||||
"middleName": "Smith", | |||||
"lastName": "Doe", | |||||
"birthday": "1986-04-20", | |||||
"bio": "This is my profile!", | |||||
"id": 2 | |||||
} | |||||
} |
@@ -0,0 +1,11 @@ | |||||
meta { | |||||
name: Get Resource Collection Metadata | |||||
type: http | |||||
seq: 1 | |||||
} | |||||
head { | |||||
url: http://localhost:3000/api/users | |||||
body: none | |||||
auth: none | |||||
} |
@@ -0,0 +1,11 @@ | |||||
meta { | |||||
name: Get Resource Collection | |||||
type: http | |||||
seq: 3 | |||||
} | |||||
get { | |||||
url: http://localhost:3000/api/users | |||||
body: none | |||||
auth: none | |||||
} |
@@ -0,0 +1,11 @@ | |||||
meta { | |||||
name: Get Resource Metadata | |||||
type: http | |||||
seq: 2 | |||||
} | |||||
head { | |||||
url: http://localhost:3000/api/users/1 | |||||
body: none | |||||
auth: none | |||||
} |
@@ -0,0 +1,11 @@ | |||||
meta { | |||||
name: Get Resource | |||||
type: http | |||||
seq: 4 | |||||
} | |||||
get { | |||||
url: http://localhost:3000/api/users/1 | |||||
body: none | |||||
auth: none | |||||
} |
@@ -0,0 +1,22 @@ | |||||
meta { | |||||
name: Patch Resource | |||||
type: http | |||||
seq: 7 | |||||
} | |||||
patch { | |||||
url: http://localhost:3000/api/users/1 | |||||
body: json | |||||
auth: none | |||||
} | |||||
headers { | |||||
Content-Type: application/json | |||||
} | |||||
body:json { | |||||
{ | |||||
"bio": "This is my updated bio!" | |||||
} | |||||
} |
@@ -0,0 +1,13 @@ | |||||
{ | |||||
"version": "1", | |||||
"name": "Yasumi", | |||||
"type": "collection", | |||||
"ignore": [ | |||||
"node_modules", | |||||
".git" | |||||
], | |||||
"presets": { | |||||
"requestType": "http", | |||||
"requestUrl": "http://localhost:3000" | |||||
} | |||||
} |
@@ -2,8 +2,6 @@ import { | |||||
application, | application, | ||||
resource, | resource, | ||||
validation as v, | validation as v, | ||||
mediaTypes, | |||||
charsets, | |||||
} from '../../src'; | } from '../../src'; | ||||
import {TEXT_SERIALIZER_PAIR} from './serializers'; | import {TEXT_SERIALIZER_PAIR} from './serializers'; | ||||
import {autoIncrement, dataSource} from './data-source'; | import {autoIncrement, dataSource} from './data-source'; | ||||
@@ -52,10 +50,7 @@ const User = resource(v.object( | |||||
const app = application({ | const app = application({ | ||||
name: 'piano-service', | name: 'piano-service', | ||||
}) | }) | ||||
.mediaType(mediaTypes.applicationJson) | |||||
.mediaType(mediaTypes.textJson) | |||||
.mediaType(TEXT_SERIALIZER_PAIR) | .mediaType(TEXT_SERIALIZER_PAIR) | ||||
.charset(charsets.utf8) | |||||
.resource(Piano) | .resource(Piano) | ||||
.resource(User); | .resource(User); | ||||
@@ -1,8 +1,14 @@ | |||||
import * as v from 'valibot'; | import * as v from 'valibot'; | ||||
import * as en from './common/languages/en'; | |||||
import * as utf8 from './common/charsets/utf-8'; | |||||
import * as applicationJson from './common/media-types/application/json'; | |||||
import {Resource, Language, MediaType, Charset, ApplicationParams, ApplicationState} from './common'; | |||||
import { | |||||
Resource, | |||||
Language, | |||||
MediaType, | |||||
Charset, | |||||
ApplicationParams, | |||||
ApplicationState, | |||||
FALLBACK_LANGUAGE, | |||||
FALLBACK_CHARSET, FALLBACK_MEDIA_TYPE, | |||||
} from './common'; | |||||
import {BackendBuilder, createBackend, CreateBackendParams} from './backend'; | import {BackendBuilder, createBackend, CreateBackendParams} from './backend'; | ||||
import {ClientBuilder, createClient, CreateClientParams} from './client'; | import {ClientBuilder, createClient, CreateClientParams} from './client'; | ||||
@@ -24,9 +30,9 @@ export const application = (appParams: ApplicationParams): ApplicationBuilder => | |||||
charsets: new Set<Charset>(), | charsets: new Set<Charset>(), | ||||
}; | }; | ||||
appState.languages.add(en); | |||||
appState.charsets.add(utf8); | |||||
appState.mediaTypes.add(applicationJson); | |||||
appState.languages.add(FALLBACK_LANGUAGE); | |||||
appState.charsets.add(FALLBACK_CHARSET); | |||||
appState.mediaTypes.add(FALLBACK_MEDIA_TYPE); | |||||
return { | return { | ||||
mediaType(serializerPair: MediaType) { | mediaType(serializerPair: MediaType) { | ||||
@@ -1,13 +1,10 @@ | |||||
import * as v from 'valibot'; | import * as v from 'valibot'; | ||||
import {ApplicationState, Resource} from '../common'; | |||||
import {ApplicationState, FALLBACK_CHARSET, FALLBACK_LANGUAGE, FALLBACK_MEDIA_TYPE, Resource} from '../common'; | |||||
import http from 'http'; | import http from 'http'; | ||||
import {createServer, CreateServerParams} from './server'; | import {createServer, CreateServerParams} from './server'; | ||||
import https from 'https'; | import https from 'https'; | ||||
import {BackendState} from './common'; | import {BackendState} from './common'; | ||||
import {BaseDataSource} from '../common/data-source'; | import {BaseDataSource} from '../common/data-source'; | ||||
import * as en from '../common/languages/en'; | |||||
import * as utf8 from '../common/charsets/utf-8'; | |||||
import * as applicationJson from '../common/media-types/application/json'; | |||||
import {DataSource} from './data-source'; | import {DataSource} from './data-source'; | ||||
export interface BackendResource< | export interface BackendResource< | ||||
@@ -41,9 +38,9 @@ export const createBackend = (params: CreateBackendParams) => { | |||||
app: params.app, | app: params.app, | ||||
dataSource: params.dataSource, | dataSource: params.dataSource, | ||||
cn: { | cn: { | ||||
language: en, | |||||
charset: utf8, | |||||
mediaType: applicationJson | |||||
language: FALLBACK_LANGUAGE, | |||||
charset: FALLBACK_CHARSET, | |||||
mediaType: FALLBACK_MEDIA_TYPE, | |||||
}, | }, | ||||
showTotalItemCountOnGetCollection: false, | showTotalItemCountOnGetCollection: false, | ||||
showTotalItemCountOnCreateItem: false, | showTotalItemCountOnCreateItem: false, | ||||
@@ -188,7 +188,7 @@ const adjustRequestForContentNegotiation = (req: RequestContext, res: http.Serve | |||||
// TODO refactor | // TODO refactor | ||||
const currentLanguage = availableLanguages.find((l) => l.name === languageCandidate); | const currentLanguage = availableLanguages.find((l) => l.name === languageCandidate); | ||||
if (typeof currentLanguage === 'undefined') { | if (typeof currentLanguage === 'undefined') { | ||||
const data = req.backend?.cn.language.bodies.languageNotAcceptable(); | |||||
const data = req.backend?.cn.language.bodies.languageNotAcceptable; | |||||
const responseRaw = req.backend?.cn.mediaType.serialize(data); | const responseRaw = req.backend?.cn.mediaType.serialize(data); | ||||
const response = typeof responseRaw !== 'undefined' ? req.backend?.cn.charset.encode(responseRaw) : undefined; | const response = typeof responseRaw !== 'undefined' ? req.backend?.cn.charset.encode(responseRaw) : undefined; | ||||
res.writeHead(constants.HTTP_STATUS_NOT_ACCEPTABLE, { | res.writeHead(constants.HTTP_STATUS_NOT_ACCEPTABLE, { | ||||
@@ -198,14 +198,14 @@ const adjustRequestForContentNegotiation = (req: RequestContext, res: http.Serve | |||||
`charset="${req.backend?.cn.charset.name}"` | `charset="${req.backend?.cn.charset.name}"` | ||||
].join('; '), | ].join('; '), | ||||
}); | }); | ||||
res.statusMessage = req.backend?.cn.language.statusMessages.languageNotAcceptable() ?? ''; | |||||
res.statusMessage = req.backend?.cn.language.statusMessages.languageNotAcceptable ?? ''; | |||||
res.end(response); | res.end(response); | ||||
return; | return; | ||||
} | } | ||||
const currentMediaType = availableMediaTypes.find((l) => l.name === mediaTypeCandidate); | const currentMediaType = availableMediaTypes.find((l) => l.name === mediaTypeCandidate); | ||||
if (typeof currentMediaType === 'undefined') { | if (typeof currentMediaType === 'undefined') { | ||||
const data = req.backend?.cn.language.bodies.mediaTypeNotAcceptable(); | |||||
const data = req.backend?.cn.language.bodies.mediaTypeNotAcceptable; | |||||
const responseRaw = req.backend?.cn.mediaType.serialize(data); | const responseRaw = req.backend?.cn.mediaType.serialize(data); | ||||
const response = typeof responseRaw !== 'undefined' ? req.backend?.cn.charset.encode(responseRaw) : undefined; | const response = typeof responseRaw !== 'undefined' ? req.backend?.cn.charset.encode(responseRaw) : undefined; | ||||
res.writeHead(constants.HTTP_STATUS_NOT_ACCEPTABLE, { | res.writeHead(constants.HTTP_STATUS_NOT_ACCEPTABLE, { | ||||
@@ -215,14 +215,14 @@ const adjustRequestForContentNegotiation = (req: RequestContext, res: http.Serve | |||||
`charset="${req.backend?.cn.charset.name}"` | `charset="${req.backend?.cn.charset.name}"` | ||||
].join('; '), | ].join('; '), | ||||
}); | }); | ||||
res.statusMessage = req.backend?.cn.language.statusMessages.mediaTypeNotAcceptable() ?? ''; | |||||
res.statusMessage = req.backend?.cn.language.statusMessages.mediaTypeNotAcceptable ?? ''; | |||||
res.end(response); | res.end(response); | ||||
return; | return; | ||||
} | } | ||||
const responseBodyCharset = availableCharsets.find((l) => l.name === charsetCandidate); | const responseBodyCharset = availableCharsets.find((l) => l.name === charsetCandidate); | ||||
if (typeof responseBodyCharset === 'undefined') { | if (typeof responseBodyCharset === 'undefined') { | ||||
const data = req.backend!.cn.language.bodies.encodingNotAcceptable(); | |||||
const data = req.backend!.cn.language.bodies.encodingNotAcceptable; | |||||
const responseRaw = req.backend!.cn.mediaType.serialize(data); | const responseRaw = req.backend!.cn.mediaType.serialize(data); | ||||
const response = typeof responseRaw !== 'undefined' ? req.backend!.cn.charset.encode(responseRaw) : undefined; | const response = typeof responseRaw !== 'undefined' ? req.backend!.cn.charset.encode(responseRaw) : undefined; | ||||
res.writeHead(constants.HTTP_STATUS_NOT_ACCEPTABLE, { | res.writeHead(constants.HTTP_STATUS_NOT_ACCEPTABLE, { | ||||
@@ -232,7 +232,7 @@ const adjustRequestForContentNegotiation = (req: RequestContext, res: http.Serve | |||||
`charset="${req.backend?.cn.charset.name}"` | `charset="${req.backend?.cn.charset.name}"` | ||||
].join('; '), | ].join('; '), | ||||
}); | }); | ||||
res.statusMessage = req.backend?.cn.language.statusMessages.encodingNotAcceptable() ?? ''; | |||||
res.statusMessage = req.backend?.cn.language.statusMessages.encodingNotAcceptable ?? ''; | |||||
res.end(response); | res.end(response); | ||||
return; | return; | ||||
} | } | ||||
@@ -282,7 +282,7 @@ export const createServer = (backendState: BackendState, serverParams = {} as Cr | |||||
const resource = Array.from(req.backend.app.resources).find((r) => r.state!.routeName === resourceRouteName); | const resource = Array.from(req.backend.app.resources).find((r) => r.state!.routeName === resourceRouteName); | ||||
if (typeof resource === 'undefined') { | if (typeof resource === 'undefined') { | ||||
res.statusCode = constants.HTTP_STATUS_NOT_FOUND; | res.statusCode = constants.HTTP_STATUS_NOT_FOUND; | ||||
res.statusMessage = req.backend.cn.language.statusMessages.urlNotFound(); | |||||
res.statusMessage = req.backend.cn.language.statusMessages.urlNotFound; | |||||
res.end(); | res.end(); | ||||
return; | return; | ||||
} | } | ||||
@@ -423,8 +423,8 @@ export const createServer = (backendState: BackendState, serverParams = {} as Cr | |||||
].join('; '); | ].join('; '); | ||||
} | } | ||||
const statusMessageFn = middlewareState.statusMessage ? req.cn.language.statusMessages[middlewareState.statusMessage] : undefined; | |||||
res.statusMessage = statusMessageFn?.(req.resource) ?? ''; | |||||
const statusMessageKey = middlewareState.statusMessage ? req.cn.language.statusMessages[middlewareState.statusMessage] : undefined; | |||||
res.statusMessage = statusMessageKey?.replace(/\$RESOURCE/g, req.resource.state.itemName) ?? ''; | |||||
res.writeHead(middlewareState.statusCode, headers); | res.writeHead(middlewareState.statusCode, headers); | ||||
if (typeof encoded !== 'undefined') { | if (typeof encoded !== 'undefined') { | ||||
res.end(encoded); | res.end(encoded); | ||||
@@ -458,8 +458,8 @@ export const createServer = (backendState: BackendState, serverParams = {} as Cr | |||||
`charset=${req.backend.cn.charset.name}` | `charset=${req.backend.cn.charset.name}` | ||||
].join('; '); | ].join('; '); | ||||
const statusMessageFn = finalErr.response.statusMessage ? req.backend.cn.language.statusMessages[finalErr.response.statusMessage] : undefined; | |||||
res.statusMessage = statusMessageFn?.(req.resource) ?? ''; | |||||
const statusMessageKey = finalErr.response.statusMessage ? req.backend.cn.language.statusMessages[finalErr.response.statusMessage] : undefined; | |||||
res.statusMessage = statusMessageKey?.replace(/\$RESOURCE/g, req.resource.state.itemName) ?? ''; | |||||
res.writeHead(finalErr.response.statusCode, headers); | res.writeHead(finalErr.response.statusCode, headers); | ||||
if (typeof encoded !== 'undefined') { | if (typeof encoded !== 'undefined') { | ||||
res.end(encoded); | res.end(encoded); | ||||
@@ -471,17 +471,20 @@ export const createServer = (backendState: BackendState, serverParams = {} as Cr | |||||
} | } | ||||
if (middlewares.length > 0) { | if (middlewares.length > 0) { | ||||
res.statusMessage = req.backend.cn.language.statusMessages.methodNotAllowed(); | |||||
res.statusMessage = req.backend.cn.language.statusMessages.methodNotAllowed.replace(/\$RESOURCE/g, req.resource.state.itemName) ?? ''; | |||||
res.writeHead(constants.HTTP_STATUS_METHOD_NOT_ALLOWED, { | res.writeHead(constants.HTTP_STATUS_METHOD_NOT_ALLOWED, { | ||||
Allow: middlewares.map((m) => m[0]).join(', ') | |||||
Allow: middlewares.map((m) => m[0]).join(', '), | |||||
'Content-Language': req.backend.cn.language.name, | |||||
}); | }); | ||||
res.end(); | res.end(); | ||||
return; | return; | ||||
} | } | ||||
// TODO error handler in line with authentication | // TODO error handler in line with authentication | ||||
res.statusMessage = req.backend.cn.language.statusMessages.urlNotFound(); | |||||
res.writeHead(constants.HTTP_STATUS_NOT_FOUND); | |||||
res.statusMessage = req.backend.cn.language.statusMessages.urlNotFound.replace(/\$RESOURCE/g, req.resource.state.itemName) ?? ''; | |||||
res.writeHead(constants.HTTP_STATUS_NOT_FOUND, { | |||||
'Content-Language': req.backend.cn.language.name, | |||||
}); | |||||
res.end(); | res.end(); | ||||
return; | return; | ||||
}); | }); | ||||
@@ -1,7 +1,12 @@ | |||||
import * as applicationJson from '../common/media-types/application/json'; | |||||
import * as utf8 from '../common/charsets/utf-8'; | |||||
import * as en from '../common/languages/en'; | |||||
import {ApplicationState, Charset, Language, MediaType} from '../common'; | |||||
import { | |||||
ApplicationState, | |||||
Charset, | |||||
FALLBACK_CHARSET, | |||||
FALLBACK_LANGUAGE, | |||||
FALLBACK_MEDIA_TYPE, | |||||
Language, | |||||
MediaType, | |||||
} from '../common'; | |||||
export interface ClientState { | export interface ClientState { | ||||
app: ApplicationState; | app: ApplicationState; | ||||
@@ -23,25 +28,25 @@ export interface CreateClientParams { | |||||
export const createClient = (params: CreateClientParams) => { | export const createClient = (params: CreateClientParams) => { | ||||
const clientState: ClientState = { | const clientState: ClientState = { | ||||
app: params.app, | app: params.app, | ||||
mediaType: applicationJson, | |||||
charset: utf8, | |||||
language: en | |||||
mediaType: FALLBACK_MEDIA_TYPE, | |||||
charset: FALLBACK_CHARSET, | |||||
language: FALLBACK_LANGUAGE | |||||
}; | }; | ||||
return { | return { | ||||
setMediaType(mediaTypeName) { | setMediaType(mediaTypeName) { | ||||
const mediaType = Array.from(clientState.app.mediaTypes).find((l) => l.name === mediaTypeName); | const mediaType = Array.from(clientState.app.mediaTypes).find((l) => l.name === mediaTypeName); | ||||
clientState.mediaType = mediaType ?? applicationJson; | |||||
clientState.mediaType = mediaType ?? FALLBACK_MEDIA_TYPE; | |||||
return this; | return this; | ||||
}, | }, | ||||
setCharset(charsetName) { | setCharset(charsetName) { | ||||
const charset = Array.from(clientState.app.charsets).find((l) => l.name === charsetName); | const charset = Array.from(clientState.app.charsets).find((l) => l.name === charsetName); | ||||
clientState.charset = charset ?? utf8; | |||||
clientState.charset = charset ?? FALLBACK_CHARSET; | |||||
return this; | return this; | ||||
}, | }, | ||||
setLanguage(languageCode) { | setLanguage(languageCode) { | ||||
const language = Array.from(clientState.app.languages).find((l) => l.name === languageCode); | const language = Array.from(clientState.app.languages).find((l) => l.name === languageCode); | ||||
clientState.language = language ?? en; | |||||
clientState.language = language ?? FALLBACK_LANGUAGE; | |||||
return this; | return this; | ||||
} | } | ||||
} satisfies ClientBuilder; | } satisfies ClientBuilder; | ||||
@@ -1 +0,0 @@ | |||||
export * as utf8 from './utf-8'; |
@@ -1,5 +0,0 @@ | |||||
export const encode = (str: string) => Buffer.from(str, 'utf-8'); | |||||
export const decode = (buf: Buffer) => buf.toString('utf-8'); | |||||
export const name = 'utf-8'; |
@@ -1,5 +1,62 @@ | |||||
import {Language} from './language'; | |||||
import {Charset} from './charset'; | |||||
import {MediaType} from './media-type'; | |||||
export * from './app'; | export * from './app'; | ||||
export * from './charset'; | export * from './charset'; | ||||
export * from './media-type'; | export * from './media-type'; | ||||
export * from './resource'; | export * from './resource'; | ||||
export * from './language'; | export * from './language'; | ||||
export const FALLBACK_LANGUAGE = { | |||||
name: 'en' as const, | |||||
statusMessages: { | |||||
unableToSerializeResponse: 'Unable To Serialize Response', | |||||
unableToEncodeResponse: 'Unable To Encode Response', | |||||
unableToInitializeResourceDataSource: 'Unable To Initialize $RESOURCE Data Source', | |||||
unableToFetchResourceCollection: 'Unable To Fetch $RESOURCE Collection', | |||||
unableToFetchResource: 'Unable To Fetch $RESOURCE', | |||||
unableToDeleteResource: 'Unable To Delete $RESOURCE', | |||||
languageNotAcceptable: 'Language Not Acceptable', | |||||
encodingNotAcceptable: 'Encoding Not Acceptable', | |||||
mediaTypeNotAcceptable: 'Media Type Not Acceptable', | |||||
methodNotAllowed: 'Method Not Allowed', | |||||
urlNotFound: 'URL Not Found', | |||||
badRequest: 'Bad Request', | |||||
ok: 'OK', | |||||
resourceCollectionFetched: '$RESOURCE Collection Fetched', | |||||
resourceFetched: '$RESOURCE Fetched', | |||||
resourceNotFound: '$RESOURCE Not Found', | |||||
deleteNonExistingResource: 'Delete Non-Existing $RESOURCE', | |||||
resourceDeleted: '$RESOURCE Deleted', | |||||
unableToDeserializeRequest: 'Unable To Deserialize Request', | |||||
patchNonExistingResource: 'Patch Non-Existing $RESOURCE', | |||||
unableToPatchResource: 'Unable To Patch $RESOURCE', | |||||
invalidResourcePatch: 'Invalid $RESOURCE Patch', | |||||
invalidResource: 'Invalid $RESOURCE', | |||||
resourcePatched: '$RESOURCE Patched', | |||||
resourceCreated: '$RESOURCE Created', | |||||
resourceReplaced: '$RESOURCE Replaced', | |||||
unableToGenerateIdFromResourceDataSource: 'Unable To Generate ID From $RESOURCE Data Source', | |||||
unableToEmplaceResource: 'Unable To Emplace $RESOURCE', | |||||
resourceIdNotGiven: '$RESOURCE ID Not Given', | |||||
unableToCreateResource: 'Unable To Create $RESOURCE', | |||||
}, | |||||
bodies: { | |||||
languageNotAcceptable: [], | |||||
encodingNotAcceptable: [], | |||||
mediaTypeNotAcceptable: [] | |||||
}, | |||||
} satisfies Language; | |||||
export const FALLBACK_CHARSET = { | |||||
encode: (str: string) => Buffer.from(str, 'utf-8'), | |||||
decode: (buf: Buffer) => buf.toString('utf-8'), | |||||
name: 'utf-8' as const, | |||||
} satisfies Charset; | |||||
export const FALLBACK_MEDIA_TYPE = { | |||||
serialize: (obj: unknown) => JSON.stringify(obj), | |||||
deserialize: (str: string) => JSON.parse(str), | |||||
name: 'application/json' as const, | |||||
} satisfies MediaType; |
@@ -1,45 +1,51 @@ | |||||
import {Resource} from './resource'; | |||||
export type MessageBody = string | string[] | (string | string[])[]; | export type MessageBody = string | string[] | (string | string[])[]; | ||||
export interface LanguageStatusMessageMap { | |||||
unableToInitializeResourceDataSource(resource: Resource): string; | |||||
unableToFetchResourceCollection(resource: Resource): string; | |||||
unableToFetchResource(resource: Resource): string; | |||||
resourceIdNotGiven(resource: Resource): string; | |||||
languageNotAcceptable(): string; | |||||
encodingNotAcceptable(): string; | |||||
mediaTypeNotAcceptable(): string; | |||||
methodNotAllowed(): string; | |||||
urlNotFound(): string; | |||||
badRequest(): string; | |||||
ok(): string; | |||||
resourceCollectionFetched(resource: Resource): string; | |||||
resourceFetched(resource: Resource): string; | |||||
resourceNotFound(resource: Resource): string; | |||||
deleteNonExistingResource(resource: Resource): string; | |||||
unableToCreateResource(resource: Resource): string; | |||||
unableToGenerateIdFromResourceDataSource(resource: Resource): string; | |||||
unableToEmplaceResource(resource: Resource): string; | |||||
unableToSerializeResponse(): string; | |||||
unableToEncodeResponse(): string; | |||||
unableToDeleteResource(resource: Resource): string; | |||||
resourceDeleted(resource: Resource): string; | |||||
unableToDeserializeRequest(): string; | |||||
patchNonExistingResource(resource: Resource): string; | |||||
unableToPatchResource(resource: Resource): string; | |||||
invalidResourcePatch(resource: Resource): string; | |||||
invalidResource(resource: Resource): string; | |||||
resourcePatched(resource: Resource): string; | |||||
resourceCreated(resource: Resource): string; | |||||
resourceReplaced(resource: Resource): string; | |||||
} | |||||
export const LANGUAGE_DEFAULT_STATUS_MESSAGE_KEYS = [ | |||||
'unableToInitializeResourceDataSource', | |||||
'unableToFetchResourceCollection', | |||||
'unableToFetchResource', | |||||
'resourceIdNotGiven', | |||||
'languageNotAcceptable', | |||||
'encodingNotAcceptable', | |||||
'mediaTypeNotAcceptable', | |||||
'methodNotAllowed', | |||||
'urlNotFound', | |||||
'badRequest', | |||||
'ok', | |||||
'resourceCollectionFetched', | |||||
'resourceFetched', | |||||
'resourceNotFound', | |||||
'deleteNonExistingResource', | |||||
'unableToCreateResource', | |||||
'unableToGenerateIdFromResourceDataSource', | |||||
'unableToEmplaceResource', | |||||
'unableToSerializeResponse', | |||||
'unableToEncodeResponse', | |||||
'unableToDeleteResource', | |||||
'resourceDeleted', | |||||
'unableToDeserializeRequest', | |||||
'patchNonExistingResource', | |||||
'unableToPatchResource', | |||||
'invalidResourcePatch', | |||||
'invalidResource', | |||||
'resourcePatched', | |||||
'resourceCreated', | |||||
'resourceReplaced', | |||||
] as const; | |||||
export interface LanguageBodyMap { | |||||
languageNotAcceptable(): MessageBody; | |||||
encodingNotAcceptable(): MessageBody; | |||||
mediaTypeNotAcceptable(): MessageBody; | |||||
} | |||||
export type LanguageDefaultStatusMessageKey = typeof LANGUAGE_DEFAULT_STATUS_MESSAGE_KEYS[number]; | |||||
export interface LanguageStatusMessageMap extends Record<LanguageDefaultStatusMessageKey, string> {} | |||||
export const LANGUAGE_DEFAULT_BODY_KEYS = [ | |||||
'languageNotAcceptable', | |||||
'encodingNotAcceptable', | |||||
'mediaTypeNotAcceptable', | |||||
] as const; | |||||
export type LanguageDefaultBodyKey = typeof LANGUAGE_DEFAULT_BODY_KEYS[number]; | |||||
export interface LanguageBodyMap extends Record<LanguageDefaultBodyKey, MessageBody> {} | |||||
export interface Language { | export interface Language { | ||||
name: string, | name: string, | ||||
@@ -1,109 +0,0 @@ | |||||
import {Resource} from '../../resource'; | |||||
import {Language} from '../../language'; | |||||
export const statusMessages = { | |||||
unableToSerializeResponse(): string { | |||||
return 'Unable To Serialize Response'; | |||||
}, | |||||
unableToEncodeResponse(): string { | |||||
return 'Unable To Encode Response'; | |||||
}, | |||||
unableToInitializeResourceDataSource(resource: Resource): string { | |||||
return `Unable To Initialize ${resource.state.itemName} Data Source`; | |||||
}, | |||||
unableToFetchResourceCollection(resource: Resource): string { | |||||
return `Unable To Fetch ${resource.state.itemName} Collection`; | |||||
}, | |||||
unableToFetchResource(resource: Resource): string { | |||||
return `Unable To Fetch ${resource.state.itemName}`; | |||||
}, | |||||
unableToDeleteResource(resource: Resource): string { | |||||
return `Unable To Delete ${resource.state.itemName}`; | |||||
}, | |||||
languageNotAcceptable(): string { | |||||
return 'Language Not Acceptable'; | |||||
}, | |||||
encodingNotAcceptable(): string { | |||||
return 'Encoding Not Acceptable'; | |||||
}, | |||||
mediaTypeNotAcceptable(): string { | |||||
return 'Media Type Not Acceptable'; | |||||
}, | |||||
methodNotAllowed(): string { | |||||
return 'Method Not Allowed'; | |||||
}, | |||||
urlNotFound(): string { | |||||
return 'URL Not Found'; | |||||
}, | |||||
badRequest(): string { | |||||
return 'Bad Request'; | |||||
}, | |||||
ok(): string { | |||||
return 'OK'; | |||||
}, | |||||
resourceCollectionFetched(resource: Resource): string { | |||||
return `${resource.state.itemName} Collection Fetched`; | |||||
}, | |||||
resourceFetched(resource: Resource): string { | |||||
return `${resource.state.itemName} Fetched`; | |||||
}, | |||||
resourceNotFound(resource: Resource): string { | |||||
return `${resource.state.itemName} Not Found`; | |||||
}, | |||||
deleteNonExistingResource(resource: Resource): string { | |||||
return `Delete Non-Existing ${resource.state.itemName}`; | |||||
}, | |||||
resourceDeleted(resource: Resource): string { | |||||
return `${resource.state.itemName} Deleted`; | |||||
}, | |||||
unableToDeserializeRequest(): string { | |||||
return 'Unable To Deserialize Request'; | |||||
}, | |||||
patchNonExistingResource(resource: Resource): string { | |||||
return `Patch Non-Existing ${resource.state.itemName}`; | |||||
}, | |||||
unableToPatchResource(resource: Resource): string { | |||||
return `Unable To Patch ${resource.state.itemName}`; | |||||
}, | |||||
invalidResourcePatch(resource: Resource): string { | |||||
return `Invalid ${resource.state.itemName} Patch`; | |||||
}, | |||||
invalidResource(resource: Resource): string { | |||||
return `Invalid ${resource.state.itemName}`; | |||||
}, | |||||
resourcePatched(resource: Resource): string { | |||||
return `${resource.state.itemName} Patched`; | |||||
}, | |||||
resourceCreated(resource: Resource): string { | |||||
return `${resource.state.itemName} Created`; | |||||
}, | |||||
resourceReplaced(resource: Resource): string { | |||||
return `${resource.state.itemName} Replaced`; | |||||
}, | |||||
unableToGenerateIdFromResourceDataSource(resource: Resource): string { | |||||
return `Unable To Generate ID From ${resource.state.itemName} Data Source`; | |||||
}, | |||||
unableToEmplaceResource(resource: Resource): string { | |||||
return `Unable To Emplace ${resource.state.itemName}`; | |||||
}, | |||||
resourceIdNotGiven(resource: Resource): string { | |||||
return `${resource.state.itemName} ID Not Given`; | |||||
}, | |||||
unableToCreateResource(resource: Resource): string { | |||||
return `Unable To Create ${resource.state.itemName}`; | |||||
} | |||||
} satisfies Language['statusMessages']; | |||||
export const bodies = { | |||||
languageNotAcceptable() { | |||||
return []; | |||||
}, | |||||
encodingNotAcceptable() { | |||||
return []; | |||||
}, | |||||
mediaTypeNotAcceptable() { | |||||
return [] | |||||
} | |||||
} satisfies Language['bodies']; | |||||
export const name = 'en' as const; |
@@ -1 +0,0 @@ | |||||
export * as en from './en'; |
@@ -1,5 +0,0 @@ | |||||
export const serialize = (obj: unknown) => JSON.stringify(obj); | |||||
export const deserialize = (str: string) => JSON.parse(str); | |||||
export const name = 'application/json'; |
@@ -1,2 +0,0 @@ | |||||
export * as applicationJson from './application/json'; | |||||
export * as textJson from './application/json'; |
@@ -3,8 +3,4 @@ export * as validation from './common/validation'; | |||||
export * as dataSources from './backend/data-sources'; | export * as dataSources from './backend/data-sources'; | ||||
export * as mediaTypes from './common/media-types'; | |||||
export * as charsets from './common/charsets'; | |||||
export * as languages from './common/languages'; | |||||
export * from './app'; | export * from './app'; |
@@ -23,12 +23,12 @@ import {request, Server} from 'http'; | |||||
import {constants} from 'http2'; | import {constants} from 'http2'; | ||||
import {DataSource} from '../../src/backend/data-source'; | import {DataSource} from '../../src/backend/data-source'; | ||||
import { dataSources } from '../../src/backend'; | import { dataSources } from '../../src/backend'; | ||||
import { application, resource, validation as v, Resource, charsets, mediaTypes } from '../../src'; | |||||
import { application, resource, validation as v, Resource } from '../../src'; | |||||
const PORT = 3000; | const PORT = 3000; | ||||
const HOST = 'localhost'; | const HOST = 'localhost'; | ||||
const ACCEPT_CHARSET = charsets.utf8.name; | |||||
const ACCEPT = mediaTypes.applicationJson.name; | |||||
const ACCEPT_CHARSET = 'utf-8'; | |||||
const ACCEPT = 'application/json'; | |||||
const autoIncrement = async (dataSource: DataSource) => { | const autoIncrement = async (dataSource: DataSource) => { | ||||
const data = await dataSource.getMultiple() as Record<string, string>[]; | const data = await dataSource.getMultiple() as Record<string, string>[]; | ||||
@@ -87,8 +87,6 @@ describe('yasumi', () => { | |||||
const app = application({ | const app = application({ | ||||
name: 'piano-service', | name: 'piano-service', | ||||
}) | }) | ||||
.mediaType(mediaTypes.applicationJson) | |||||
.charset(charsets.utf8) | |||||
.resource(Piano); | .resource(Piano); | ||||
const backend = app | const backend = app | ||||