Question
Daniel Castro · Jan 11

%Net.HttpRequest and {}.%FromJSON

Hi !

 I am new to the language and I am trying to read some json data from a government site (it is public data).

The address is: https://apisidra.ibge.gov.br/values/t/1736/n1/all/v/all/p/all/d/v44%202,...

Here is some data sample:

[{"NC":"Nível Territorial (Código)","NN":"Nível Territorial","MC":"Unidade de Medida (Código)","MN":"Unidade de Medida","V":"Valor","D1C":"Brasil (Código)","D1N":"Brasil","D2C":"Variável (Código)","D2N":"Variável","D3C":"Mês (Código)","D3N":"Mês"},{"NC":"1","NN":"Brasil","MC":"30","MN":"Número-índice","V":"0.0000000055765","D1C":"1","D1N":"Brasil","D2C":"2289","D2N":"INPC - Número-índice (base: dezembro de 1993 = 100)","D3C":"197903","D3N":"março 1979"},{"NC":"1","NN":"Brasil","MC":"30","MN":"Número-índice","V":"0.0000000057689","D1C":"1","D1N":"Brasil","D2C":"2289","D2N":"INPC - Número-índice (base: dezembro de 1993 = 100)","D3C":"197904","D3N":"abril 1979"},{"NC":"1","NN":"Brasil","MC":"30","MN":"Número-índice","V":"0.0000000058704","D1C":"1","D1N":"Brasil","D2C":"2289","D2N":"INPC - Número-índice (base: dezembro de 1993 = 100)","D3C":"197905","D3N":"maio 1979"},{"NC":"1","NN":"Brasil","MC":"30","MN":"Número-índice","V":"0.0000000060465","D1C":"1","D1N":"Brasil","D2C":"2289","D2N":"INPC - Número-índice (base: dezembro de 1993 = 100)","D3C":"197906","D3N":"junho 1979"},

I am trying  to make a class to read some of this data:

/// Contém os dados do INPC para calculos financeiros
Class User.TabelaINPC Extends (%Persistent, %JSON.Adaptor)
{ Property Mes As %Integer [ Required ]; Index MesIndex On Mes [ Unique ]; Property Descricao As %String [ Required ]; Property Valor As %Double [ Required ]; ClassMethod leINPC() As %Status
{
Set result = ##class(%Net.HttpRequest).%New()
Set result.Server = "api.sidra.ibge.gov.br"
set result.SSLConfiguration = "padrao"
set result.Https = 1
set result.SSLCheckServerIdentity = 0
set result.FollowRedirect = $$$YES
TRY {
set status = result.Get("/values/t/1736/n1/all/v/all/p/all/d/v44%202,v68%202,v2289%2013,v2290%202,v2291%202,v2292%202?formato=json")
set response = result.HttpResponse.Data
set dados = {}.%FromJSON(response) -----> THE ERROR IS HERE
}
CATCH erro {
write "ERRO:"
write erro.Name_", "_erro.Location_", error code "_erro.Code,!
do $system.OBJ.DisplayError()
RETURN erro.AsStatus()
}
Quit $$$OK
}

I am getting the error code 5035, Parsing error code 3.

What I am doing wrong?

Thanks in advance !

 

Product version: IRIS 2021.2
00
3 0 15 138
Log in or sign up to continue

I'd recommend looking at what (other than valid JSON) is in result.HttpResponse.Data. Also worth looking at result.HttpResponse.StatusCode - is it 400 or 404?

It looks like there might be an issue with the service you're trying to use - at https://apisidra.ibge.gov.br/ , pasting in "/t/1612/n2/all/v/all/p/last/c81/2702/f/u" as "Parâmetros/valores da API:" then clicking "Consultar" I get an alert saying "A solicitação de conexão com pools sofreu timeout".

I also see this from ObjectScript with Server set to apisidra.ibge.gov.br instead of api.sidra.ibge.gov.br

Hi Timothy !

Thank´s for the help.

Yesterday the service was unstable, but today is working fine When I type de url in the browser I get the data, but in my code (I did as you told me to) HttpResponse.StatusCode returns 404.

I don´t know why...

Right - at this point I'd say set Server to apisidra.ibge.gov.br instead of api.sidra.ibge.gov.br and see if that fixes it.

Hi,

No, it din´t fix it. It didn´t find the server apisidra.ibge.gov.br. The correct one is api.sidra.ibge.gov.br.
Does it make any difference if the connection is sync or async?

Do I have to change the code because of it?

Thanks !

Problem solved !

/// Contém os dados do INPC para calculos financeiros
Class User.TabelaINPC Extends (%Persistent, %JSON.Adaptor)
{ Property Mes As %Integer [ Required ]; Index MesIndex On Mes [ Unique ]; Property Descricao As %String [ Required ]; Property Valor As %Double [ Required ]; ClassMethod leINPC() As %Status
{
Set result = ##class(%Net.HttpRequest).%New()
Set result.Server = "api.sidra.ibge.gov.br"
set result.SSLConfiguration = "padrao"
set result.Https = 0 --- HTTPS MUST Be ZERO, although there is a redirect to https in the browser
set result.SSLCheckServerIdentity = 0
set result.FollowRedirect = $$$YES
set result.ContentType = "application/json"
TRY {
set status = result.Get("/values/t/1736/n1/all/v/all/p/all/d/v44%202,v68%202,v2289%2013,v2290%202,v2291%202,v2292%202?formato=json")
set response = result.HttpResponse.Data
write "HTTP_CODE:"_result.HttpResponse.StatusCode,!
set dados = {}.%FromJSON(response)
set formatter = ##class(%JSON.Formatter).%New()
do formatter.Format(dados)
set iterator = dados.%GetIterator()
while iterator.%GetNext(.key, .value) { write "element:"_key_"=/"_value_"/ ",!} }
CATCH erro {
write "ERRO:",!
write erro.Name_", "_erro.Location_", error code "_erro.Code,!
do $system.OBJ.DisplayError()
RETURN erro.AsStatus()
}
Quit $$$OK
}

Thank you for the help Timothy !

Your result.HttpResponse.Data can be either a string or a stream object. If it's a stream object you'll have to handle it a little bit differently using result.HttpResponse.Data.Read():

set response=result.HttpResponse.Data.Read()
while 'result.HttpResponse.Data.AtEnd{
    set response = response_result.HttpResponse.Data.Read()
}

No, as long as response is json this should work - %FromJSON accepts strings, streams and even file paths as input:

set response = result.HttpResponse.Data
set dados = {}.%FromJSON(response)  

I think I am doing something wrong before 

set response = result.HttpResponse.Data
set dados = {}.%FromJSON(response)  

I am getting error 404 although the access by the browser is ok.

Thanks !

Try to set UserAgent in IRIS to your browser.

Just to add more information.

This is a C# Code that works fine :

HttpClient client = new HttpClient();
            string baseApiAddress = "http://www.sidra.ibge.gov.br";
            client.BaseAddress = new Uri(baseApiAddress);
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            HttpResponseMessage response = client.GetAsync("/api/values/t/1612/n2/all/v/all/p/last/c81/2702/f/u").Result;

It is a asynchronous connection.

Daniel,

One thing I always recommend is to get familiar with the API using a standalone tool before attempting to code the programmatic interface.  I like Postman as it has pretty good UI to work with.  If you are at the command line you can use curl.

https://www.postman.com/

Postman can also give you the code for different programming environments.  Unfortunately not Objectscript, but it is fairly easy to translate from the examples you can see.