From 5ecb50550bc387ede04c17056484795c9570b131 Mon Sep 17 00:00:00 2001 From: Marco Casula Date: Sat, 12 Sep 2020 21:26:02 -0600 Subject: [PATCH] impl GET ALL and POST (#1) --- src/index.ts | 21 +++++++++++-------- tests/GET.test.ts | 40 ++++++++++++++++++++++++++++++++++++ tests/POST.test.ts | 45 +++++++++++++++++++++++++++++++++++++++++ tests/configure.test.ts | 39 ----------------------------------- 4 files changed, 98 insertions(+), 47 deletions(-) create mode 100644 tests/GET.test.ts create mode 100644 tests/POST.test.ts delete mode 100644 tests/configure.test.ts diff --git a/src/index.ts b/src/index.ts index aa5fa97..aec1974 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,5 @@ -import {normalize} from 'path' -import { Router, Request, Response, NextFunction } from 'express' +import { normalize } from 'path' +import { Router, Request, Response, NextFunction, json, urlencoded } from 'express' export interface Pagination { limit: number @@ -48,7 +48,7 @@ export interface Query { conditions?: Condition[] } -export type DataExtractor = (payload: any) => T +export type DataExtractor = (payload: any) => any export type QueryExtractor = (payload: any) => Query @@ -107,6 +107,8 @@ export interface RestOptions { export default (options: RestOptions): Router => { const router = Router() + router.use(json()) + router.use(urlencoded({ extended: false })) const parent = !options.parent ? '/' : options.parent const path = normalize(`${parent}/${options.version}/${options.resourceName}`) @@ -126,7 +128,7 @@ export default (options: RestOptions): Router => { req.dbQuery = options.query.extractor(req[queryExtractorSource]) } - if (options.parser) { + if (req.method === 'POST' && options.parser) { req.parsedResource = options.parser.extractor(req[options.parser.source]) } @@ -175,15 +177,16 @@ export default (options: RestOptions): Router => { } }) - router.post(`${path}/:id`, async (req, res, next) => { + router.post(`${path}`, async (req, res, next) => { if (!options.dataAdapter.createOne) { next(new Error(`createOne not yet implemented`)) return } + try { - res.send(await options.dataAdapter.createOne(options.resourceName, req.parsedResource)) + res.send(await options.dataAdapter.createOne(options.resourceName, req.parsedResource || req.body)) } catch ({ message }) { - next(new Error(`could not create the resource "${req.dbResourceId}", ${message}`)) + next(new Error(`could not create the new resource, ${message}`)) } }) @@ -205,7 +208,9 @@ export default (options: RestOptions): Router => { return } try { - res.send(await options.dataAdapter.updateOne(options.resourceName, req.dbResourceId, req.parsedResource)) + res.send( + await options.dataAdapter.updateOne(options.resourceName, req.dbResourceId, req.parsedResource || req.body), + ) } catch ({ message }) { next(new Error(`could not update the resource "${req.dbResourceId}", ${message}`)) } diff --git a/tests/GET.test.ts b/tests/GET.test.ts new file mode 100644 index 0000000..66f8092 --- /dev/null +++ b/tests/GET.test.ts @@ -0,0 +1,40 @@ +import * as express from 'express' +import * as request from 'supertest' +import resty, { DataAdapter, RequestDataSource } from '../src' + +interface User { + name: string +} +let database: User[] = [] + +beforeAll(() => { + database = [] +}) + +test('GET ALL', function (done) { + const dataAdapter: DataAdapter = { + selectMany: (resourceName: string): Promise => + new Promise((resolve) => { + resolve(database) + }), + } + + const users = resty({ + version: 'v1', + resourceName: 'users', + dataAdapter, + }) + + const app = express() + app.use(users) + + request(app) + .get('/v1/users') + .expect(200) + .expect('Content-Type', /json/) + .end((err, res) => { + if (err) return done(err) + expect(res.body).toMatchObject(database) + done() + }) +}) diff --git a/tests/POST.test.ts b/tests/POST.test.ts new file mode 100644 index 0000000..fcd7830 --- /dev/null +++ b/tests/POST.test.ts @@ -0,0 +1,45 @@ +import * as express from 'express' +import * as request from 'supertest' +import resty, { DataAdapter, RequestDataSource } from '../src' + +interface User { + name: string +} +let database: User[] = [] + +beforeAll(() => { + database = [] +}) + +const dataAdapter: DataAdapter = { + createOne: (resourceName: string, resource: User): Promise => + new Promise((resolve) => { + database.push(resource) + resolve(resource) + }), +} + +const users = resty({ + version: 'v1', + resourceName: 'users', + dataAdapter, +}) + +const app = express() +app.use(users) + +test('CREATE ONE', function (done) { + const payload = { user: 'marco' } + request(app) + .post('/v1/users') + .send(payload) + .set('Accept', 'application/json') + .expect(200) + .expect('Content-Type', /json/) + .end((err, res) => { + if (err) return done(err) + expect(res.body).toMatchObject(payload) + expect(database.length).toBe(1) + done() + }) +}) diff --git a/tests/configure.test.ts b/tests/configure.test.ts deleted file mode 100644 index 02ecc78..0000000 --- a/tests/configure.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import * as express from 'express' -import * as request from 'supertest' -import resty, { DataAdapter } from '../src' - -let numbersInDatabase: number[] = [] - -beforeAll(() => { - numbersInDatabase = [] -}) - -const dataAdapter: DataAdapter = { - selectMany: (resourceName: string): Promise => - new Promise((resolve) => { - resolve(numbersInDatabase) - }), -} - -describe('minimal configuration (numbers example)', () => { - const numbers = resty({ - version: 'v1', - resourceName: 'numbers', - dataAdapter, - }) - - const app = express() - app.use(numbers) - - it('GET ALL should be accessible', function (done) { - request(app) - .get('/v1/numbers') - .expect('Content-Type', /json/) - .expect(200) - .end((err, res) => { - if (err) return done(err) - expect(res.body).toMatchObject(numbersInDatabase) - done() - }) - }) -})