Skip to content
This repository has been archived by the owner on May 14, 2020. It is now read-only.

Commit

Permalink
Try and compromise between the router and named nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
thewilkybarkid committed Jan 23, 2020
1 parent 55ec0d8 commit 0d43a9a
Show file tree
Hide file tree
Showing 6 changed files with 18 additions and 44 deletions.
2 changes: 0 additions & 2 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import errorHandler from './middleware/error-handler';
import jsonld from './middleware/jsonld';
import routing from './middleware/routing';
import namespaces from './namespaces';
import article from './routes/article';

export type AppState = DefaultState;

Expand Down Expand Up @@ -49,7 +48,6 @@ export default (
}));
app.use(apiDocumentationLink(apiDocumentationPath));
app.use(errorHandler());
app.use(article());
app.use(routing(router));

return app;
Expand Down
2 changes: 2 additions & 0 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AppServiceContext, AppState } from './app';
import Routes from './routes';
import addArticle from './routes/add-article';
import apiDocumentation from './routes/api-documentation';
import article from './routes/article';
import articleList from './routes/article-list';
import entryPoint from './routes/entry-point';

Expand All @@ -12,6 +13,7 @@ export default (): Router<AppState, AppServiceContext> => {
router.get(Routes.ApiDocumentation, '/doc', apiDocumentation());
router.get(Routes.ArticleList, '/articles', articleList());
router.post(Routes.AddArticle, '/articles', addArticle());
router.get(Routes.Article, '/articles/:id', article());
router.get(Routes.EntryPoint, '/', entryPoint());

return router;
Expand Down
5 changes: 3 additions & 2 deletions src/routes/add-article.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import uniqueString from 'unique-string';
import url from 'url';
import { AppContext, AppMiddleware } from '../app';
import { rdf, schema } from '../namespaces';
import Routes from './index';

export default (): AppMiddleware => (
async ({
articles, dataFactory: { namedNode, quad }, request, response,
articles, dataFactory: { namedNode, quad }, request, response, router,
}: AppContext, next: Next): Promise<void> => {
const id = clownface({ dataset: request.dataset }).has(rdf.type, schema.Article).term;

Expand All @@ -27,7 +28,7 @@ export default (): AppMiddleware => (
throw new createHttpError.BadRequest(`Article must have at least one ${termToString(schema('name'))}`);
}

const newId = namedNode(url.resolve(request.origin, 'articles/'.concat(uniqueString())));
const newId = namedNode(url.resolve(request.origin, router.url(Routes.Article, uniqueString())));

[...request.dataset].forEach((originalQuad: Quad): void => {
let newQuad: Quad;
Expand Down
13 changes: 3 additions & 10 deletions src/routes/article.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,8 @@ import ArticleNotFound from '../errors/article-not-found';

export default (): AppMiddleware => (
async ({
path, articles, request, response,
articles, request, response, path,
}: AppContext, next: Next): Promise<void> => {
try {
await next();
return;
} catch (error) {
if (!(error instanceof createHttpError.NotFound)) {
throw error;
}
}

try {
response.dataset = await articles.get(namedNode(url.resolve(request.origin, path)));
} catch (error) {
Expand All @@ -30,5 +21,7 @@ export default (): AppMiddleware => (
}

response.status = OK;

await next();
}
);
1 change: 1 addition & 0 deletions src/routes/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
enum Routes {
'AddArticle' = 'add-article',
'ApiDocumentation' = 'api-documentation',
'Article' = 'article',
'ArticleList' = 'article-list',
'EntryPoint' = 'entry-point',
}
Expand Down
39 changes: 9 additions & 30 deletions test/routes/article.test.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
import {
namedNode,
} from '@rdfjs/data-model';
import { namedNode } from '@rdfjs/data-model';
import createHttpError from 'http-errors';
import { OK } from 'http-status-codes';
import { Response } from 'koa';
import InMemoryArticles from '../../src/adaptors/in-memory-articles';
import Articles from '../../src/articles';
import { WithDataset } from '../../src/middleware/dataset';
import article from '../../src/routes/article';
import createContext from '../context';
import createArticle from '../create-article';
import runMiddleware, { NextMiddleware, throwingNext } from '../middleware';
import { WithDataset } from '../../src/middleware/dataset';
import runMiddleware, { NextMiddleware } from '../middleware';

const makeRequest = async (
path: string,
articles?: Articles,
next: NextMiddleware = throwingNext(new createHttpError.NotFound()),
path: string, articles?: Articles, next?: NextMiddleware,
): Promise<WithDataset<Response>> => (
runMiddleware(article(), createContext({ articles, path }), next)
);
Expand All @@ -31,37 +27,20 @@ describe('article', (): void => {
expect(response.status).toBe(OK);
});

it('should not attempt article retrieval when next middleware throws not found http error', async (): Promise<void> => {
const mockArticles: Articles = {
set: jest.fn(),
get: jest.fn(),
remove: jest.fn(),
contains: jest.fn(),
count: jest.fn(),
[Symbol.asyncIterator]: jest.fn(),
};

const next = jest.fn();
await makeRequest('path-to/article/one', mockArticles, next);
expect(mockArticles.get).toHaveBeenCalledTimes(0);
});

it('should throw an error if article is not found', async (): Promise<void> => {
const response = makeRequest('path-to/article/not-found');

await expect(response).rejects.toBeInstanceOf(createHttpError.NotFound);
await expect(response).rejects.toHaveProperty('message', 'Article http://example.com/path-to/article/not-found could not be found');
});

it('should throw error raised in next middleware', async (): Promise<void> => {
const response = makeRequest('path-to/article/not-found', undefined, throwingNext(new createHttpError.BadRequest()));

await expect(response).rejects.toBeInstanceOf(createHttpError.BadRequest);
});

it('should call the next middleware', async (): Promise<void> => {
const id = namedNode('http://example.com/path-to/article/one');
const articles = new InMemoryArticles();
await articles.set(id, createArticle({ id }));
const next = jest.fn();
await makeRequest('path-to/article/one', undefined, next);

await makeRequest('path-to/article/one', articles, next);

expect(next).toHaveBeenCalledTimes(1);
});
Expand Down

0 comments on commit 0d43a9a

Please sign in to comment.