A guest post by Mehmet Tokgöz, a contributor to the Accord Project Summer of Code 2022.
About the project
Cicero makes it possible to process traditional text contracts by converting it to a template with data model and business logic. It provides an API to create, validate and execute contract templates.
Through the interfaces, you can execute Cicero functions on your templates and manage them. Cicero has a command line (CLI) and web API interface to use its functionality. Also, you can check the source code from Cicero GitHub repo where all the Cicero packages are hosted: Cicero GitHub. Unlike the CLI, Cicero Server is not complete and misses many of the Cicero API methods. This project aims to complete Cicero Server functionality with a documentation interface.
The main goal here is to provide a web API to developers and allow them to integrate Cicero API to their application. People can develop various top-level apps and use the functionality of Cicero using our web API. Without having such an API, developers need to import Cicero Core and Cicero Engine modules directly inside their application and develop these functionalities by themselves. Once we have completed the API as a RESTful service, users will be able to use all methods and interact with Cicero more robustly.
As you can see in the above diagram, Cicero Server runs as a part of a top-level application and processes the given request on behalf of the top-level API. Suppose that you have a Car Rental application and you are using Cicero as a part of contract management. When a user wants to rent a car, you will initialize and draft requests to Cicero Server. You can use a `car-rental` template to initialize and it will return you a drafted text version of the template which you can show the end user. You can store the state and other info in your database and apply other business logics to the initialized template.
Also, we aimed to make experimenting with Cicero much more easy by providing a Swagger interface for the complete API. So, new beginners to the Accord Project can easily experience Cicero. Another advantage is that users can send their arguments directly inside of the request body instead of dealing with local files. While using the current command-line interface, they have to create specific files for arguments. A web API allows users to prepare their request easily and return the response as JSON object, which is easily processable.
Since I did not contribute to the Accord Project before, I spent the first two weeks learning the underlying architecture and use cases for Cicero. I started by using the command line-client and explored the functionality of Cicero. Cicero has two main modules that expose its functionality, Cicero Core and Cicero Engine. The key operations for this API come from Cicero Core and Engine packages.
Cicero Server is developed using Express.js, which is an API development framework for Node.js. Express.js has a very easy to use interface for creating new endpoints and defining the request and response. Since previously I had experience on Express.js, I did not have any problems with writing code for it.
Architectural Design Choices
We aimed to design Cicero Server as a RESTful service as much as possible by following REST principles. One of the most important design goals was defining both the input and output payloads in a JSON format.
JSON provides an appropriate convention for structured data since it can be easily processable and transferable over the network. It also defines a standard for communication between two machine clients so that they can understand the responses of each other without extra workload. We can make the API more robust and independent by defining input and output as JSON objects. Users can easily prepare a request to send our API and process the result in JSON type.
Following the REST principles, our API design should not depend on any client architecture. From an API perspective, there is no difference between different client architectures, it only processes the given input. It does not keep any state information about incoming requests, rather it takes the state of the template inside the request body and returns the resulting state in response. These choices allow us to follow two important principles of REST: client/server separation and stateless requests.
Another change was the response of the error cases. Previously, we were returning a renderable HTML response in case of error. This makes the API dependent on the client understanding the returned HTML style and processing it to get the message of error. Instead, now we are returning an JSON object, like the successful response type that includes an error message field. Also, we defined different status codes for the successful and unsuccessful cases to indicate there is an error. Users can easily understand if there is an error and get the error message without having to parse the HTML. You can see the difference from the following sample error returns.
New JSON Error Response
Legacy HTML Error Response
Designing endpoints for an API is an important step. To follow the REST principles, we needed to design our endpoints as data sources, not as methods. But the nature of Cicero API is not applicable for this principle. Cicero does not interact with any database rather than the templates. One possible solution to that was changing the order of arguments in the request link, and make it /:template/[method]. But this option still is not fully compatible since we are still requesting a method name inside the link. So, we decided to keep the current endpoints design as /method/:template since it is much more understandable and usable. Since we don’t have a ton of endpoints and different request types for an endpoint, this design works best for us. So, our final decision for our endpoint list was as follows:
I implemented all of these commands by following the design principles explained in this section.
Different Source Supports for Templates
In the scope of this project, we added support for template sources other than local directory. By using the fromUrl() method of the Cicero Core, we are now able to download an archived template file (.cta file) and process it. This feature allows users to run Cicero Server on their cloud without having an exclusive template library. We are already providing a list of templates under templates.accordproject.org page but users can also introduce new URL sources. There is a new environment variable for controlling the URL link named CICERO_URL. Also, we were not supporting local archive templates before. Now Cicero Server also supports the usage of local .cta files as archives. The following flowchart explains the creating a template instance process in more detail.
Swagger UI Interface
Swagger, specially Swagger UI is an useful tool to create interactive documentation for your API easily without dealing with extra work. It automatically detects the API endpoint and creates an interactive web page. There are two options for creating a Swagger UI interface. Either we can embed the endpoint properties inside our implementation or we can create a separate independent JSON file to render. We selected the first approach since it is easier to edit while code changes. So, we have added comment sections like the following for each method, defining the request and response of the endpoint. Swagger Autogen module automatically creates the JSON file from these comments and render them under `/docs` endpoint.
In the page, it shows the description of the endpoint, the arguments for the execution and their schemas. For all of our methods there is a data input in JSON type that contains necessary arguments for the command. Although data is common for all of the methods, the content of it differs. You can see the request model of invoke from below, there are sample values for each of the arguments and they lead the user to discover the usage. Also, response types are defined with different status codes.
The video at the start of the article shows a sample execution of Parse command using the Swagger UI. It is very easy and simple. It also gives a cURL version of the request.
Now, Cicero Server supports all of the Cicero API commands and their functionality. It takes the arguments for the methods inside the body of the request as a JSON object, validates them and then returns the output. Similar to input, it returns the output as a JSON object inside the response body. It has nine different endpoints to run different commands. In case of an error, it also returns a JSON type response containing a specific status code and an error message indicating the cause of the error.
As a part of development, test cases for the commands are implemented. They cover successful and failed cases of endpoints and validate that they are running correctly.
Although Cicero Server is now completed in terms of functionality, there are many things to improve. We can refactor the codes to prevent bugs and improve the documentation quality of Cicero. We can also prepare new guides to show usage of Cicero Server.
This summer was a total fun of learning for me. I learned many things that I didn’t know before. I had a chance to learn about smart contracts and understand the underlying technologies. I would like to specially thank my mentor Martin for helping me all the time when I need help. Also special thanks to Matt for helping us through the APSoC.
I am hoping to continue to contribute to the Accord Project, especially Cicero. I really enjoyed contributing to Cicero and want to develop it much further by writing code, ideas and possibly helping to reach out more contributors. At least, APSoC was one of the best project programs I have ever participated in.