Unify order of properties and methods in services (#3353)

I find having these in a consistent order makes the services much faster to read.

This is the order I’ve generally been using:

1. Category
2. Route
3. Examples
4. Rendering
5. Other helpers (`fetch()`, `transform()`)
6. `handle()`
This commit is contained in:
Paul Melnikow
2019-04-23 21:36:04 -04:00
committed by GitHub
parent 12191e20c4
commit 1cdcaabd38
48 changed files with 769 additions and 740 deletions

View File

@@ -70,26 +70,6 @@ const serviceDataSchema = Joi.object({
.required()
module.exports = class BaseService {
constructor({ sendAndCacheRequest }, { handleInternalErrors }) {
this._requestFetcher = sendAndCacheRequest
this._handleInternalErrors = handleInternalErrors
}
static render(props) {
throw new Error(`render() function not implemented for ${this.name}`)
}
/**
* Asynchronous function to handle requests for this service. Take the route
* parameters (as defined in the `route` property), perform a request using
* `this._sendAndCacheRequest`, and return the badge data.
*/
async handle(namedParams, queryParams) {
throw new Error(`Handler not implemented for ${this.constructor.name}`)
}
// Metadata
/**
* Name of the category to sort this badge into (eg. "build"). Used to sort
* the badges on the main shields.io website.
@@ -98,6 +78,10 @@ module.exports = class BaseService {
throw new Error(`Category not set for ${this.name}`)
}
static get isDeprecated() {
return false
}
/**
* Returns an object:
* - base: (Optional) The base path of the routes for this service. This is
@@ -127,17 +111,14 @@ module.exports = class BaseService {
throw new Error(`Route not defined for ${this.name}`)
}
static get isDeprecated() {
return false
}
/**
* Default data for the badge. Can include label, logo, and color. These
* defaults are used if the value is neither included in the service data
* from the handler nor overridden by the user via query parameters.
*/
static get defaultBadgeData() {
return {}
static get _cacheLength() {
const cacheLengths = {
build: 30,
license: 3600,
version: 300,
debug: 60,
}
return cacheLengths[this.category]
}
/**
@@ -172,6 +153,15 @@ module.exports = class BaseService {
return []
}
/**
* Default data for the badge. Can include label, logo, and color. These
* defaults are used if the value is neither included in the service data
* from the handler nor overridden by the user via query parameters.
*/
static get defaultBadgeData() {
return {}
}
static validateDefinition() {
assertValidCategory(this.category, `Category for ${this.name}`)
@@ -219,14 +209,53 @@ module.exports = class BaseService {
return result
}
static get _cacheLength() {
const cacheLengths = {
build: 30,
license: 3600,
version: 300,
debug: 60,
}
return cacheLengths[this.category]
static render(props) {
throw new Error(`render() function not implemented for ${this.name}`)
}
constructor({ sendAndCacheRequest }, { handleInternalErrors }) {
this._requestFetcher = sendAndCacheRequest
this._handleInternalErrors = handleInternalErrors
}
async _request({ url, options = {}, errorMessages = {} }) {
const logTrace = (...args) => trace.logTrace('fetch', ...args)
logTrace(emojic.bowAndArrow, 'Request', url, '\n', options)
const { res, buffer } = await this._requestFetcher(url, options)
logTrace(emojic.dart, 'Response status code', res.statusCode)
return checkErrorResponse.asPromise(errorMessages)({ buffer, res })
}
static _validate(
data,
schema,
{
prettyErrorMessage = 'invalid response data',
includeKeys = false,
allowAndStripUnknownKeys = true,
} = {}
) {
return validate(
{
ErrorClass: InvalidResponse,
prettyErrorMessage,
includeKeys,
traceErrorMessage: 'Response did not match schema',
traceSuccessMessage: 'Response after validation',
allowAndStripUnknownKeys,
},
data,
schema
)
}
/**
* Asynchronous function to handle requests for this service. Take the route
* parameters (as defined in the `route` property), perform a request using
* `this._sendAndCacheRequest`, and return the badge data.
*/
async handle(namedParams, queryParams) {
throw new Error(`Handler not implemented for ${this.constructor.name}`)
}
_handleError(error) {
@@ -398,35 +427,4 @@ module.exports = class BaseService {
})
)
}
static _validate(
data,
schema,
{
prettyErrorMessage = 'invalid response data',
includeKeys = false,
allowAndStripUnknownKeys = true,
} = {}
) {
return validate(
{
ErrorClass: InvalidResponse,
prettyErrorMessage,
includeKeys,
traceErrorMessage: 'Response did not match schema',
traceSuccessMessage: 'Response after validation',
allowAndStripUnknownKeys,
},
data,
schema
)
}
async _request({ url, options = {}, errorMessages = {} }) {
const logTrace = (...args) => trace.logTrace('fetch', ...args)
logTrace(emojic.bowAndArrow, 'Request', url, '\n', options)
const { res, buffer } = await this._requestFetcher(url, options)
logTrace(emojic.dart, 'Response status code', res.statusCode)
return checkErrorResponse.asPromise(errorMessages)({ buffer, res })
}
}

View File

@@ -25,22 +25,16 @@ const queryParamSchema = Joi.object({
.required()
class DummyService extends BaseService {
static render({ namedParamA, queryParamA }) {
return {
message: `Hello namedParamA: ${namedParamA} with queryParamA: ${queryParamA}`,
}
}
async handle({ namedParamA }, { queryParamA }) {
return this.constructor.render({ namedParamA, queryParamA })
}
static get category() {
return 'other'
}
static get defaultBadgeData() {
return { label: 'cat', namedLogo: 'appveyor' }
static get route() {
return {
base: 'foo',
pattern: ':namedParamA',
queryParamSchema,
}
}
static get examples() {
@@ -54,13 +48,19 @@ class DummyService extends BaseService {
]
}
static get route() {
static get defaultBadgeData() {
return { label: 'cat', namedLogo: 'appveyor' }
}
static render({ namedParamA, queryParamA }) {
return {
base: 'foo',
pattern: ':namedParamA',
queryParamSchema,
message: `Hello namedParamA: ${namedParamA} with queryParamA: ${queryParamA}`,
}
}
async handle({ namedParamA }, { queryParamA }) {
return this.constructor.render({ namedParamA, queryParamA })
}
}
describe('BaseService', function() {

View File

@@ -38,22 +38,22 @@ function deprecatedService(attrs) {
return category
}
static get route() {
return route
}
static get isDeprecated() {
return true
}
static get defaultBadgeData() {
return { label }
static get route() {
return route
}
static get examples() {
return examples
}
static get defaultBadgeData() {
return { label }
}
async handle() {
throw new Deprecated({ prettyMessage: message })
}

View File

@@ -40,18 +40,6 @@ module.exports = function redirector(attrs) {
} = Joi.attempt(attrs, attrSchema, `Redirector for ${attrs.route.base}`)
return class Redirector extends BaseService {
static get category() {
return category
}
static get route() {
return route
}
static get isDeprecated() {
return true
}
static get name() {
if (name) {
return name
@@ -62,6 +50,18 @@ module.exports = function redirector(attrs) {
}
}
static get category() {
return category
}
static get isDeprecated() {
return true
}
static get route() {
return route
}
static register({ camp, requestCounter }) {
const { regex, captureNames } = prepareRoute(this.route)