Serverless & runtimes
Google Cloud Run functions
Register a Functions Framework HTTP function with native context and streaming response support.
@hulla/api-google-cloud-functions mounts an @hulla/api server implementation as an HTTP function for the Google
Cloud Functions Framework. The same Functions Framework boundary is used by Google Cloud Run functions and the
2nd-generation Cloud Functions deployment model.
Prerequisites
This guide starts at the adapter boundary. First define the shared contract from contract authoring, then turn it into the server value mounted below:
// src/api/server.ts
import { defineServer } from '@hulla/api/server'
import { contract } from './contract'
const server = defineServer(contract)
export const implementation = server.implement({
health: ({ response }) => response(200, 'ok'),
users: {
byId: ({ params, response }) =>
response(200, { id: params.id, name: 'Ada' }),
rename: ({ params, body, response }) =>
response(200, { id: params.id, name: body.name }),
},
})defineServer(contract) creates the server authoring scope. implement() requires the handler tree to cover the
contract and returns the complete implementation accepted by mount(). See
server authoring for context, middleware, declared errors, and independently deployable
fragments.
Register the HTTP function
// src/index.ts
import { http } from '@google-cloud/functions-framework'
import { googleCloudFunctionsAdapter } from '@hulla/api-google-cloud-functions'
import { implementation } from './api/server'
const adapter = googleCloudFunctionsAdapter()
export const api = adapter.mount(implementation)
http('api', api)The adapter converts the Functions Framework’s Express-compatible request into the Web Request used by the shared
Fetch executor, then streams its Web Response to the native response with backpressure. The framework’s buffered
rawBody is used when present, so body-parser transformations do not change the bytes decoded by the contract. HEAD
requests execute the corresponding GET route and suppress the response body.
The contract’s basePath must match the path forwarded to the function. A contract with /api matches requests such
as /api/health; a function mounted behind a gateway or rewritten prefix should use the public path seen in
googleRequest.originalUrl.
Client consumption
The Google adapter only hosts the server implementation. Browser, mobile, and service consumers use the ordinary contract-shaped client against the function’s public origin:
import { createClient } from '@hulla/api/client'
import { fetchTransport } from '@hulla/api/fetch'
import { contract } from './api/contract'
export const api = createClient(contract, {
transport: fetchTransport({ baseUrl: 'https://api.example.com' }),
})
export async function getUser(id: string) {
const result = await api.users.byId({ params: { id } })
if (result.status === 200) return result.body
if (result.status === 404) return undefined
throw new Error(`Could not load user: ${result.status}`)
}baseUrl is placed before the contract’s basePath. The returned value is a status-discriminated union, so each
declared response narrows its body and headers. See client authoring and
client integrations.
Native context
Use the adapter object’s context() method for Functions Framework metadata or direct access to the native response:
import { defineServer } from '@hulla/api/server'
import { googleCloudFunctionsAdapter } from '@hulla/api-google-cloud-functions'
const adapter = googleCloudFunctionsAdapter()
const server = defineServer(contract, {
context: adapter.context(({ request, googleRequest, response, route }) => ({
webRequest: request,
executionId: googleRequest.executionId,
spanId: googleRequest.spanId,
response,
route,
})),
})request is the Web Request used for routing and contract decoding. googleRequest is the native Functions
Framework request and includes additions such as rawBody, executionId, spanId, and abortController. response
is the native Express-compatible response. An adapter-native context factory binds every implementation and fragment
from that server definition to this adapter.
Pass onError to the adapter or one mount() call to observe failures or return a replacement Web response:
const handler = adapter.mount(implementation, {
onError({ error, phase, googleRequest, defaultResponse }) {
console.error(phase, googleRequest.executionId, error)
return defaultResponse
},
})Scope
The adapter targets HTTP functions registered through the Google Cloud Functions Framework. CloudEvents, Pub/Sub events, storage events, and other event-driven signatures use different lifecycles and do not use this adapter. Registration, function naming, deployment settings, IAM, ingress, and gateway rewrites remain under application and platform control.