Skip to content

Commit

Permalink
Merge pull request #44 from frangeris/refactor-functions
Browse files Browse the repository at this point in the history
Refactor for v1.0.0
  • Loading branch information
frangeris authored May 11, 2018
2 parents a85937a + dfb5c4c commit 1cf4a4b
Show file tree
Hide file tree
Showing 26 changed files with 514 additions and 436 deletions.
90 changes: 43 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,53 +47,53 @@ Generate new functions inside a project using CLI (recomended for overwrite `ser

```bash
$ yo pong:func
? Resource name users
? What kind of design? Normal "/users"
? Path (can include parameters) /users/{uid}
? Which HTTP method? GET
? Your function description Get users
create functions/users/get.js
✔ GET /users for "get-users" function generated successfully
? Your function description Get users by uid
create functions/users/id.js
✔ GET /users/{uid} ► functions/users/id.handler (get-users-id)
```

Functions also can be nested resources, running the same above inside the functions folder will create another folder in, eg:
create another resource inside `users` will end with `/users/{id}/<new resource>`
Functions also can be nested resources, just specify the url and `pong` will create the files and nested folders.

```bash
$ pwd
/home/code/myproject/functions/users
/home/code/myproject

dev @ ~/code/myproject/functions/users
dev @ ~/code/myproject
$ yo pong:func
? Resource name orgs
? What kind of design? Normal "/orgs"
? Path (can include parameters) /users/{uid}/orgs
? Which HTTP method? GET
? Your function description Get orgs
create functions/orgs/get.js
✔ GET /orgs for "get-orgs" function generated successfully
? Your function description Get users orgs
create functions/users/orgs/get.js
✔ GET /users/{uid}/orgs ► functions/users/orgs/get.handler (get-users-orgs)

dev @ ~/code/myproject/functions/users
$ ls
total 16K
drwxr-xr-x 3 dev 4,0K jun 27 10:41 .
drwxr-xr-x 4 dev 4,0K jun 27 10:36 ..
-rw-r--r-- 1 dev 266 jun 27 10:36 get.js
drwxr-xr-x 2 dev 4,0K jun 27 10:41 orgs/
total 16K
drwxr-xr-x 3 frang 4,0K feb 14 12:34 .
drwxr-xr-x 5 frang 4,0K feb 14 12:32 ..
-rw-r--r-- 1 frang 268 feb 14 12:32 id.js
drwxr-xr-x 2 frang 4,0K feb 14 12:34 orgs <-------------- Nested folder was created
```
> The `func` subgenerator will save the path with parameters (if have), to change parameters name update the file `serverless.yml` manually.
> The `func` subgenerator will save the path with parameters (if have)
## New updates from here?
## New updates & new nice stuff here?
Thank's to [Yeoman](http://yeoman.io) :raised_hands: we have a [conflict handler](http://yeoman.io/generator/Conflicter.html) out-of-the-box.

> The Conflicter is a module that can be used to detect conflict between files. Each Generator file system helpers pass files through this module to make sure they don't break a user file.
To update a project with the latest features in the boilerplate just run `yo pong:update` inside the project, the generator must detect and automatically inform that an update will be made, the generator will only update global files, if you have modifed "core" files be careful while overwriting in updates.
To update a project with the latest features in the boilerplate just run `yo pong` inside the project, the generator must detect and automatically inform that an update will be made, the generator will only update global files, if you have modifed "core" files be careful while overwriting in updates.

```bash
dev @ ~/code/my-api
$ yo pong:update
$ yo pong
Project detected, updating the boilerplate files instead...
? Your project name (my-api)
```
Resolve conflicts (in case that exists) and continue...

*Note:* it will ask for some fields in case you want to update basic parameters in `serverless.yml`, in case nothing change, hit enter to use existing previous values.

## Now, let's Rock n' roll
Expand All @@ -104,19 +104,11 @@ If you wish to read more about this pattern and comparation with others, please
The basic project contains the following directory structure:
```
.
├── serverless.yml
├── README.md
├── LICENSE
├── package.json
├── .gitignore
├── .env.yml.example
├── templates
│ ├── request.vtl
| └── response.vtl
├── helpers
│ ├── authpolicy.js
│ ├── index.js
│ └── response.js
├── __tests__
├── .vscode
│ ├── debug.js # Debugger for vscode <3
│ ├── event.json # Parameters for request when debugging
│ └── launch.json
├── functions
│ └── aws-authorizer-jwt # AWS authorizer for jwt tokens
│ └── handler.js
Expand All @@ -128,10 +120,23 @@ The basic project contains the following directory structure:
│ ├── post.js
│ ├── put.js
│ └── delete.js
└── tests
├── helpers
│ ├── authpolicy.js
│ ├── index.js
│ └── response.js
├── templates
│ ├── request.vtl
| └── response.vtl
├── tokens
│ ├── aws.json # AWS jwks file
│ └── firebase.json # Firebase tokens
├── .editorconfig
├── .env.yml.example
├── .gitignore
├── LICENSE
├── package.json
├── README.md
├── serverless.yml
```

## Concepts
Expand Down Expand Up @@ -224,9 +229,7 @@ And that's it, API Gateway will run the [authorizer before the lambda execution]

Samples of the `response` **using lambda-proxy integration**, [more info of integrations](https://serverless.com/framework/docs/providers/aws/events/apigateway).
```javascript
const {
response
} = require('path/to/helpers')
const { response } = require('path/to/helpers')
response(201)
// {"statusCode": 201, "body": "{\"data\":null}","headers": {}}
Expand Down Expand Up @@ -291,14 +294,9 @@ module.exports.handler = (event, context, callback) => {
After adding the code bellow, just import the helper lib built-in and that's it... ^_^

```javascript
const {
validate,
resolver,
response
} = require('../../helpers')
const { validate, resolver, response } = require('../../helpers')
module.exports.handler = (event, context, callback) => {
// needed for response scope
global.cb = callback
Expand All @@ -313,10 +311,8 @@ module.exports.handler = (event, context, callback) => {
// { email: '[email protected]' }
validate(event)
// all good!
.then((body) => console.log('passed!'))
/*
400 Bad Request
{"message": "The required options \"password\" are missing"}
Expand Down
25 changes: 13 additions & 12 deletions __tests__/app.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
'use strict';
const path = require('path');
const assert = require('yeoman-assert');
const helpers = require('yeoman-test');
'use strict'
const path = require('path')
const assert = require('yeoman-assert')
const helpers = require('yeoman-test')

describe('serverless-boilerplate:app', () => {
describe('pong:app', () => {
beforeEach(() => {
return helpers.run(path.join(__dirname, '../generators/app'));
});
return helpers.run(path.join(__dirname, '../generators/app'))
})

// Validate structure
// validate structure
it('generate base files', () => {
assert.file([
'__tests__',
'.vscode',
'functions',
'helpers',
'templates',
'tests',
'.env.yml.example',
'.gitignore',
'LICENSE',
'package.json',
'README.md',
'serverless.yml'
]);
});
});
])
})
})
32 changes: 16 additions & 16 deletions __tests__/function.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
'use strict';
const path = require('path');
const assert = require('yeoman-assert');
const helpers = require('yeoman-test');
'use strict'
const path = require('path')
const assert = require('yeoman-assert')
const helpers = require('yeoman-test')

describe('serverless-boilerplate:function', () => {
describe('pong:func', () => {
beforeEach(done => {
helpers
.run(path.join(__dirname, '../generators/func'), {
tmpir: false
})
.withPrompts({
name: 'users',
path: 'users',
method: 'get',
nested: 'Normal "/users"'
description: 'Get users'
})
.withGenerators([
[helpers.createDummyGenerator(), '../generators/app']
])
.on('end', done);
});
.on('end', done)
})

it('generate GET method', () => {
assert.file('functions/users/get.js');
});
assert.file('functions/users/get.js')
})

xit('generate a nested method');
xit('generate a method by id');
xit('generate a nested method')
xit('generate a method by id')

// File serverless.yml do not exists
xit('generate a valid serverless.yml');
xit('must enable cors');
});
xit('generate a valid serverless.yml')
xit('must enable cors')
})
33 changes: 0 additions & 33 deletions __tests__/helpers.js

This file was deleted.

73 changes: 73 additions & 0 deletions __tests__/helpers/response.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
'use strict'
const response = require('../../generators/app/templates/helpers/response')

// eslint-disable-next-line
global.cb = (err, payload) => payload

describe('response helper', () => {
it('should return OK', () => {
let result = response(200)
expect(result).toHaveProperty('body')
expect(JSON.parse(result.body)).toHaveProperty('data')
expect(result).toHaveProperty('headers')
expect(result).toHaveProperty('statusCode')
expect(result.statusCode).toBe(200)
})

it('should return ok without http status', () => {
let result = response({})
expect(result).toHaveProperty('body')
expect(JSON.parse(result.body)).toHaveProperty('data')
expect(result).toHaveProperty('headers')
expect(result).toHaveProperty('statusCode')
expect(result.statusCode).toBe(200)
})

it('should return ok with http status as second parameter', () => {
let result = response({}, 201)
expect(result).toHaveProperty('body')
expect(JSON.parse(result.body)).toHaveProperty('data')
expect(result).toHaveProperty('headers')
expect(result).toHaveProperty('statusCode')
expect(result.statusCode).toBe(201)
})

it('should return not errors bad request', () => {
let result = response(400)
expect(result).toHaveProperty('body')
expect(result).toHaveProperty('headers')
expect(result).toHaveProperty('statusCode')
expect(result.statusCode).toBe(400)
})

it('should return errors bad request', () => {
let result = response(400, [])
expect(result).toHaveProperty('body')
expect(JSON.parse(result.body)).toHaveProperty('errors')
expect(result).toHaveProperty('headers')
expect(result).toHaveProperty('statusCode')
expect(result.statusCode).toBe(400)
})

it('should return unauthorized', () => {
let result = response(401, new Error('Invalid Error'))
let body = JSON.parse(result.body)
expect(result).toHaveProperty('body')
expect(result).toHaveProperty('headers')
expect(result).toHaveProperty('statusCode')
expect(body).toHaveProperty('errors')
expect(body.errors).toContainEqual({ title: 'Invalid Error' })
expect(result.statusCode).toBe(401)
})

it('should return an error', () => {
let result = response(Error('Invalid Error'))
let body = JSON.parse(result.body)
expect(result).toHaveProperty('body')
expect(result).toHaveProperty('headers')
expect(result).toHaveProperty('statusCode')
expect(body).toHaveProperty('errors')
expect(body.errors).toContainEqual({ title: 'Invalid Error' })
expect(result.statusCode).toBe(400)
})
})
11 changes: 11 additions & 0 deletions __tests__/helpers/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"title": "Schema",
"properties": {
"name": {
"type": "string"
}
},
"required": [
"name"
]
}
17 changes: 17 additions & 0 deletions __tests__/helpers/validate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use strict'
const validate = require('../../generators/app/templates/helpers/validate')
const path = require('path')

describe('validate helper', () => {
it('should return error when no parameters', () => {
let check = () => validate()
expect(check).toThrowError()
})

it('should validate against schema', () => {
let check = validate({}, path.join(__dirname, 'schema.json'))
expect(check).toHaveProperty('valid')
expect(check).toHaveProperty('errors')
expect(check.valid).toBeFalsy()
})
})
Loading

0 comments on commit 1cf4a4b

Please sign in to comment.