Module tencent_scf::builtin::api[][src]

This is supported on crate feature builtin-api-gateway only.

Module for auto serialization/deserialization of Web API Gateway Trigger.

Overview

This modules implements auto serialization/deserialization of Web API Gateway Trigger events and responses as described in API Gateway Trigger Overview.

http::request::Request, http::response::Response and http::response::Builder are re-exported and user can directly use these types when constructing a serverless compute function.

Note

There are some design decisions and limitation users may want to pay attention to:

  • Since the query string is already parsed by the upstream cloud, we found it counter-productive to re-encode it and put it back into the uri of the request. So we leave the path as-is as the uri of the request and use the extension of the request to hold the parsed query string. User can acquire the String-keyed query string as follows:
    use tencent_scf::builtin::api::ext;
    // Assume `req` is the incoming request
    let query_string = &req.extensions().get::<ext::QueryString>().unwrap().0;
  • It is allowed to set path parameters, header parameters and query string parameters in the API dashboard. We wrap these parameters in ext::PathParameters, ext::HeaderParameters, and ext::QueryStringParameters and put them in the extension of the request as well. User can retrieve them like ext::QueryString above.
  • The request context is wrapped in ext::RequestContext and can be retrieved just like above.
  • Multi-valued header is not supported in request due to a limitation in the format used by the upstream cloud protocol.
  • Currently we only support Request<T>/Response<T> where T is String or Vec<u8>.
  • For Request<String>/Response<String>, we assume the body is a utf-8 string and we don't do any processing. For Request<Vec<u8>>/Response<Vec<u8>> however, we assume user wants a binary format, so we will assume that the incoming request is base64 encoded (as required by the cloud), and the runtime will try to decode the incoming event. We will also base64 encode the response before sending it out as well (as required by the cloud).

Example

Here is an example of a very primitive reverse proxy:

use std::{io::Read, str::FromStr};

use tencent_scf::{
    builtin::api::{
        ext,
        http::{
            header::{HeaderName, HeaderValue},
            Method,
        },
        Request, Response, ResponseBuilder,
    },
    make_scf, start, Context,
};
extern crate ureq;

const FORWARD_TARGET: &str = "http://example.com";

let scf = make_scf(
    |req: Request<Vec<u8>>, _context: Context| -> Result<Response<Vec<u8>>, ureq::Error> {
        // Check method
        if *req.method() == Method::GET {
            let forward_req = ureq::get(&format!("{}{}", FORWARD_TARGET, req.uri()));
            // Retrieve query string
            let query_string = &req.extensions().get::<ext::QueryString>().unwrap().0;
            let forward_req = query_string
                .iter()
                .fold(forward_req, |req, (key, value)| req.query(key, value));
            // Set headers
            let forward_req = req
                .headers()
                .iter()
                .fold(forward_req, |req, (header, value)| {
                    req.set(header.as_str(), value.to_str().unwrap())
                });
            // Send request
            let resp = forward_req.call()?;
            // Build response
            let mut forward_resp = ResponseBuilder::new().status(resp.status());
            let headers = forward_resp.headers_mut().unwrap();
            // Set headers
            for header in resp.headers_names() {
                for value in resp.all(&header) {
                    headers.append(
                        HeaderName::from_str(&header).unwrap(),
                        HeaderValue::from_str(value).unwrap(),
                    );
                }
            }
            // Read response
            let mut reader = resp.into_reader();
            let mut bytes: Vec<u8> = Vec::new();
            reader.read_to_end(&mut bytes)?;
            // Assemble response
            Ok(forward_resp.body(bytes).unwrap())
        } else {
            Ok(ResponseBuilder::new()
                .status(501)
                .body("Only GET method is supported".to_string().into_bytes())
                .unwrap())
        }
    },
);
start(scf);

Re-exports

pub use http;
pub use http::request::Request;
pub use http::response::Builder as ResponseBuilder;
pub use http::response::Response;

Modules

ext

Module that contains extensions in the Request.