Skip to content

Commit

Permalink
renames and context.http.location
Browse files Browse the repository at this point in the history
  • Loading branch information
vonagam committed Jan 13, 2022
1 parent b1ff9e2 commit 067152e
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 63 deletions.
11 changes: 4 additions & 7 deletions packages/express/src/rest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,10 @@ const serviceMiddleware = (): RequestHandler => {
const context = await (service as any)[method](...args, contextBase);
res.hook = context;

const result = http.getData(context);
const statusCode = http.getStatusCode(context, result);
const responseHeaders = http.getResponseHeaders(context);

res.data = result;
res.statusCode = statusCode;
res.set(responseHeaders);
const response = http.getResponse(context);
res.statusCode = response.status;
res.set(response.headers);
res.data = response.body;

return next();
});
Expand Down
4 changes: 2 additions & 2 deletions packages/express/test/rest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ describe('@feathersjs/express/rest provider', () => {

app.service('hook-status').hooks({
after (hook: HookContext) {
hook.http!.statusCode = 206;
hook.http!.status = 206;
}
});

Expand All @@ -215,7 +215,7 @@ describe('@feathersjs/express/rest provider', () => {

app.service('hook-headers').hooks({
after (hook: HookContext) {
hook.http!.responseHeaders = { foo: 'first', bar: ['second', 'third'] };
hook.http!.headers = { foo: 'first', bar: ['second', 'third'] };
}
});

Expand Down
17 changes: 10 additions & 7 deletions packages/feathers/src/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,14 +242,17 @@ export interface Params {

export interface Http {
/**
* A writeable, optional property that allows to override the standard HTTP status
* code that should be returned.
* A writeable, optional property with status code override.
*/
statusCode?: number;
status?: number;
/**
* A writeable, optional property with headers.
*/
headers?: { [key: string]: string | string[] };
/**
* A writeable, optional property that allows to provide HTTP response headers.
* A writeable, optional property with `Location` header's value.
*/
responseHeaders?: { [key: string]: string | string[] };
location?: string;
}

export interface HookContext<A = Application, S = any> extends BaseHookContext<ServiceGenericType<S>> {
Expand Down Expand Up @@ -323,11 +326,11 @@ export interface HookContext<A = Application, S = any> extends BaseHookContext<S
* A writeable, optional property that allows to override the standard HTTP status
* code that should be returned.
*
* @deprecated Use `http.statusCode` instead.
* @deprecated Use `http.status` instead.
*/
statusCode?: number;
/**
* A writeable, optional property that contains options specific to HTTP transports.
* A writeable, optional property with options specific to HTTP transports.
*/
http?: Http;
/**
Expand Down
4 changes: 2 additions & 2 deletions packages/feathers/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@ export function hookMixin<A> (
event: null,
type: null,
get statusCode () {
return this.http?.statusCode;
return this.http?.status;
},
set statusCode (value: number) {
(this.http ||= {}).statusCode = value;
(this.http ||= {}).status = value;
}
});

Expand Down
11 changes: 4 additions & 7 deletions packages/koa/src/rest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,10 @@ const serviceMiddleware = (): Middleware => {
const context = await (service as any)[method](...args, contextBase);
ctx.hook = context;

const result = http.getData(context);
const statusCode = http.getStatusCode(context, result);
const responseHeaders = http.getResponseHeaders(context);

ctx.body = result;
ctx.status = statusCode;
ctx.set(responseHeaders);
const response = http.getResponse(context);
ctx.status = response.status;
ctx.set(response.headers);
ctx.body = response.body;

return next();
};
Expand Down
2 changes: 2 additions & 0 deletions packages/transport-commons/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@
"@feathersjs/commons": "^5.0.0-pre.16",
"@feathersjs/errors": "^5.0.0-pre.16",
"@feathersjs/feathers": "^5.0.0-pre.16",
"encodeurl": "^1.0.2",
"lodash": "^4.17.21"
},
"devDependencies": {
"@types/encodeurl": "^1.0.0",
"@types/lodash": "^4.14.178",
"@types/mocha": "^9.0.0",
"@types/node": "^17.0.5",
Expand Down
42 changes: 24 additions & 18 deletions packages/transport-commons/src/http.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { MethodNotAllowed } from '@feathersjs/errors/lib';
import { HookContext, NullableId, Params } from '@feathersjs/feathers';
import encodeUrl from 'encodeurl';

export const METHOD_HEADER = 'x-service-method';

Expand All @@ -13,7 +14,8 @@ export const statusCodes = {
created: 201,
noContent: 204,
methodNotAllowed: 405,
success: 200
success: 200,
seeOther: 303
};

export const knownMethods: { [key: string]: string } = {
Expand Down Expand Up @@ -53,28 +55,32 @@ export const argumentsFor = {
default: ({ data, params }: ServiceParams) => [ data, params ]
}

export function getData (context: HookContext) {
return context.dispatch !== undefined
? context.dispatch
: context.result;
}
export function getResponse (context: HookContext) {
const http = context.http || {};

export function getStatusCode (context: HookContext, data?: any) {
if (context.http?.statusCode) {
return context.http.statusCode;
}
let status = statusCodes.success;
let headers = http.headers || {};
let location = headers[ 'Location' ];
let body = context.result;

if (context.method === 'create') {
return statusCodes.created;
if (context.dispatch !== undefined) {
body = context.dispatch;
}

if (!data) {
return statusCodes.noContent;
if (http.location !== undefined) {
location = encodeUrl(http.location);
headers = { ...headers, Location: location };
}

return statusCodes.success;
}
if (http.status) {
status = http.status;
} else if (context.method === 'create') {
status = statusCodes.created;
} else if (location !== undefined) {
status = statusCodes.seeOther;
} else if (!body) {
status = statusCodes.noContent;
}

export function getResponseHeaders (context: HookContext) {
return context.http?.responseHeaders ?? {};
return { status, headers, body };
}
48 changes: 28 additions & 20 deletions packages/transport-commons/test/http.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { HookContext } from '@feathersjs/feathers';
import { http } from '../src';

describe('@feathersjs/transport-commons HTTP helpers', () => {
it('getData', () => {
it('getResponse body', () => {
const plainData = { message: 'hi' };
const dispatch = { message: 'from dispatch' };
const resultContext = {
Expand All @@ -13,22 +13,41 @@ describe('@feathersjs/transport-commons HTTP helpers', () => {
dispatch
};

assert.strictEqual(http.getData(resultContext as HookContext), plainData);
assert.strictEqual(http.getData(dispatchContext as HookContext), dispatch);
assert.strictEqual(http.getResponse(resultContext as HookContext).body, plainData);
assert.strictEqual(http.getResponse(dispatchContext as HookContext).body, dispatch);
});

it('getStatusCode', () => {
it('getResponse status', () => {
const statusContext = {
http: { statusCode: 202 }
http: { status: 202 }
};
const createContext = {
method: 'create'
};
const redirectContext = {
http: { location: '/' }
};

assert.strictEqual(http.getResponse(statusContext as HookContext).status, 202);
assert.strictEqual(http.getResponse(createContext as HookContext).status, http.statusCodes.created);
assert.strictEqual(http.getResponse(redirectContext as HookContext).status, http.statusCodes.seeOther);
assert.strictEqual(http.getResponse({} as HookContext).status, http.statusCodes.noContent);
assert.strictEqual(http.getResponse({result: true} as HookContext).status, http.statusCodes.success);
});

it('getResponse headers', () => {
const headers = { key: 'value' } as any;
const headersContext = {
http: { headers }
};
const locationContext = {
http: { location: '/' }
};

assert.strictEqual(http.getStatusCode(statusContext as HookContext, {}), 202);
assert.strictEqual(http.getStatusCode(createContext as HookContext, {}), http.statusCodes.created);
assert.strictEqual(http.getStatusCode({} as HookContext), http.statusCodes.noContent);
assert.strictEqual(http.getStatusCode({} as HookContext, {}), http.statusCodes.success);
assert.deepStrictEqual(http.getResponse({} as HookContext).headers, {});
assert.deepStrictEqual(http.getResponse({http: {}} as HookContext).headers, {});
assert.strictEqual(http.getResponse(headersContext as HookContext).headers, headers);
assert.deepStrictEqual(http.getResponse(locationContext as HookContext).headers, { Location: '/' });
});

it('getServiceMethod', () => {
Expand All @@ -39,15 +58,4 @@ describe('@feathersjs/transport-commons HTTP helpers', () => {
assert.strictEqual(http.getServiceMethod('delete', null), 'remove');
assert.throws(() => http.getServiceMethod('nonsense', null));
});

it('getResponseHeaders', () => {
const responseHeaders = { key: 'value' };
const headersContext = {
http: { responseHeaders }
};

assert.deepStrictEqual(http.getResponseHeaders({} as HookContext), {});
assert.deepStrictEqual(http.getResponseHeaders({http: {}} as HookContext), {});
assert.strictEqual(http.getResponseHeaders(headersContext as any as HookContext), responseHeaders);
});
});

0 comments on commit 067152e

Please sign in to comment.