REST API typing for frontend developer

Today, the following approaches are widely used to describe the interaction of the browser and server, such as OpenApi & GraphQL.



In this article I will talk about our attempt to make a statically typed REST API and save the front-end team from writing code for writing data requests, simplify testing and reduce the number of possible errors.







These tools help us:





The main idea of ​​the approach is that having the same data types on the client and server, it is more difficult for the developers in the team to make an error on the client, and using the code generation it will not need to be written, maintained and, accordingly, covered with unit tests.



The frontend application will not compile if the command made a mistake in the data types that the REST API accepts / supplies.



Thus, having statically typed code on the client, we can get rid of stupid errors related to types and be sure that our code is fully compatible with the current version of the API.



In order to get all the above advantages of a statically typed API, we need to use a code generator that, according to the OpenAPI specification, can generate type description files, for Typescript these are * .d.ts files.



Our project uses microservice architecture and the entire backend is written in .NET, so we used NSwag to generate API clients for the frontend / backend. This tool allows you to generate OpenAPI documents, which then in turn are already used to generate client code.



Architecture



In general, the code generation process consists of several stages:





In our case, the backend is written using .Net and the main C # development language is the reason for the choice of tools. We use the same tool called NSwag to generate OpenAPI documents and clients.





Figure 1 Architecture of a solution for generating rest client code



The figure shows:





The sequence of actions is as follows:





Documentation



In order to be able to generate code, we need to describe the types of accepted / returned values ​​of the API controller, in this example, where the C # language is used, using the SwaggerOperation attribute, we marked a method that will return a list of all the questionnaires on the server, in the client code, a method to get The data will be called GetAllQuestionnaires:



[HttpGet, Route("")] [SwaggerOperation(OperationId = "GetAllQuestionnaires")] [SuccessResponse(typeof(IEnumerable<QuestionnaireViewModel>))] public IEnumerable<QuestionnaireViewModel> Get() { var surveys = _questionnaireRepository.GetAll(); return surveys.Select(QuestionnaireViewModel.ToViewModel).ToArray(); }
      
      





Listing 1 Example C # code describing an API method



Then, using NSwag, we automatically generate an OpenAPI document that will contain all the API endpoints that were marked with the corresponding attributes in the backend code.





Figure 2 OpenAPI Document



Thus, we managed to create always up-to-date automatically updated documentation of our API.



Typing



The OpenAPI documentation contains information about the types of data that will be sent / received by the backend controller. Thus, on the front-end side, we can fully rely on the types that the backend supplies to us and not create our own types, but import them from the client code that was generated using the OpenAPI document.



For our example, the document contains information about the QuestionnaireViewModel type (here the specification is presented in HTML form for readability)





Figure 3 Example data model in an OpenAPI document



The next step is to pass this information to the frontend application code.



Code generation



We also use NSwag to generate client API code. At the input, it receives an OpenAPI document and generates client API code in accordance with the specified settings. For the front, next to the received code, we add package.json and send it to our local npm register.



As you can see from the backend code listing (see Listing 1), we marked the controller method with the attribute



 [SwaggerOperation(OperationId = "GetAllQuestionnaires")]
      
      





The OperationId specified in the C # attribute in our case will become the name of the client method.





Figure 4 Example usage of the generated client API



Also, after generating the client, we received a d.ts file that contains the corresponding descriptions of data types, shown in the figure below.





Figure 5 Example data type description in a .d.ts file



Now, in the frontend application code, you can use data types that are exported from the client’s API code and use auto-completion in the code editor, an example is shown in the figure below.





Figure 6 Example use of client API data type information



All relevant data type validators in Typescript also work.



An example in the figures below.





Figure 7 Example client API data type validation





Figure 8 Example client API data type validation



conclusions



After applying this approach, we received the following advantages:







References




All Articles