Browse Source

Fix stream errors

Trying to customize request objects trigger typescript errors.
master
TheoryOfNekomata 6 months ago
parent
commit
a0e5c45db3
6 changed files with 37 additions and 69 deletions
  1. +5
    -3
      examples/basic/data-source.ts
  2. +2
    -0
      examples/basic/server.ts
  3. +1
    -1
      src/backend/extenders/method.ts
  4. +1
    -1
      src/backend/extenders/url.ts
  5. +6
    -6
      src/backend/handlers.ts
  6. +22
    -58
      src/backend/server.ts

+ 5
- 3
examples/basic/data-source.ts View File

@@ -1,7 +1,9 @@
import {DataSource, dataSources, Resource} from '../../src';
import {dataSources, Resource} from '../../src';
import {DataSource} from '../../src/backend/data-source';
import {BaseDataSource} from '../../src/common/data-source';

export const autoIncrement = async (dataSource: DataSource) => {
const data = await dataSource.getMultiple() as Record<string, string>[];
export const autoIncrement = async (dataSource: BaseDataSource) => {
const data = await (dataSource as DataSource).getMultiple() as Record<string, string>[];

const highestId = data.reduce<number>(
(highestId, d) => (Number(d.id) > highestId ? Number(d.id) : highestId),


+ 2
- 0
examples/basic/server.ts View File

@@ -15,6 +15,7 @@ const Piano = resource(v.object(
v.never()
))
.name('Piano')
.route('pianos')
.id('id', {
generationStrategy: autoIncrement,
serialize: (id) => id?.toString() ?? '0',
@@ -45,6 +46,7 @@ const User = resource(v.object(
schema: v.number(),
})
.name('User')
.route('users')
.fullText('bio');

const app = application({


+ 1
- 1
src/backend/extenders/method.ts View File

@@ -3,7 +3,7 @@ import http from 'http';
import {HttpMiddlewareError} from '../server';

interface RequestContext extends http.IncomingMessage {
method: string;
method?: string;
}

export const adjustMethod = (req: RequestContext) => {


+ 1
- 1
src/backend/extenders/url.ts View File

@@ -7,7 +7,7 @@ interface RequestContext extends http.IncomingMessage {

query?: URLSearchParams;

rawUrl: string;
rawUrl?: string;
}

export const adjustUrl = (req: RequestContext) => {


+ 6
- 6
src/backend/handlers.ts View File

@@ -6,10 +6,10 @@ export const handleGetRoot: Middleware = (req) => {
const { backend, basePath } = req;

const data = {
name: backend.app.name
name: backend!.app.name
};

const registeredResources = Array.from(backend.app.resources);
const registeredResources = Array.from(backend!.app.resources);
const availableResources = registeredResources.filter((r) => (
r.state.canFetchCollection
|| r.state.canCreate
@@ -43,7 +43,7 @@ export const handleGetCollection: Middleware = async (req) => {
try {
// TODO querying mechanism
data = await resource.dataSource.getMultiple(query); // TODO paginated responses per resource
if (backend.showTotalItemCountOnGetCollection && typeof resource.dataSource.getTotalCount === 'function') {
if (backend!.showTotalItemCountOnGetCollection && typeof resource.dataSource.getTotalCount === 'function') {
totalItemCount = await resource.dataSource.getTotalCount(query);
}
} catch (cause) {
@@ -133,7 +133,7 @@ export const handleDeleteItem: Middleware = async (req) => {
});
}

if (!existing && backend.throws404OnDeletingNotFound) {
if (!existing && backend!.throws404OnDeletingNotFound) {
throw new HttpMiddlewareError('deleteNonExistingResource', {
statusCode: constants.HTTP_STATUS_NOT_FOUND
});
@@ -214,7 +214,7 @@ export const handleCreateItem: Middleware = async (req) => {
let totalItemCount: number | undefined;
try {
newObject = await resource.dataSource.create(params);
if (backend.showTotalItemCountOnCreateItem && typeof resource.dataSource.getTotalCount === 'function') {
if (backend!.showTotalItemCountOnCreateItem && typeof resource.dataSource.getTotalCount === 'function') {
totalItemCount = await resource.dataSource.getTotalCount();
}
} catch (cause) {
@@ -266,7 +266,7 @@ export const handleEmplaceItem: Middleware = async (req) => {

const headers: Record<string, string> = {};
let totalItemCount: number | undefined;
if (backend.showTotalItemCountOnCreateItem && typeof resource.dataSource.getTotalCount === 'function') {
if (backend!.showTotalItemCountOnCreateItem && typeof resource.dataSource.getTotalCount === 'function') {
totalItemCount = await resource.dataSource.getTotalCount();
}
if (isCreated) {


+ 22
- 58
src/backend/server.ts View File

@@ -1,9 +1,6 @@
import http from 'http';
import {BackendState} from './common';
import {Language, Resource, Charset, MediaType, LanguageStatusMessageMap} from '../common';
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 https from 'https';
import Negotiator from 'negotiator';
import {constants} from 'http2';
@@ -89,19 +86,19 @@ export interface CreateServerParams {
}

export interface RequestContext extends http.IncomingMessage {
backend: BackendState;
backend?: BackendState;

host: string;
host?: string;

scheme: string;
scheme?: string;

basePath: string;
basePath?: string;

method: string;
method?: string;

url: string;
url?: string;

rawUrl: string;
rawUrl?: string;

cn: {
language: Language;
@@ -122,39 +119,6 @@ export interface Middleware<Req extends RequestContext = RequestContext> {
(req: Req): undefined | Response | Promise<undefined | Response>;
}

class ServerYasumiRequest extends http.IncomingMessage implements RequestContext {
host = 'localhost';

scheme = 'http';

basePath = '';

backend = {} as BackendState;

resource = undefined as unknown as BackendResource;

resourceId?: string;

query = new URLSearchParams();

body?: unknown;

method = '';

url = '';

rawUrl = '';

readonly cn: {
language: Language;
mediaType: MediaType;
charset: Charset;
} = {
language: en,
mediaType: applicationJson,
charset: utf8,
};
}
const getAllowedMiddlewares = <T extends v.BaseSchema>(resource: Resource<T>, mainResourceId: string) => {
const middlewares = [] as [string, Middleware, v.BaseSchema?][];
if (mainResourceId === '') {
@@ -210,13 +174,13 @@ const getAllowedMiddlewares = <T extends v.BaseSchema>(resource: Resource<T>, ma

const adjustRequestForContentNegotiation = (req: RequestContext, res: http.ServerResponse<RequestContext>) => {
const negotiator = new Negotiator(req);
const availableLanguages = Array.from(req.backend.app.languages);
const availableCharsets = Array.from(req.backend.app.charsets);
const availableMediaTypes = Array.from(req.backend.app.mediaTypes);
const availableLanguages = Array.from(req.backend!.app.languages);
const availableCharsets = Array.from(req.backend!.app.charsets);
const availableMediaTypes = Array.from(req.backend!.app.mediaTypes);

const languageCandidate = negotiator.language(availableLanguages.map((l) => l.name)) ?? req.backend.cn.language.name;
const charsetCandidate = negotiator.charset(availableCharsets.map((l) => l.name)) ?? req.backend.cn.charset.name;
const mediaTypeCandidate = negotiator.mediaType(availableMediaTypes.map((l) => l.name)) ?? req.backend.cn.mediaType.name;
const languageCandidate = negotiator.language(availableLanguages.map((l) => l.name)) ?? req.backend!.cn.language.name;
const charsetCandidate = negotiator.charset(availableCharsets.map((l) => l.name)) ?? req.backend!.cn.charset.name;
const mediaTypeCandidate = negotiator.mediaType(availableMediaTypes.map((l) => l.name)) ?? req.backend!.cn.mediaType.name;

// TODO refactor
const currentLanguage = availableLanguages.find((l) => l.name === languageCandidate);
@@ -255,9 +219,9 @@ const adjustRequestForContentNegotiation = (req: RequestContext, res: http.Serve

const responseBodyCharset = availableCharsets.find((l) => l.name === charsetCandidate);
if (typeof responseBodyCharset === 'undefined') {
const data = req.backend?.cn.language.bodies.encodingNotAcceptable();
const responseRaw = req.backend?.cn.mediaType.serialize(data);
const response = typeof responseRaw !== 'undefined' ? req.backend?.cn.charset.encode(responseRaw) : undefined;
const data = req.backend!.cn.language.bodies.encodingNotAcceptable();
const responseRaw = req.backend!.cn.mediaType.serialize(data);
const response = typeof responseRaw !== 'undefined' ? req.backend!.cn.charset.encode(responseRaw) : undefined;
res.writeHead(constants.HTTP_STATUS_NOT_ACCEPTABLE, {
'Content-Language': req.backend?.cn.language.name,
'Content-Type': [
@@ -283,18 +247,18 @@ export const createServer = (backendState: BackendState, serverParams = {} as Cr
key: serverParams.key,
cert: serverParams.cert,
requestTimeout: serverParams.requestTimeout,
IncomingMessage: ServerYasumiRequest,
})
: http.createServer({
requestTimeout: serverParams.requestTimeout,
IncomingMessage: ServerYasumiRequest,
});

server.on('request', async (req: RequestContext, res) => {
server.on('request', async (req: RequestContext, res: http.ServerResponse<RequestContext>) => {
req.backend = backendState;
req.basePath = serverParams.basePath ?? '';
req.host = serverParams.host ?? 'localhost';
req.scheme = isHttps ? 'https' : 'http';
req.cn = req.backend.cn;

adjustRequestForContentNegotiation(req, res);

try {
@@ -373,7 +337,7 @@ export const createServer = (backendState: BackendState, serverParams = {} as Cr
return;
}

const [, resourceRouteName, resourceId = ''] = req.url.split('/') ?? [];
const [, resourceRouteName, resourceId = ''] = req.url?.split('/') ?? [];
const resource = Array.from(req.backend.app.resources).find((r) => r.state!.routeName === resourceRouteName);
if (typeof resource === 'undefined') {
res.statusCode = constants.HTTP_STATUS_NOT_FOUND;
@@ -414,8 +378,8 @@ export const createServer = (backendState: BackendState, serverParams = {} as Cr
}

if (schema) {
const availableSerializers = Array.from(req.backend.app.mediaTypes);
const availableCharsets = Array.from(req.backend.app.charsets);
const availableSerializers = Array.from(req.backend!.app.mediaTypes);
const availableCharsets = Array.from(req.backend!.app.charsets);
const contentTypeHeader = req.headers['content-type'] ?? 'application/octet-stream';
const fragments = contentTypeHeader.split(';');
const mediaType = fragments[0];


Loading…
Cancel
Save