Tiny tooling for headless HTTP-based lambda functions
npm install lessttp
Minimum viable async setup for Netlify Functions with built-in:
Content-Type=application/json
when you return a JSON object in the body- 200 success status when there are no errors
- Error handling
- Parses deeply nested query string objects as JSON
- Validates that
GET
HTTP method is used
const http = require('lessttp')
const StarWars = require('./services/StarWars')
exports.handler = http.function(async (request) => {
const allJedi = await StarWars.queryJedi()
return {
body: allJedi,
}
})
const http = require('lessttp')
const StarWars = require('./services/StarWars')
exports.handler = http.function(async (request) => {
try {
const allJedi = await StarWars.queryJedi()
return {
body: allJedi,
}
} catch (error) {
console.error(error)
return {
statusCode: 502,
body: 'You were the chosen one!',
}
}
})
const http = require('lessttp')
const StarWars = require('./services/StarWars')
const baseUrl = '/.netlify/functions'
exports.handler = http.function({
path: `${baseUrl}/jedi/:id`,
async handler(request) {
const { id } = request.params
const jedi = await (id ? StarWars.getJediById(id) : StarWars.queryJedi())
return {
body: jedi,
}
},
})
While the request query string is already parsed as JSON, the built-in middleware further uses qs.parse
which supports deeply nested objects.
const http = require('lessttp')
const StarWars = require('./services/StarWars')
const baseUrl = '/.netlify/functions'
exports.handler = http.function({
path: `${baseUrl}/jedi`,
async handler(request) {
const { id, filter: { name, side } } = request.query
const jedi = await (id ? StarWars.getJediById(id) : StarWars.queryJedi({ name, side }))
return {
body: jedi,
}
},
})
The request body is automatically parsed as JSON when available:
const http = require('lessttp')
const StarWars = require('./services/StarWars')
exports.handler = http.function({
method: 'POST',
async handler(request) {
const jedi = await StarWars.createJedi(request.body)
return {
body: jedi,
}
}
})
Validate request body, headers, params, or query using powerful JSON schemas:
const http = require('lessttp')
const StarWars = require('./services/StarWars')
exports.handler = http.function({
method: 'POST',
request: {
body: {
type: 'object',
properties: {
name: { type: 'string' },
side: { type: 'string', enum: ['light', 'neutral', 'dark'] },
},
required: ['name', 'side'],
additionalProperties: false,
}
},
async handler(request) {
const jedi = await StarWars.createJedi(request.body)
return {
body: jedi,
}
}
})
Easily combine multiple handlers to create REST endpoints:
const http = require('lessttp')
const StarWars = require('./services/StarWars')
exports.handler = http.resource({
async get() {
const allJedi = await StarWars.queryJedi()
return {
body: allJedi,
}
},
post: {
request: {
body: {
type: 'object',
properties: {
name: { type: 'string' },
side: { type: 'string', enum: ['light', 'neutral', 'dark'] },
},
required: ['name', 'side'],
additionalProperties: false,
}
},
async handler(request) {
const jedi = await StarWars.createJedi(request.body)
return {
body: jedi,
}
},
},
})
You can override individual functions by key:
const http = require('lessttp')
const StarWars = require('./services/StarWars')
exports.handler = http.function({
middleware: {
async parseBody(request) {
if (request.body) {
try {
request.body = JSON.parse(request.body)
} catch (error) {
return {
statusCode: 400,
body: 'You were supposed to bring balance to the Force!'
}
}
}
}
},
async handler(request) {
const jedi = await StarWars.createJedi(request.body)
return {
body: jedi,
}
}
})
Replace the middleware array entirely:
const http = require('lessttp')
const { alias, validateHttpMethod } = require('lessttp/middleware')
const StarWars = require('./services/StarWars')
exports.handler = http.function({
method: 'POST',
middleware() {
return [
alias({ httpMethod: 'method', queryStringParameters: 'query' }),
validateHttpMethod(this.method),
async function parseBody(request) {
if (request.body) {
try {
request.body = JSON.parse(request.body)
} catch (error) {
return {
statusCode: 400,
body: 'You were supposed to bring balance to the Force!'
}
}
}
}
]
},
async handler(request) {
const jedi = await StarWars.createJedi(request.body)
return {
body: jedi,
}
}
})
Disable the middleware completely and do everything yourself in the handler:
const http = require('lessttp')
const StarWars = require('./services/StarWars')
exports.handler = http.function({
method: 'POST',
middleware: null,
async handler(request) {
let body
try {
body = JSON.parse(request.body)
} catch (error) {
console.error(error)
return {
statusCode: 400,
body: 'You were supposed to bring balance to the Force!'
}
}
try {
const jedi = await StarWars.createJedi(body)
return {
body: jedi,
}
} catch (error) {
console.error(error)
return {
statusCode: 502,
body: 'You were the chosen one!',
}
}
}
})