Skip to content

HTTP Status Response Codes in Contract Functions

Since HTTP Status Response Codes are a standardized way of communicating statuses between software services, it is typically a good idea to implement a similar pattern in the return values from smart contract function calls. You can model the return values based on the corresponding HTTP status code of the action that occurred. So if a user does not have permissions to call a function, the function would return the HTTP "Forbidden 403" error code, rather than failing the contract call completely. And if a new contract was created as a result of this function call, then a "201 Created" would be returned, along with a URI for the newly created resource (in this case, the URI would be the address of the new contract.) This has the advantage of providing more detailed information to the application middleware server via the returned status code, vs a generic 400-level error returned by STRATO when a transaction fails.

The Asset Framework includes the RestStatus contract for easy-to-use status codes to reference by name.

contract RestStatus {

   uint constant OK = 200;
   uint constant CREATED = 201;
   uint constant ACCEPTED = 202;

   uint constant BAD_REQUEST = 400;
   uint constant UNAUTHORIZED = 401;
   uint constant FORBIDDEN = 403;
   uint constant NOT_FOUND = 404;
   uint constant CONFLICT = 409;

   uint constant INTERNAL_SERVER_ERROR = 500;
   uint constant NOT_IMPLEMENTED = 501;
   uint constant BAD_GATEWAY = 502;
   uint constant GATEWAY_TIMEOUT = 504;
}

Example usage:

contract Asset is RestStatus {
   ...
   // update without status code
   function update(...) {
      require(canUpdateAsset(tx.origin), "Caller cannot update asset");
      // update asset fields
      ...
   }

  // update with status code
  function updateWithStatusCode(...) returns (uint) {
      if (!canUpdateAsset(tx.origin)) {
         return RestStatus.FORBIDDEN; //403
      }
      // update asset fields
      ...
      return RestStatus.OK; // 200
  }
}

In the above contract, when update is called and fails, the application would receive a 400-level error from the STRATO directly, potentially throwing an error in our application and causing unexpected behavior. The error could be caught and parsed for the "Caller cannot update asset" message, however that introduces additional complexity to the app.

However, when calling updateWithStatusCode and the caller does not have permission, our application will never receive a 400-error directly. Since the more detailed error code is contained in the function return value, it can be easily evaluated in the app.

This has the beneficial side-effect of making application APIs very straight-forward to write in terms of requests and their responses. An API can be designed with endpoints corresponding to each function in a contract, with the response type simply being the returned value from the called function piped through to the application API layer.