Rust Web Services

Routing


  
  
    
      
    
    
      
    
    
      
    
    
      
    
    
      
    
  
  
  
  http
  
  server
  service
  
  sites
  service's
  serveSys
  action
  
  registered
  service's
  serveSys
  action
  
  psinode
  
  HTTP
  Request
  
  common
  
  api
  service's
  serveSys
  action
  no
  yes
  no
  yes
  no
  yes
  target
  with
  begins
  on
  a
  subdomain?
  registered?
  /common?
  
    
    
  
  
    
    
  
  
    
    
    
    
    
    
  
  
    
    
  
  
    
    
    
    
    
    
  
  
    
    
    
    
    
  
  
    
    
  
  
    
    
    
    
    
    
  
  
    
    
    
    
  
  
    
    
  
  
    
    
    
    
    
  
  
    
    
  

psinode passes most HTTP requests to the SystemService::HttpServer service, which then routes requests to the appropriate service's serveSys action (see diagram). The services run in RPC mode; this prevents them from writing to the database, but allows them to read data they normally can't. See psibase::DbId.

SystemService::CommonApi provides services common to all domains under the /common tree. It also serves the chain's main page.

SystemService::Sites provides web hosting for non-service accounts or service accounts that did not register for HTTP handling.

psinode directly handles requests which start with /native, e.g. /native/push_transaction. Services don't serve these.

Registration

Services which wish to serve HTTP requests need to register using the SystemService::HttpServer service's SystemService::HttpServer::registerServer action. There are multiple ways to do this:

  • psibase deploy and cargo psibase deploy have a --register-proxy option (shortcut -p) that can do this while deploying the service.
  • psibase register-proxy can also do it. TODO: implement psibase register-proxy.
  • A service may call registerServer during its own initialization action.

A service doesn't have to serve HTTP requests itself; it may delegate this to another service during registration.

HTTP Interfaces

Services which serve HTTP implement these interfaces:

Helpers

These help implement basic functionality:

Here's a common pattern for using these functions. #[psibase::service] defines Wrapper; the serve_* functions fetch action definitions from Wrapper.

#[psibase::service]
#[allow(non_snake_case)]
mod service {
    use psibase::*;

    #[action]
    fn serveSys(request: HttpRequest) -> Option<HttpReply> {
        if request.method == "GET"
        && (request.target == "/" || request.target == "/index.html")
        {
            return Some(HttpReply {
                contentType: "text/html".into(),
                body: "<b>This is my UI</b>".into(),
                headers: vec![],
            });
        }

        None.or_else(|| serve_schema::<Wrapper>(&request))
            .or_else(|| serve_action_templates::<Wrapper>(&request))
            .or_else(|| serve_pack_action::<Wrapper>(&request))
    }
}