Write HTTP Cloud Run functions

In Cloud Run functions, you write an HTTP function when you want to invoke a function through an HTTP(S) request. To allow for HTTP semantics, you use the Function Framework and specify the HTTP Function signature to accept HTTP-specific arguments.

Implement HTTP handler functions

The following example shows a basic HTTP function source file for each runtime. See Source directory structure for information about where to locate your source code.

Node.js

ES module

   
 import 
  
 { 
  
 http 
  
 } 
  
 from 
  
 '@google-cloud/functions-framework' 
 ; 
  
 http 
 ( 
 'myHttpFunction' 
 , 
  
 ( 
 req 
 , 
  
 res 
 ) 
  
 = 
>  
 { 
  
 // Your code here 
  
 // Send an HTTP response 
  
 res 
 . 
 send 
 ( 
 'OK' 
 ); 
  
 }); 
 

Add the following dependencies, including "type": "module" in your package.json file:

   
 { 
  
 "dependencies" 
 : 
  
 { 
  
 "@google-cloud/functions-framework" 
 : 
  
 "^3.0.0" 
  
 }, 
  
 "type" 
 : 
  
 "module" 
  
 } 
 

CommonJS module

   
 const 
  
 functions 
  
 = 
  
 require 
 ( 
 '@google-cloud/functions-framework' 
 ); 
  
 // Register an HTTP function with the Functions Framework 
  
 functions 
 . 
 http 
 ( 
 'myHttpFunction' 
 , 
  
 ( 
 req 
 , 
  
 res 
 ) 
  
 = 
>  
 { 
  
 // Your code here 
  
 // Send an HTTP response 
  
 res 
 . 
 send 
 ( 
 'OK' 
 ); 
  
 }); 
 

Add the following dependencies in your package.json file:

   
 { 
  
 "dependencies" 
 : 
  
 { 
  
 "@google-cloud/functions-framework" 
 : 
  
 "^3.0.0" 
  
 } 
  
 } 
 

In Node.js, you register an HTTP handler function with the Functions Framework for Node.js . Your HTTP handler function must be an Express middleware function that accepts the request and response arguments and sends an HTTP response.

Cloud Run automatically parses the request body for you based on the request's Content-Type header using body-parser , so you can access the req.body and req.rawBody objects in your HTTP handler.

The function entry point is the name with which the handler is registered with the Functions Framework. In this example, the entry point is myHttpFunction .

Python

  import 
  
 functions_framework 
 # Register an HTTP function with the Functions Framework 
 @functions_framework 
 . 
 http 
 def 
  
 my_http_function 
 ( 
 request 
 ): 
 # Your code here 
 # Return an HTTP response 
 return 
 'OK' 
 

In Python, you register an HTTP handler function with the Functions Framework for Python . Your HTTP handler function must accept a Flask request object as an argument and return a value that Flask can convert into an HTTP response object .

The function entry point is the name with which the handler is registered with the Functions Framework. In this example, the entry point is my_http_function .

Go

  package 
  
 myhttpfunction 
 import 
  
 ( 
  
 "fmt" 
  
 "net/http" 
  
 "github.com/GoogleCloudPlatform/functions-framework-go/functions" 
 ) 
 func 
  
 init 
 () 
  
 { 
  
 // Register an HTTP function with the Functions Framework 
  
 functions 
 . 
 HTTP 
 ( 
 "MyHTTPFunction" 
 , 
  
 myHTTPFunction 
 ) 
 } 
 // Function myHTTPFunction is an HTTP handler 
 func 
  
 myHTTPFunction 
 ( 
 w 
  
 http 
 . 
 ResponseWriter 
 , 
  
 r 
  
 * 
 http 
 . 
 Request 
 ) 
  
 { 
  
 // Your code here 
  
 // Send an HTTP response 
  
 fmt 
 . 
 Fprintln 
 ( 
 w 
 , 
  
 "OK" 
 ) 
 } 
 

In Go, you register an HTTP handler function with the Functions Framework for Go in your init() function. Your HTTP handler function must use the standard http.HandlerFunc interface to send an HTTP response.

The function entry point is the name with which the handler is registered with the Functions Framework. In this example, the entry point is MyHTTPFunction .

Your HTTP handler function must implement the standard http.HandlerFunc interface. It accepts an http.ResponseWriter interface that your function uses to create a reply to the request, and a pointer to an http.Request struct containing the details of the inbound HTTP request.

Java

  package 
  
 myhttpfunction 
 ; 
 import 
  
 com.google.cloud.functions.HttpFunction 
 ; 
 import 
  
 com.google.cloud.functions.HttpRequest 
 ; 
 import 
  
 com.google.cloud.functions.HttpResponse 
 ; 
 // Define a class that implements the HttpFunction interface 
 public 
  
 class 
 MyHttpFunction 
  
 implements 
  
 HttpFunction 
  
 { 
  
 // Implement the service() method to handle HTTP requests 
  
 @Override 
  
 public 
  
 void 
  
 service 
 ( 
 HttpRequest 
  
 request 
 , 
  
 HttpResponse 
  
 response 
 ) 
  
 throws 
  
 Exception 
  
 { 
  
 // Your code here 
  
 // Send an HTTP response 
  
 response 
 . 
 getWriter 
 (). 
 write 
 ( 
 "OK" 
 ); 
  
 } 
 } 
 

In Java, you use the Functions Framework Java API to implement an HTTP handler class with the HttpFunction interface. The service() method must send an HTTP response.

The function entry point is the fully-qualified name of the HTTP handler class, including the package name. In this example, the entry point is myhttpfunction.MyHttpFunction .

Your service method receives an HttpRequest object describing the inbound HTTP request, and an HttpResponse object that your function populates with a response message.

.NET

  using 
  
 Google.Cloud.Functions.Framework 
 ; 
 using 
  
 Microsoft.AspNetCore.Http 
 ; 
 using 
  
 System.Threading.Tasks 
 ; 
 namespace 
  
 MyProject 
 { 
  
 // Define a class that implements the IHttpFunction interface 
  
 public 
  
 class 
  
 MyHttpFunction 
  
 : 
  
 IHttpFunction 
  
 { 
  
 // Implement the HandleAsync() method to handle HTTP requests 
  
 public 
  
 async 
  
 Task 
  
 HandleAsync 
 ( 
 HttpContext 
  
 context 
 ) 
  
 { 
  
 // Your code here 
  
 // Send an HTTP response 
  
 await 
  
 context 
 . 
 Response 
 . 
 WriteAsync 
 ( 
 "OK" 
 ); 
  
 } 
  
 } 
 } 
 

In .NET runtimes, you use the Functions Framework for .NET to implement an HTTP handler class with the IHttpFunction interface. The HandleAsync() method accepts a standard ASP.NET HttpContext object as an argument and must send an HTTP response.

The function entry point is the fully-qualified name of the HTTP handler class, including the namespace. In this example, the entry point is MyProject.MyHttpFunction .

Ruby

  require 
  
 "functions_framework" 
 # Register an HTTP function with the Functions Framework 
 FunctionsFramework 
 . 
 http 
  
 "my_http_function" 
  
 do 
  
 | 
 request 
 | 
  
 # Your code here 
  
 # Return an HTTP response 
  
 "OK" 
 end 
 

In Ruby, you register an HTTP handler function with the Functions Framework for Ruby . Your HTTP handler function must accept a Rack request object as an argument and return a value that can be used as an HTTP response .

The function entry point is the name with which the handler is registered with the Functions Framework. In this example, the entry point is my_http_function .

PHP

 < ?php 
 use Google\CloudFunctions\FunctionsFramework; 
 use Psr\Http\Message\ServerRequestInterface; 
 // Register an HTTP function with the Functions Framework 
 FunctionsFramework::http('myHttpFunction', 'myHttpHandler'); 
 // Define your HTTP handler 
 function myHttpHandler(ServerRequestInterface $request): string 
 { 
 // Your code here 
 // Return an HTTP response 
 return 'OK'; 
 } 
 

In PHP, you register an HTTP handler function with the Functions Framework for PHP . Your HTTP handler function must accept an argument that implements the PSR-7 ServerRequestInterface interface, and must return an HTTP response as either a string or an object that implements the PSR-7 ResponseInterface interface.

The function entry point is the name with which the handler is registered with the Functions Framework. In this example, the entry point is myHttpFunction .

HTTP request and responses

When you register an HTTP handler function with the Functions Framework, your HTTP handler can inspect the request method and perform different actions based on the method.

When you configure an event provider to send HTTP requests to your Cloud Run function, your function sends an HTTP response. If the function creates background tasks (such as with threads, futures, JavaScript Promise objects, callbacks, or system processes), you must terminate or otherwise resolve these tasks before sending an HTTP response. Any tasks not terminated before the HTTP response is sent might not be completed, and might cause undefined behavior.

Handling CORs / CORS support

Cross-Origin Resource Sharing (CORS) is a way to let applications running on one domain access resources from another domain. For example, you might need to let your domain make requests to the Cloud Run functions domain to access your function.

To allow cross-origin requests to your function, set the Access-Control-Allow-Origin header as appropriate on your HTTP response. For preflighted cross-origin requests , you must respond to the preflight OPTIONS request with a 204 response code and additional headers.

Node.js

  const 
  
 functions 
  
 = 
  
 require 
 ( 
 '@google-cloud/functions-framework' 
 ); 
 /** 
 * HTTP function that supports CORS requests. 
 * 
 * @param {Object} req Cloud Function request context. 
 * @param {Object} res Cloud Function response context. 
 */ 
 functions 
 . 
 http 
 ( 
 'corsEnabledFunction' 
 , 
  
 ( 
 req 
 , 
  
 res 
 ) 
  
 = 
>  
 { 
  
 // Set CORS headers for preflight requests 
  
 // Allows GETs from any origin with the Content-Type header 
  
 // and caches preflight response for 3600s 
  
 res 
 . 
 set 
 ( 
 'Access-Control-Allow-Origin' 
 , 
  
 '*' 
 ); 
  
 if 
  
 ( 
 req 
 . 
 method 
  
 === 
  
 'OPTIONS' 
 ) 
  
 { 
  
 // Send response to OPTIONS requests 
  
 res 
 . 
 set 
 ( 
 'Access-Control-Allow-Methods' 
 , 
  
 'GET' 
 ); 
  
 res 
 . 
 set 
 ( 
 'Access-Control-Allow-Headers' 
 , 
  
 'Content-Type' 
 ); 
  
 res 
 . 
 set 
 ( 
 'Access-Control-Max-Age' 
 , 
  
 '3600' 
 ); 
  
 res 
 . 
 status 
 ( 
 204 
 ). 
 send 
 ( 
 '' 
 ); 
  
 } 
  
 else 
  
 { 
  
 res 
 . 
 send 
 ( 
 'Hello World!' 
 ); 
  
 } 
 }); 
 

Python

  import 
  
 functions_framework 
 @functions_framework 
 . 
 http 
 def 
  
 cors_enabled_function 
 ( 
 request 
 ): 
 # For more information about CORS and CORS preflight requests, see: 
 # https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request 
 # Set CORS headers for the preflight request 
 if 
 request 
 . 
 method 
 == 
 "OPTIONS" 
 : 
 # Allows GET requests from any origin with the Content-Type 
 # header and caches preflight response for an 3600s 
 headers 
 = 
 { 
 "Access-Control-Allow-Origin" 
 : 
 "*" 
 , 
 "Access-Control-Allow-Methods" 
 : 
 "GET" 
 , 
 "Access-Control-Allow-Headers" 
 : 
 "Content-Type" 
 , 
 "Access-Control-Max-Age" 
 : 
 "3600" 
 , 
 } 
 return 
 ( 
 "" 
 , 
 204 
 , 
 headers 
 ) 
 # Set CORS headers for the main request 
 headers 
 = 
 { 
 "Access-Control-Allow-Origin" 
 : 
 "*" 
 } 
 return 
 ( 
 "Hello World!" 
 , 
 200 
 , 
 headers 
 ) 
 

Go

  // Package http provides a set of HTTP Cloud Functions samples. 
 package 
  
 http 
 import 
  
 ( 
  
 "fmt" 
  
 "net/http" 
  
 "github.com/GoogleCloudPlatform/functions-framework-go/functions" 
 ) 
 // CORSEnabledFunction is an example of setting CORS headers. 
 // For more information about CORS and CORS preflight requests, see 
 // https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request. 
 func 
  
 CORSEnabledFunction 
 ( 
 w 
  
 http 
 . 
 ResponseWriter 
 , 
  
 r 
  
 * 
 http 
 . 
 Request 
 ) 
  
 { 
  
 // Set CORS headers for the preflight request 
  
 if 
  
 r 
 . 
 Method 
  
 == 
  
 http 
 . 
 MethodOptions 
  
 { 
  
 w 
 . 
 Header 
 (). 
 Set 
 ( 
 "Access-Control-Allow-Origin" 
 , 
  
 "*" 
 ) 
  
 w 
 . 
 Header 
 (). 
 Set 
 ( 
 "Access-Control-Allow-Methods" 
 , 
  
 "POST" 
 ) 
  
 w 
 . 
 Header 
 (). 
 Set 
 ( 
 "Access-Control-Allow-Headers" 
 , 
  
 "Content-Type" 
 ) 
  
 w 
 . 
 Header 
 (). 
 Set 
 ( 
 "Access-Control-Max-Age" 
 , 
  
 "3600" 
 ) 
  
 w 
 . 
 WriteHeader 
 ( 
 http 
 . 
 StatusNoContent 
 ) 
  
 return 
  
 } 
  
 // Set CORS headers for the main request. 
  
 w 
 . 
 Header 
 (). 
 Set 
 ( 
 "Access-Control-Allow-Origin" 
 , 
  
 "*" 
 ) 
  
 fmt 
 . 
 Fprint 
 ( 
 w 
 , 
  
 "Hello, World!" 
 ) 
 } 
 func 
  
 init 
 () 
  
 { 
  
 functions 
 . 
 HTTP 
 ( 
 "CORSEnabledFunction" 
 , 
  
 CORSEnabledFunction 
 ) 
 } 
 

Java

  import 
  
 com.google.cloud.functions.HttpFunction 
 ; 
 import 
  
 com.google.cloud.functions.HttpRequest 
 ; 
 import 
  
 com.google.cloud.functions.HttpResponse 
 ; 
 import 
  
 java.io.BufferedWriter 
 ; 
 import 
  
 java.io.IOException 
 ; 
 import 
  
 java.net.HttpURLConnection 
 ; 
 public 
  
 class 
 CorsEnabled 
  
 implements 
  
 HttpFunction 
  
 { 
  
 // corsEnabled is an example of setting CORS headers. 
  
 // For more information about CORS and CORS preflight requests, see 
  
 // https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request. 
  
 @Override 
  
 public 
  
 void 
  
 service 
 ( 
 HttpRequest 
  
 request 
 , 
  
 HttpResponse 
  
 response 
 ) 
  
 throws 
  
 IOException 
  
 { 
  
 // Set CORS headers 
  
 //   Allows GETs from any origin with the Content-Type 
  
 //   header and caches preflight response for 3600s 
  
 response 
 . 
 appendHeader 
 ( 
 "Access-Control-Allow-Origin" 
 , 
  
 "*" 
 ); 
  
 if 
  
 ( 
 "OPTIONS" 
 . 
 equals 
 ( 
 request 
 . 
 getMethod 
 ())) 
  
 { 
  
 response 
 . 
 appendHeader 
 ( 
 "Access-Control-Allow-Methods" 
 , 
  
 "GET" 
 ); 
  
 response 
 . 
 appendHeader 
 ( 
 "Access-Control-Allow-Headers" 
 , 
  
 "Content-Type" 
 ); 
  
 response 
 . 
 appendHeader 
 ( 
 "Access-Control-Max-Age" 
 , 
  
 "3600" 
 ); 
  
 response 
 . 
 setStatusCode 
 ( 
 HttpURLConnection 
 . 
 HTTP_NO_CONTENT 
 ); 
  
 return 
 ; 
  
 } 
  
 // Handle the main request. 
  
 BufferedWriter 
  
 writer 
  
 = 
  
 response 
 . 
 getWriter 
 (); 
  
 writer 
 . 
 write 
 ( 
 "CORS headers set successfully!" 
 ); 
  
 } 
 } 
 

.NET

  using 
  
 Google.Cloud.Functions.Framework 
 ; 
 using 
  
 Microsoft.AspNetCore.Http 
 ; 
 using 
  
 System.Net 
 ; 
 using 
  
 System.Threading.Tasks 
 ; 
 namespace 
  
 Cors 
 ; 
 // For more information about CORS and CORS preflight requests, see 
 // https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request. 
 public 
  
 class 
  
 Function 
  
 : 
  
 IHttpFunction 
 { 
  
 public 
  
 async 
  
 Task 
  
 HandleAsync 
 ( 
 HttpContext 
  
 context 
 ) 
  
 { 
  
 HttpRequest 
  
 request 
  
 = 
  
 context 
 . 
 Request 
 ; 
  
 HttpResponse 
  
 response 
  
 = 
  
 context 
 . 
 Response 
 ; 
  
 // Set CORS headers 
  
 //   Allows GETs from any origin with the Content-Type 
  
 //   header and caches preflight response for 3600s 
  
 response 
 . 
 Headers 
 . 
 Append 
 ( 
 "Access-Control-Allow-Origin" 
 , 
  
 "*" 
 ); 
  
 if 
  
 ( 
 HttpMethods 
 . 
 IsOptions 
 ( 
 request 
 . 
 Method 
 )) 
  
 { 
  
 response 
 . 
 Headers 
 . 
 Append 
 ( 
 "Access-Control-Allow-Methods" 
 , 
  
 "GET" 
 ); 
  
 response 
 . 
 Headers 
 . 
 Append 
 ( 
 "Access-Control-Allow-Headers" 
 , 
  
 "Content-Type" 
 ); 
  
 response 
 . 
 Headers 
 . 
 Append 
 ( 
 "Access-Control-Max-Age" 
 , 
  
 "3600" 
 ); 
  
 response 
 . 
 StatusCode 
  
 = 
  
 ( 
 int 
 ) 
  
 HttpStatusCode 
 . 
 NoContent 
 ; 
  
 return 
 ; 
  
 } 
  
 await 
  
 response 
 . 
 WriteAsync 
 ( 
 "CORS headers set successfully!" 
 , 
  
 context 
 . 
 RequestAborted 
 ); 
  
 } 
 } 
 

Ruby

  FunctionsFramework 
 . 
 http 
  
 "cors_enabled_function" 
  
 do 
  
 | 
 request 
 | 
  
 # For more information about CORS and CORS preflight requests, see 
  
 # https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request 
  
 # for more information. 
  
 # Set CORS headers for the preflight request 
  
 if 
  
 request 
 . 
 options? 
  
 # Allows GET requests from any origin with the Content-Type 
  
 # header and caches preflight response for an 3600s 
  
 headers 
  
 = 
  
 { 
  
 "Access-Control-Allow-Origin" 
  
 = 
>  
 "*" 
 , 
  
 "Access-Control-Allow-Methods" 
  
 = 
>  
 "GET" 
 , 
  
 "Access-Control-Allow-Headers" 
  
 = 
>  
 "Content-Type" 
 , 
  
 "Access-Control-Max-Age" 
  
 = 
>  
 "3600" 
  
 } 
  
 [ 
 204 
 , 
  
 headers 
 , 
  
 []] 
  
 else 
  
 # Set CORS headers for the main request 
  
 headers 
  
 = 
  
 { 
  
 "Access-Control-Allow-Origin" 
  
 = 
>  
 "*" 
  
 } 
  
 [ 
 200 
 , 
  
 headers 
 , 
  
 [ 
 "Hello World!" 
 ]] 
  
 end 
 end 
 

PHP

  use Psr\Http\Message\ResponseInterface; 
 use Psr\Http\Message\ServerRequestInterface; 
 use GuzzleHttp\Psr7\Response; 
 function corsEnabledFunction(ServerRequestInterface $request): ResponseInterface 
 { 
 // Set CORS headers for preflight requests 
 // Allows GETs from any origin with the Content-Type header 
 // and caches preflight response for 3600s 
 $headers = ['Access-Control-Allow-Origin' => '*']; 
 if ($request->getMethod() === 'OPTIONS') { 
 // Send response to OPTIONS requests 
 $headers = array_merge($headers, [ 
 'Access-Control-Allow-Methods' => 'GET', 
 'Access-Control-Allow-Headers' => 'Content-Type', 
 'Access-Control-Max-Age' => '3600' 
 ]); 
 return new Response(204, $headers, ''); 
 } else { 
 return new Response(200, $headers, 'Hello World!'); 
 } 
 } 
 

If CORS is not set up properly, you might see errors like the following:

XMLHttpRequest cannot load https:// YOUR_FUNCTION_URL 
.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'https:// YOUR_DOMAIN 
' is therefore not allowed access.

CORS limitations

For preflighted cross-origin requests, preflight OPTIONS requests are sent without an Authorization header, so they will be rejected on all HTTP functions that require authentication. Because the preflight requests fail, the main requests will also fail. To work around this limitation, use one of the following options:

What's next

Design a Mobile Site
View Site in Mobile | Classic
Share by: