In the previous article, we made an HTTP service in 1C, to which you can connect from any application that works with REST API. This service can give away any data that is in 1C.
But now suppose we need to send data to the server. For this, a POST request is usually used. So now, let's complicate our example and add the implementation of the POST request to it.
Well, let's begin!
We add the POST method for our HTTP Service:
and also create
the program code for this method:
For the test, add
the text line output to the server's response:
Function ourAPIPOST(Request)
Response = New HTTPServiceResponse(200);
result = "This is POST method in 1C";
Response.SetBodyFromString(result,TextEncoding.UTF8);
Return Response;
EndFunction
Let's publish 1C on a web server and see how our POST request works. For debugging, I usually use the POSTMAN. Well, let's use it:
As you can see,
our POST request works correctly.
For example, let's check how the GET request that we made earlier works:
Everything works fine!
OK, complicate our example now.
Let's make another
1C application - better mobile - and this application will send data to the
server using the POST request and receive data from the server back.
First, we will
slightly modify our 1C server program. Add one attribute "Price" to
the catalog "Products":
Attention! This is an example for a study. In fact, it's undesirable to store prices in catalogs. For this, it's better to use information registers.
Now
create a new mobile 1C, add the catalog "Products" to it and also
create one attribute "Price":
Let's also make the Common form "frmMain", and place two commands on it: "getProductsFromServer" and "postPriceToServer".
The idea is this: the command "getProductsFromServer" will receive a list of products from the server (here we'll use the Get request, slightly modifying it). Then the user will set prices for the products, and then the command "postPriceToServer" will post all the data to the server. In the second command, we'll use the POST request.
So,
for the command "getProductsFromServer" write the program code:
&AtClient
Procedure getProductsFromServer(Command)
getProductsFromServerAtServer();
EndProcedure
&AtServer
Procedure getProductsFromServerAtServer()
HTTPConnection = New HTTPConnection("localhost");
HTTPRequest = New HTTPRequest("ourAPI/hs/ourAPI/V1/list");
HTTPAnswer = HTTPConnection.Get(HTTPRequest);
Result = HTTPAnswer.GetBodyAsString();
EndProcedure
For simplicity, I write the server address as a "localhost".
Let's
run this code and see what result the server returns to us:
Everything works, the list of products from the server has come. Now it can be processed and recorded in the Products catalog, but it is not very convenient to work with such unstructured data.
Let's
change the program code on the server so that the server returns a list of
products in the form of a structure. Return to the server 1C and change the
procedure "ourAPIGET" as follows:
Function ourAPIGET(Request)
Response = New HTTPServiceResponse(200);
MethodName = Request.URLParameters.Get("MethodName");
If MethodName = "list" Then
//result = GetProducts();
structureResult = New Structure;
structureResult.Insert("products", GetArrayProducts());
JSONWriter = New JSONWriter;
JSONWriter.SetString();
WriteJSON(JSONWriter, structureResult);
result = JSONWriter.Close();
ElsIf MethodName = "product" Then
Parameter = Request.QueryOptions.Get("code");
If Parameter = Undefined Then
Response.StatusCode = 405;
result = "Parameter not defined";
Else
result = GetProducts(Parameter);
EndIf;
Else
Response.StatusCode = 405;
result = "Not found Method: " + MethodName;
EndIf;
Response.SetBodyFromString(result,TextEncoding.UTF8);
Response.Headers.Insert("Content-Type","text/html; charset=utf-8");
Return Response;
EndFunction
Instead of the GetProducts function, the function GetArrayProducts is called. This function returns an array of data, which is then packed into the structure structureResult and then converted to the string JSON.
Below
is the source code of the function GetArrayProducts:
Function GetArrayProducts()
arrayProducts = New Array;
query = New Query;
query.Text = "SELECT
| Products.Ref AS Ref,
| Products.Code AS Code,
| Products.Description AS Description,
| Products.DeletionMark AS DeletionMark
|FROM
| Catalog.Products AS Products";
selection = query.Execute().Select();
While selection.Next() Do
structureProduct = New Structure("_GUID,_Code,_Description,_DeletionMark");
structureProduct._GUID = String(selection.Ref.UUID());
structureProduct._Code = selection.Code;
structureProduct._Description = selection.Description;
structureProduct._DeletionMark = selection.DeletionMark;
arrayProducts.Add(structureProduct);
EndDo;
Return arrayProducts;
EndFunction
An array is created inside the function, then the elements are added to this array. Each element added is also a structure. And already the structure, in turn, stores information on each product.
Let's
check how this code works. Request Postman:
This structured data can be processed in any programming language that can work with JSON.
We'll
process this data in 1C, so we return to our mobile application and write the
following code in the procedure getProductsFromServerAtServer:
&AtServer
Procedure getProductsFromServerAtServer()
HTTPConnection = New HTTPConnection("localhost");
HTTPRequest = New HTTPRequest("ourAPI/hs/ourAPI/V1/list");
HTTPAnswer = HTTPConnection.Get(HTTPRequest);
If Not HTTPAnswer.StatusCode = 200 Then
Return;
EndIf;
result = HTTPAnswer.GetBodyAsString();
JSONReader = New JSONReader;
JSONReader.SetString(result);
structureResult = ReadJSON(JSONReader);
If TypeOf(structureResult) = Type("Structure") Then
If structureResult.Property("products") Then
If TypeOf(structureResult.products) = Type("Array") Then
For Each curElement In structureResult.products Do
_guid = curElement._GUID;
refProduct = Catalogs.Products.GetRef(New UUID(_guid));
objectProduct = refProduct.GetObject();
If objectProduct = Undefined Then
objectProduct = Catalogs.Products.CreateItem();
objectProduct.SetNewObjectRef(refProduct);
EndIf;
objectProduct.Description = curElement._Description;
objectProduct.Code = curElement._Code;
objectProduct.DeletionMark = curElement._DeletionMark;
objectProduct.Write();
EndDo;
EndIf;
EndIf;
EndIf;
EndProcedure
A little bit about how this code works.
First, GET request to the server is generated. Then, if the server returned StatusCode = 200, the request result is converted to JSON:
result = HTTPAnswer.GetBodyAsString();
JSONReader = New JSONReader;
JSONReader.SetString(result);
structureResult = ReadJSON(JSONReader);
After
this, several checks will be performed that the result has the correct
structure and the resulting array of products is processed in a cycle.
If TypeOf(structureResult) = Type("Structure") Then
If structureResult.Property("products") Then
If TypeOf(structureResult.products) = Type("Array") Then
For Each curElement In structureResult.products Do
EndDo;
EndIf;
EndIf;
EndIf;
In addition to the product description, the server also returns GUID (UUID). According to this GUID, we are trying to find a product in our catalog "Products". If a product with such a GUID is in the catalog "Products", then its description and code are simply updated. If there is no such product, a new one is created, and the same GUID is installed for it.
_guid = curElement._GUID;
refProduct = Catalogs.Products.GetRef(New UUID(_guid));
objectProduct = refProduct.GetObject();
If objectProduct = Undefined Then
objectProduct = Catalogs.Products.CreateItem();
objectProduct.SetNewObjectRef(refProduct);
EndIf;
objectProduct.Description = curElement._Description;
objectProduct.Code = curElement._Code;
objectProduct.DeletionMark = curElement._DeletionMark;
objectProduct.Write();
Let's
check how this code works. Launch our 1C application, click the
"getProductsFromServer" button, and then open the catalog "Products".
Well -
all products from the server are in the catalog on our mobile device:
Excellent!
Now
let's change the price of the products and transfer this data back to the
server.
First
create the code to process the PostPriceToServer command:
&AtClient
Procedure postPriceToServer(Command)
postPriceToServerAtServer();
EndProcedure
&AtServer
Procedure postPriceToServerAtServer()
structureResult = New Structure;
structureResult.Insert("products", GetProducts());
JSONWriter = New JSONWriter;
JSONWriter.SetString();
WriteJSON(JSONWriter, structureResult);
result = JSONWriter.Close();
HTTPConnection = New HTTPConnection("localhost");
HTTPRequest = New HTTPRequest("ourAPI/hs/ourAPI/V1/post_products");
HTTPRequest.SetBodyFromString(result);
HTTPAnswer = HTTPConnection.Post(HTTPRequest);
If Not HTTPAnswer.StatusCode = 200 Then
Message("Data Transfer Error");
EndIf;
EndProcedure
&AtServer
Function GetProducts()
JSONWriter = New JSONWriter;
arrayProducts = New Array;
query = New Query;
query.Text = "SELECT
| Products.Ref AS Ref
|FROM
| Catalog.Products AS Products";
selection = query.Execute().Select();
While selection.Next() Do
JSONWriter.SetString();
objectProduct = selection.Ref.GetObject();
XDTOSerializer.WriteJSON(JSONWriter, objectProduct,XMLTypeAssignment.Explicit);
stringProduct = JSONWriter.Close();
arrayProducts.Add(stringProduct);
EndDo;
Return arrayProducts;
EndFunction
The
principle of operation is similar to the "ourAPIGET" procedure on the
server. The structure "structureResult" is formed, an array of
"products" is added to this structure.
But in
the array itself, data on products are formed differently. If in the procedure "ourAPIGET"
we saved each product attribute separately (for this, we used another structure
"structureProduct"), now we record all the product attributes with
one command. For this, the 1C object "XDTOSerializer" is used:
JSONWriter.SetString();
XDTOSerializer.WriteJSON(JSONWriter, objectProduct, XMLTypeAssignment.Explicit);
stringProduct = JSONWriter.Close();
Using the "XDTOSerializer" object allows us to simplify both the source code and the subsequent support of the program.
Suppose
we later needed to add additional attributes to the catalog "Products".
If you use the first version of the source code (without using the object
"XDTOSerializer"), then you will have to change the source code of
our procedures both on the server and on the clients.
If you
use the "XDTOSerializer" object, you won't have to change the code,
since in this case, all newly added attributes will automatically be processed.
Well,
let's create program code on the server to process the POST request:
Function ourAPIPOST(Request)
Response = New HTTPServiceResponse(200);
result = "OK";
MethodName = Request.URLParameters.Get("MethodName");
If MethodName = "post_products" Then
stringResult = Request.GetBodyAsString("UTF-8");
JSONReader = New JSONReader;
JSONReader.SetString(stringResult);
structureResult = ReadJSON(JSONReader);
JSONReader.Close();
If TypeOf(structureResult) = Type("Structure") Then
If structureResult.Property("products") Then
If TypeOf(structureResult.products) = Type("Array") Then
For Each curElement In structureResult.products Do
JSONReader.SetString(curElement);
objectProduct = XDTOSerializer.ReadJSON(JSONReader);
Try
objectProduct.Write();
Except
result = "Error writing object";
Response.StatusCode = 400;
Break;
EndTry;
JSONReader.Close();
EndDo;
EndIf;
EndIf;
EndIf;
Else
Response.StatusCode = 405;
result = "Not found Method: " + MethodName;
EndIf;
Response.SetBodyFromString(result,TextEncoding.UTF8);
Return Response;
EndFunction
To
convert product data into 1C object, "XDTOSerializer" is also used
here:
objectProduct = XDTOSerializer.ReadJSON(JSONReader);
Well,
now we can check how our program works. Open the mobile application, change
product prices there, then click the "postPriceToServer" button.
After that, open the server application and look at the catalog "Products"
there:
All
the prices from the mobile application hit the server. We have completed the
task!
Thus,
using HTTP services, you can create any exchanges data between your 1C program
and any other software products.
You can download this Example for your own application.
If you
have any questions about this article, you can always ask them on our forum:
https://1c-dn.com/forum/
Stay with us!