Skip to content
This repository has been archived by the owner on Nov 21, 2019. It is now read-only.

Commit

Permalink
feat: route http methods to relevant functions (#8)
Browse files Browse the repository at this point in the history
* feat: route http methods to relevant functions

* test: route http methods to relevant functions

* chore(packages): update deps
  • Loading branch information
Burak Tasci authored Sep 30, 2017
1 parent 5c0cdfc commit 1629980
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 57 deletions.
17 changes: 9 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,24 @@
"test:ci": "jest --ci --coverage --colors",
"release": "standard-version"
},
"dependencies": {
"azure-functions-ts-essentials": "1.0.0"
},
"devDependencies": {
"@types/jest": "~21.1.0",
"@types/node": "~8.0.30",
"rimraf": "~2.6.1",
"azure-functions-ts-essentials": "1.1.1",
"@types/jest": "~21.1.1",
"@types/node": "~8.0.31",
"rimraf": "~2.6.2",
"webpack": "~3.6.0",
"awesome-typescript-loader": "~3.2.3",
"copy-webpack-plugin": "~4.1.0",
"jest": "~21.2.0",
"jest": "~21.2.1",
"jest-junit-reporter": "~1.1.0",
"ts-jest": "~21.0.1",
"standard-version": "~4.2.0",
"tslint": "~5.7.0",
"backend-tslint-rules": "1.0.0",
"typescript": "~2.5.2"
"typescript": "~2.5.3"
},
"peerDependencies": {
"azure-functions-ts-essentials": ">=1.1.0"
},
"jest": {
"transform": {
Expand Down
2 changes: 1 addition & 1 deletion src/some-function/function.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"bindings": [
{
"type": "httpTrigger",
"route": "some-function",
"route": "some-function/{id?}",
"methods": [
"get"
],
Expand Down
163 changes: 139 additions & 24 deletions src/some-function/some-function.spec.ts
Original file line number Diff line number Diff line change
@@ -1,64 +1,179 @@
import { Context, HttpRequest } from 'azure-functions-ts-essentials';
import { run } from './some-function';

const testData: { name: string } = {
name: 'Azure'
};
import { Context, HttpMethod, HttpRequest, HttpStatusCode } from 'azure-functions-ts-essentials';
import { run, TEST_ID, TEST_REQUEST_BODY } from './some-function';

describe('@azure-seed/azure-functions-typescript', () => {
describe('generator', () => {
it('should be able to return success code w/request body', () => {
describe('some-function', () => {
it('should be able to return success code using Http GET w/`id`', () => {
const mockContext: Context = {
done: (err, response) => {
expect(err).toBeUndefined();

expect(response.status).toEqual(HttpStatusCode.OK);
expect(response.body).toHaveProperty('id');
expect(response.body).toHaveProperty('object');
expect(response.body).toHaveProperty('name');
},
log: () => {/**/}
};

const mockRequest: HttpRequest = {
method: HttpMethod.Get,
params: {
id: TEST_ID
},
query: {},
body: {}
};

run(mockContext, mockRequest);
});

it('should be able to return success code using Http GET', () => {
const mockContext: Context = {
done: (err, response) => {
expect(err).toBeUndefined(); // never call the done function with an `Error`
expect(err).toBeUndefined();

expect(response.status).toEqual(HttpStatusCode.OK);
expect(response.body).toHaveProperty('object');
expect(response.body).toHaveProperty('data');
expect(response.body).toHaveProperty('url');
expect(response.body).toHaveProperty('hasMore');
expect(response.body).toHaveProperty('totalCount');
},
log: () => {/**/}
};

const mockRequest: HttpRequest = {
method: HttpMethod.Get,
params: {},
query: {},
body: {}
};

expect(response.status).toBe(200); // if succeeds, should return 200
expect(response.body).toBe(`Hello ${testData.name}`);
run(mockContext, mockRequest);
});

it('should be able to return success code using Http POST', () => {
const mockContext: Context = {
done: (err, response) => {
expect(err).toBeUndefined();

expect(response.status).toEqual(HttpStatusCode.OK);
expect(response.body).toHaveProperty('id');
expect(response.body).toHaveProperty('object');
expect(response.body).toHaveProperty('name');
},
log: () => {/**/} // use a jest mock here if the logs are important, in this case not
log: () => {/**/}
};

const mockRequest: HttpRequest = {
body: testData,
query: {}
method: HttpMethod.Post,
params: {},
query: {},
body: TEST_REQUEST_BODY
};

run(mockContext, mockRequest);
});

it('should be able to return success code w/request query', () => {
it('should not return success code using Http PATCH', () => {
const mockContext: Context = {
done: (err, response) => {
expect(err).toBeUndefined();

expect(response.status).toBe(200);
expect(response.body).toBe(`Hello ${testData.name}`);
expect(response.status).toEqual(HttpStatusCode.MethodNotAllowed);
expect(response.body).toEqual({
error: {
type: 'not_supported',
message: 'PATCH operations are not supported.'
}
});
},
log: () => {/**/}
};

const mockRequest: HttpRequest = {
body: {},
query: testData
method: HttpMethod.Patch,
params: {
id: TEST_ID
},
query: {},
body: TEST_REQUEST_BODY
};

run(mockContext, mockRequest);
});

it('should be able to return success code using Http PUT', () => {
const mockContext: Context = {
done: (err, response) => {
expect(err).toBeUndefined();

expect(response.status).toEqual(HttpStatusCode.OK);
expect(response.body).toHaveProperty('id');
expect(response.body).toHaveProperty('object');
expect(response.body).toHaveProperty('name');
},
log: () => {/**/}
};

const mockRequest: HttpRequest = {
method: HttpMethod.Put,
params: {
id: TEST_ID
},
query: {},
body: TEST_REQUEST_BODY
};

run(mockContext, mockRequest);
});

it('should be able to return success code using Http DELETE', () => {
const mockContext: Context = {
done: (err, response) => {
expect(err).toBeUndefined();

expect(response.status).toEqual(HttpStatusCode.OK);
expect(response.body).toHaveProperty('deleted');
expect(response.body).toHaveProperty('id');
},
log: () => {/**/}
};

const mockRequest: HttpRequest = {
method: HttpMethod.Delete,
params: {
id: TEST_ID
},
query: {},
body: {}
};

run(mockContext, mockRequest);
});

it('should not return success code w/o any input', () => {
it('should not return success code using any other Http method', () => {
const mockContext: Context = {
done: (err, response) => {
expect(err).toBeUndefined();

expect(response.status).toBe(400);
expect(response.body).toBe('Please pass a name on the query string or in the request body');
expect(response.status).toEqual(HttpStatusCode.MethodNotAllowed);
expect(response.body).toEqual({
error: {
type: 'not_supported',
message: 'Method XYZ not supported.'
}
});
},
log: () => {/**/}
};

const mockRequest: HttpRequest = {
body: {},
query: {}
method: 'XYZ' as HttpMethod,
params: {},
query: {},
body: {}
};

run(mockContext, mockRequest);
Expand Down
137 changes: 122 additions & 15 deletions src/some-function/some-function.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,127 @@
import { Context, HttpRequest, HttpResponse } from 'azure-functions-ts-essentials';
import { Context, HttpMethod, HttpRequest, HttpResponse, HttpStatusCode } from 'azure-functions-ts-essentials';

const OBJECT_NAME = 'someObject';

const getOne = (id: any) => {
return {
status: HttpStatusCode.OK,
body: {
id,
object: OBJECT_NAME,
...TEST_REQUEST_BODY
}
};
};

const getMany = (req: HttpRequest) => {
return {
status: HttpStatusCode.OK,
body: {
object: 'list',
data: [
{
id: TEST_ID,
object: OBJECT_NAME,
...TEST_REQUEST_BODY
}
],
url: '/some-function',
hasMore: false,
totalCount: 1
}
};
};

const insertOne = (req: HttpRequest) => {
return {
status: HttpStatusCode.OK,
body: {
id: TEST_ID,
object: OBJECT_NAME,
...req.body
}
};
};

const patchOne = (req: HttpRequest, id: any) => {
return {
status: HttpStatusCode.MethodNotAllowed,
body: {
error: {
type: 'not_supported',
message: 'PATCH operations are not supported.'
}
}
};
};

const updateOne = (req: HttpRequest, id: any) => {
return {
status: HttpStatusCode.OK,
body: {
id,
object: OBJECT_NAME,
...req.body
}
};
};

const deleteOne = (id: any) => {
return {
status: HttpStatusCode.OK,
body: {
deleted: true,
id
}
};
};

export const TEST_ID = '57ade20771e59f422cc652d9';
export const TEST_REQUEST_BODY: { name: string } = {
name: 'Azure'
};

/**
* Routes the request to the default controller using the relevant method.
*
* @param {Context} context
* @param {HttpRequest} req
* @returns {any}
*/
export function run(context: Context, req: HttpRequest): any {
context.log('TypeScript HTTP trigger function processed a request.');

let res: HttpResponse | null = null;

if (req.query.name || (req.body && req.body.name))
res = {
status: 200,
body: `Hello ${req.query.name || req.body.name}`
};
else
res = {
status: 400,
body: 'Please pass a name on the query string or in the request body'
};
let res: HttpResponse;
const id = req.params.id;

switch (req.method) {
case HttpMethod.Get:
res = id
? getOne(id)
: getMany(req);
break;
case HttpMethod.Post:
res = insertOne(req);
break;
case HttpMethod.Patch:
res = patchOne(req, id);
break;
case HttpMethod.Put:
res = updateOne(req, id);
break;
case HttpMethod.Delete:
res = deleteOne(id);
break;

default:
res = {
status: HttpStatusCode.MethodNotAllowed,
body: {
error: {
type: 'not_supported',
message: `Method ${req.method} not supported.`
}
}
};
}

context.done(undefined, res);
}
Loading

0 comments on commit 1629980

Please sign in to comment.