Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: introduce declarative function signatures
This commit introduces an API that allows developers to explictly register their functions against the framework so that they can declaratively configure thier signature type.
- Loading branch information
1 parent
51cb666
commit 978b26c
Showing
7 changed files
with
253 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// Copyright 2019 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// Functions framework entry point that configures and starts Node.js server | ||
// that runs user's code on HTTP request. | ||
import {getUserFunction} from './loader'; | ||
import {ErrorHandler} from './invoker'; | ||
import {getServer} from './server'; | ||
import {parseOptions, helpText, OptionsError} from './options'; | ||
|
||
export const main = async () => { | ||
try { | ||
const options = parseOptions(); | ||
|
||
if (options.printHelp) { | ||
console.error(helpText); | ||
return; | ||
} | ||
const loadedFunction = await getUserFunction( | ||
options.sourceLocation, | ||
options.target, | ||
options.signatureType | ||
); | ||
if (!loadedFunction) { | ||
console.error('Could not load the function, shutting down.'); | ||
// eslint-disable-next-line no-process-exit | ||
process.exit(1); | ||
} | ||
const {userFunction, signatureType} = loadedFunction; | ||
const server = getServer(userFunction!, signatureType); | ||
const errorHandler = new ErrorHandler(server); | ||
server | ||
.listen(options.port, () => { | ||
errorHandler.register(); | ||
if (process.env.NODE_ENV !== 'production') { | ||
console.log('Serving function...'); | ||
console.log(`Function: ${options.target}`); | ||
console.log(`Signature type: ${signatureType}`); | ||
console.log(`URL: http://localhost:${options.port}/`); | ||
} | ||
}) | ||
.setTimeout(0); // Disable automatic timeout on incoming connections. | ||
} catch (e) { | ||
if (e instanceof OptionsError) { | ||
console.error(e.message); | ||
// eslint-disable-next-line no-process-exit | ||
process.exit(1); | ||
} | ||
throw e; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// Copyright 2021 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
import {HttpFunction, CloudEventFunction, HandlerFunction} from './functions'; | ||
import {SignatureType} from './types'; | ||
|
||
interface RegisteredFunction { | ||
signatureType: SignatureType; | ||
userFunction: HandlerFunction; | ||
} | ||
|
||
/** | ||
* Singleton map to hold the registered functions | ||
*/ | ||
const registrationContainer = new Map<string, RegisteredFunction>(); | ||
|
||
/** | ||
* Helper method to store a registered function in the regsitration container | ||
*/ | ||
const register = ( | ||
functionName: string, | ||
signatureType: SignatureType, | ||
userFunction: HandlerFunction | ||
): void => { | ||
registrationContainer.set(functionName, { | ||
signatureType, | ||
userFunction, | ||
}); | ||
}; | ||
|
||
/** | ||
* Get a declaratively registered function | ||
* @param functionName the name with which the function was registered | ||
* @returns the restered function and signature type or undefined no function matching | ||
* the provided name has been registered. | ||
*/ | ||
export const getRegisteredFunction = ( | ||
functionName: string | ||
): RegisteredFunction | undefined => { | ||
return registrationContainer.get(functionName); | ||
}; | ||
|
||
/** | ||
* The declative function registration API exposed as a default export | ||
* from the root of the npm package. | ||
*/ | ||
export const registrationAPI = { | ||
/** | ||
* Register a function that repsponds to HTTP requests. See | ||
* [Writing HTTP Functions]{@link https://cloud.google.com/functions/docs/http} for | ||
* more details. | ||
* @param functionName the name of the function | ||
* @param handler the function to invoke when handling HTTP requests | ||
*/ | ||
http(functionName: string, handler: HttpFunction): void { | ||
register(functionName, 'http', handler); | ||
}, | ||
|
||
/** | ||
* Register a function that handles cloudevents. See | ||
* [Writing CloudEvent Functions]{@link https://cloud.google.com/functions/docs/writing} | ||
* for more details. | ||
* @param functionName the name of the function | ||
* @param handler the function to trigger when handling cloudevents | ||
*/ | ||
cloudevent(functionName: string, handler: CloudEventFunction): void { | ||
register(functionName, 'cloudevent', handler); | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Copyright 2019 Google LLC | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
import * as assert from 'assert'; | ||
import { | ||
registrationAPI, | ||
getRegisteredFunction, | ||
} from '../src/registration_container'; | ||
|
||
describe('registrationAPI', () => { | ||
it('can register http functions', () => { | ||
registrationAPI.http('httpFunction', () => 'HTTP_PASS'); | ||
const {userFunction, signatureType} = getRegisteredFunction( | ||
'httpFunction' | ||
)!; | ||
assert.deepStrictEqual('http', signatureType); | ||
assert.deepStrictEqual((userFunction as () => string)(), 'HTTP_PASS'); | ||
}); | ||
|
||
it('can register cloudevent functions', () => { | ||
registrationAPI.cloudevent('ceFunction', () => 'CE_PASS'); | ||
const {userFunction, signatureType} = getRegisteredFunction('ceFunction')!; | ||
assert.deepStrictEqual('cloudevent', signatureType); | ||
assert.deepStrictEqual((userFunction as () => string)(), 'CE_PASS'); | ||
}); | ||
}); |