Skip to content

Commit

Permalink
refactor(core): Create rest package and use server instances (#567)
Browse files Browse the repository at this point in the history
Reintroduce the Server concept to the Application level, and move the
HTTP-specific behaviours out into the "rest" package.

**BREAKING CHANGE**: Core package no longer hosts HTTP-specific
behaviours, functions or modules
  • Loading branch information
kjdelisle committed Sep 29, 2017
1 parent 866953a commit 42416dd
Show file tree
Hide file tree
Showing 74 changed files with 187 additions and 279 deletions.
10 changes: 7 additions & 3 deletions bin/lint-commits.sh
Expand Up @@ -23,12 +23,12 @@ echo "TRAVIS_BRANCH => $TRAVIS_BRANCH"
echo "TRAVIS_COMMIT => $TRAVIS_COMMIT"
echo "TRAVIS_COMMIT_MSG => $TRAVIS_COMMIT_MESSAGE"
echo "TRAVIS_COMMIT_RANGE => $TRAVIS_COMMIT_RANGE"
echo "TRAVIS_EVENT_TYPE => $TRAVIS_EVENT_TYPE"
echo "TRAVIS_EVENT_TYPE => $TRAVIS_EVENT_TYPE"https://travis-ci.org/strongloop/loopback-next/jobs/281324624
echo "TRAVIS_PULL_REQUEST => $TRAVIS_PULL_REQUEST"
echo "TRAVIS_PULL_REQUEST_BRANCH => $TRAVIS_PULL_REQUEST_BRANCH"
echo "TRAVIS_PULL_REQUEST_SHA => $TRAVIS_PULL_REQUEST_SHA"
echo "TRAVIS_PULL_REQUEST_SLUG => $TRAVIS_PULL_REQUEST_SLUG"
echo "TRAVIS_REPO_SLUG => $TRAVIS_REPO_SLUG"
echo "TRAVIS_REPO_SLUG => $TRAVIS_REPO_SLUG"

# Lint all commits in the PR
# - Covers fork pull requests (when TO=slug/branch)
Expand All @@ -37,4 +37,8 @@ echo "TRAVIS_REPO_SLUG => $TRAVIS_REPO_SLUG"

# Always lint the triggering commit
# - Covers direct commits
./node_modules/.bin/commitlint --from="$TRAVIS_COMMIT"
COMMIT=$TRAVIS_COMMIT
if [[ $TRAVIS_PULL_REQUEST_SHA != "" && $TRAVIS_PULL_REQUEST_SHA != $TRAVIS_COMMIT ]]; then
COMMIT=$TRAVIS_PULL_REQUEST_SHA
fi
./node_modules/.bin/commitlint --from="$COMMIT"
1 change: 0 additions & 1 deletion packages/authentication/src/auth-component.ts
Expand Up @@ -4,7 +4,6 @@
// License text available at https://opensource.org/licenses/MIT

import {AuthenticationBindings} from './keys';
import {Constructor} from '@loopback/context';
import {Component, ProviderMap} from '@loopback/core';
import {AuthenticationProvider} from './providers/authenticate';
import {AuthMetadataProvider} from './providers/auth-metadata';
Expand Down
3 changes: 1 addition & 2 deletions packages/authentication/src/providers/authenticate.ts
Expand Up @@ -3,8 +3,7 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import * as http from 'http';
import {HttpErrors, ParsedRequest} from '@loopback/rest';
import {ParsedRequest} from '@loopback/rest';
import {inject} from '@loopback/core';
import {Provider, Getter, Setter} from '@loopback/context';
import {Strategy} from 'passport';
Expand Down
1 change: 0 additions & 1 deletion packages/authentication/src/strategy-adapter.ts
Expand Up @@ -2,7 +2,6 @@
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
import * as http from 'http';
import {HttpErrors, ParsedRequest} from '@loopback/rest';
import {Strategy} from 'passport';
import {UserProfile} from './providers/authenticate';
Expand Down
11 changes: 3 additions & 8 deletions packages/authentication/test/acceptance/basic-auth.ts
Expand Up @@ -3,7 +3,7 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {Application, Server, mountComponent} from '@loopback/core';
import {Application} from '@loopback/core';
import {
api,
RestBindings,
Expand All @@ -12,26 +12,21 @@ import {
ParseParams,
FindRoute,
InvokeMethod,
GetFromContext,
BindElement,
HttpErrors,
Send,
Reject,
HttpHandler,
SequenceHandler,
get,
RestServer,
RestComponent,
} from '@loopback/rest';
import {expect, Client, createClientForHandler} from '@loopback/testlab';
import {Client, createClientForHandler} from '@loopback/testlab';
import {anOpenApiSpec} from '@loopback/openapi-spec-builder';
import {inject, Provider, ValueOrPromise} from '@loopback/context';
import {
authenticate,
UserProfile,
AuthenticationBindings,
AuthenticateFn,
AuthMetadataProvider,
AuthenticationMetadata,
AuthenticationComponent,
} from '../..';
Expand Down Expand Up @@ -148,7 +143,7 @@ describe('Basic Authentication', () => {
const route = this.findRoute(req);

// Authenticate
const user = await this.authenticateRequest(req);
await this.authenticateRequest(req);

// Authentication successful, proceed to invoke controller
const args = await this.parseParams(req, route);
Expand Down
36 changes: 17 additions & 19 deletions packages/authentication/test/unit/authenticate-action.test.ts
Expand Up @@ -4,7 +4,7 @@
// License text available at https://opensource.org/licenses/MIT

import {expect} from '@loopback/testlab';
import {Context, Provider, instantiateClass} from '@loopback/context';
import {Context, instantiateClass} from '@loopback/context';
import {ParsedRequest} from '@loopback/rest';
import {
AuthenticationProvider,
Expand All @@ -13,11 +13,12 @@ import {
AuthenticationBindings,
} from '../..';
import {MockStrategy} from './fixtures/mock-strategy';

// FIXME: All of these BDD titles are too verbose and should be reworded
// to not run afoul of the lint rules!
// tslint:disable:max-line-length
describe('AuthenticationProvider', () => {
describe('constructor()', () => {
it('instantiateClass injects authentication.strategy in the constructor',
async () => {
it('instantiateClass injects authentication.strategy in the constructor', async () => {
const context = new Context();
const strategy = new MockStrategy();
context.bind(AuthenticationBindings.STRATEGY).to(strategy);
Expand All @@ -35,8 +36,7 @@ describe('AuthenticationProvider', () => {

beforeEach(givenAuthenticationProvider);

it('returns a function which authenticates a request and returns a user',
async () => {
it('returns a function which authenticates a request and returns a user', async () => {
const authenticate: AuthenticateFn = await Promise.resolve(
provider.value(),
);
Expand All @@ -45,16 +45,15 @@ describe('AuthenticationProvider', () => {
expect(user).to.be.equal(mockUser);
});

it('updates current user', async () => {
const authenticate = await Promise.resolve(provider.value());
const request = <ParsedRequest> {};
await authenticate(request);
expect(currentUser).to.equal(mockUser);
});
it('updates current user', async () => {
const authenticate = await Promise.resolve(provider.value());
const request = <ParsedRequest> {};
await authenticate(request);
expect(currentUser).to.equal(mockUser);
});

describe('context.get(provider_key)', () => {
it('returns a function which authenticates a request and returns a user',
async () => {
it('returns a function which authenticates a request and returns a user', async () => {
const context: Context = new Context();
context.bind(AuthenticationBindings.STRATEGY).to(strategy);
context
Expand All @@ -68,8 +67,7 @@ describe('AuthenticationProvider', () => {
expect(user).to.be.equal(mockUser);
});

it('throws an error if the injected passport strategy is not valid',
async () => {
it('throws an error if the injected passport strategy is not valid', async () => {
const context: Context = new Context();
context.bind(AuthenticationBindings.STRATEGY).to({});
context
Expand All @@ -88,8 +86,7 @@ describe('AuthenticationProvider', () => {
expect(error).to.have.property('message', 'invalid strategy parameter');
});

it('throws Unauthorized error when authentication fails',
async () => {
it('throws Unauthorized error when authentication fails', async () => {
const context: Context = new Context();
context.bind(AuthenticationBindings.STRATEGY).to(strategy);
context
Expand All @@ -115,7 +112,8 @@ describe('AuthenticationProvider', () => {
strategy.setMockUser(mockUser);
provider = new AuthenticationProvider(
() => Promise.resolve(strategy),
u => currentUser = u);
u => (currentUser = u),
);
currentUser = undefined;
}
});
Expand Down
Expand Up @@ -7,7 +7,6 @@ import {expect} from '@loopback/testlab';
import {
authenticate,
getAuthenticateMetadata,
AuthenticationMetadata,
} from '../..';

describe('Authentication', () => {
Expand Down
Expand Up @@ -2,7 +2,6 @@
// Node module: loopback
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
import {ParsedRequest} from '@loopback/rest';
import {Strategy} from 'passport';
import * as http from 'http';

Expand Down
10 changes: 3 additions & 7 deletions packages/authentication/test/unit/metadata-provider.test.ts
Expand Up @@ -6,7 +6,6 @@
import {expect} from '@loopback/testlab';
import {CoreBindings} from '@loopback/core';
import {Context, Provider} from '@loopback/context';
import {ParsedRequest} from '@loopback/rest';
import {
AuthMetadataProvider,
AuthenticationMetadata,
Expand All @@ -28,8 +27,7 @@ describe('AuthMetadataProvider', () => {
beforeEach(givenAuthMetadataProvider);

describe('value()', () => {
it('returns the authentication metadata of a controller method',
async () => {
it('returns the auth metadata of a controller method', async () => {
const authMetadata:
| AuthenticationMetadata
| undefined = await provider.value();
Expand All @@ -40,8 +38,7 @@ describe('AuthMetadataProvider', () => {
});

describe('context.get(provider_key)', () => {
it('returns the authentication metadata of a controller method',
async () => {
it('returns the auth metadata of a controller method', async () => {
const context: Context = new Context();
context.bind(CoreBindings.CONTROLLER_CLASS).to(TestController);
context.bind(CoreBindings.CONTROLLER_METHOD_NAME).to('whoAmI');
Expand All @@ -57,8 +54,7 @@ describe('AuthMetadataProvider', () => {
});
});

it('returns undefined if no authentication metadata is defined',
async () => {
it('returns undefined if no auth metadata is defined', async () => {
const context: Context = new Context();
context
.bind(CoreBindings.CONTROLLER_CLASS)
Expand Down
5 changes: 2 additions & 3 deletions packages/authentication/test/unit/strategy-adapter.test.ts
Expand Up @@ -47,7 +47,7 @@ describe('Strategy Adapter', () => {
request.headers = {testState: 'fail'};
let error;
try {
const user: Object = await adapter.authenticate(request);
await adapter.authenticate(request);
} catch (err) {
error = err;
}
Expand All @@ -62,12 +62,11 @@ describe('Strategy Adapter', () => {
request.headers = {testState: 'error'};
let error;
try {
const user: Object = await adapter.authenticate(request);
await adapter.authenticate(request);
} catch (err) {
error = err;
}
expect(error).to.be.instanceof(HttpErrors.InternalServerError);
});
});
});

1 change: 0 additions & 1 deletion packages/context/src/context.ts
Expand Up @@ -4,7 +4,6 @@
// License text available at https://opensource.org/licenses/MIT

import {Binding, BoundValue, ValueOrPromise} from './binding';
import {inject} from './inject';
import {isPromise} from './is-promise';

export class Context {
Expand Down
1 change: 0 additions & 1 deletion packages/context/src/inject.ts
Expand Up @@ -3,7 +3,6 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import * as assert from 'assert';
import {Reflector} from './reflect';
import {BoundValue, ValueOrPromise} from './binding';
import {Context} from './context';
Expand Down
1 change: 0 additions & 1 deletion packages/context/src/reflect.ts
Expand Up @@ -3,7 +3,6 @@
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import {inject, Constructor} from '..';
import 'reflect-metadata';

/* tslint:disable:no-any */
Expand Down
2 changes: 1 addition & 1 deletion packages/context/src/resolver.ts
Expand Up @@ -4,7 +4,7 @@
// License text available at https://opensource.org/licenses/MIT

import {Context} from './context';
import {Binding, BoundValue, ValueOrPromise} from './binding';
import {BoundValue, ValueOrPromise} from './binding';
import {isPromise} from './is-promise';
import {
describeInjectedArguments,
Expand Down
2 changes: 1 addition & 1 deletion packages/context/test/acceptance/class-level-bindings.ts
Expand Up @@ -4,7 +4,7 @@
// License text available at https://opensource.org/licenses/MIT

import {expect} from '@loopback/testlab';
import {Context, inject, isPromise, Setter, Getter} from '../..';
import {Context, inject, Setter, Getter} from '../..';

const INFO_CONTROLLER = 'controllers.info';

Expand Down
Expand Up @@ -4,7 +4,7 @@
// License text available at https://opensource.org/licenses/MIT

import {expect} from '@loopback/testlab';
import {Context, isPromise} from '../..';
import {Context} from '../..';

describe('Context bindings - Creating and resolving bindings', () => {
let ctx: Context;
Expand Down
1 change: 0 additions & 1 deletion packages/context/test/acceptance/unlocking-bindings.ts
Expand Up @@ -30,7 +30,6 @@ describe(`Context bindings - Unlocking bindings`, () => {
describe('when the context', () => {
context('rebinds the duplicate key with an unlocked binding', () => {
it('does not throw a rebinding error', () => {
const key = 'foo';
const operation = () => ctx.bind('foo').to('baz');
expect(operation).to.not.throw();
});
Expand Down
4 changes: 2 additions & 2 deletions packages/context/test/unit/context.ts
Expand Up @@ -44,7 +44,7 @@ describe('Context', () => {
describe('find', () => {
it('returns matching binding', () => {
const b1 = ctx.bind('foo');
const b2 = ctx.bind('bar');
ctx.bind('bar');
const result = ctx.find('foo');
expect(result).to.be.eql([b1]);
});
Expand All @@ -63,7 +63,7 @@ describe('Context', () => {
describe('findByTag', () => {
it('returns matching binding', () => {
const b1 = ctx.bind('foo').tag('t1');
const b2 = ctx.bind('bar').tag('t2');
ctx.bind('bar').tag('t2');
const result = ctx.findByTag('t1');
expect(result).to.be.eql([b1]);
});
Expand Down
4 changes: 4 additions & 0 deletions packages/context/test/unit/inject.test.ts
Expand Up @@ -12,6 +12,7 @@ import {

describe('function argument injection', () => {
it('can decorate class constructor arguments', () => {
// tslint:disable-next-line:no-unused-variable
class TestClass {
constructor(@inject('foo') foo: string) {}
}
Expand All @@ -28,6 +29,7 @@ describe('function argument injection', () => {
});

it('can retrieve information about injected method arguments', () => {
// tslint:disable-next-line:no-unused-variable
class TestClass {
test(@inject('foo') foo: string) {}
}
Expand Down Expand Up @@ -81,6 +83,7 @@ describe('function argument injection', () => {

describe('property injection', () => {
it('can decorate properties', () => {
// tslint:disable-next-line:no-unused-variable
class TestClass {
@inject('foo') foo: string;
}
Expand All @@ -107,6 +110,7 @@ describe('property injection', () => {

it('cannot decorate static properties', () => {
expect(() => {
// tslint:disable-next-line:no-unused-variable
class TestClass {
@inject('foo') static foo: string;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/context/test/unit/provider.ts
Expand Up @@ -4,7 +4,7 @@
// License text available at https://opensource.org/licenses/MIT

import {expect} from '@loopback/testlab';
import {Provider, Context, Binding} from '../../src';
import {Provider} from '../../src';

describe('Provider', () => {
let provider: Provider<String>;
Expand Down
4 changes: 2 additions & 2 deletions packages/context/test/unit/resolver.test.ts
Expand Up @@ -33,7 +33,7 @@ describe('constructor injection', () => {
}

expect(() => {
const t = instantiateClass(TestClass, ctx) as TestClass;
instantiateClass(TestClass, ctx);
}).to.throw(/Cannot resolve injected arguments/);
});

Expand Down Expand Up @@ -140,7 +140,7 @@ describe('property injection', () => {
}

expect(() => {
const t = instantiateClass(TestClass, ctx) as TestClass;
instantiateClass(TestClass, ctx);
}).to.throw(/Cannot resolve injected property/);
});

Expand Down

0 comments on commit 42416dd

Please sign in to comment.