Hi Scott,

A "Web Service" is just a generic term for an electronic service that operates over HTTP.

SOAP and REST can both be considered as a web service. Whilst SOAP is a protocol, REST is just an architectural style that operates over HTTP.

The NPI registry API can also be considered a web service, but it's clearly not SOAP, and it doesn't really conform to a REST architecture style either.

In fact if you look at the demo page you realise that the API is actually just a simple HTML form submit handler where the form values are sent in the GET request, as you can see here it submits all of the form values even if we provide just one form value...

https://npiregistry.cms.hhs.gov/api/?number=&enumeration_type=&taxonomy_description=&first_name=&last_name=&organization_name=&address_purpose=&city=baltimore&state=&postal_code=&country_code=&limit=&skip=

You don't need to use a REST client library to work with this API, here is a simple command line demo just using the standard %Net library  - I had to create an empty SSL/TLS configuration in the management portal named npiregistry as this needs to work over SSL.

USER>set req=##class(%Net.HttpRequest).%New()                                    
USER>set req.SSLConfiguration="npiregistry"
USER>set sc=req.Get("https://npiregistry.cms.hhs.gov/api?city=baltimore&postal_code=212")
USER>set results={}.%FromJSON(req.HttpResponse.Data)
USER>write results.%Get("result_count")
10

For Ensemble you could just use the standard HTTP Outbound Adapter.

Hi Jack,

The important parts of the error message are

<UNDEFINED>
*k1

Which tells us that k1 is being used but has not been initialised.

Set k1=request.GetNextIndex("PIDgrpgrp("_(1)_").ORCgrp()",k1,.tSCTrans)
                                                          /\
                                                       UNDEFINED

Without the source code its a little hard to see how your are implementing this.

If this is your own code block then you could initialise k1 first

Set k1=""
Set k1=request.GetNextIndex("PIDgrpgrp("_(1)_").ORCgrp()",k1,.tSCTrans)

Alternatively, if you make k1 a context property then I believe it will initialise it for you.

Seems like a simple task to crack with a BPL sledgehammer. If there is no other BPL logic then you might want to consider just using a simple custom process, or via an HL7 routing rule with your own custom function

https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=EGDV_adv_custom_utilfunctions

Hi Fiona,

You shouldn't trust variables populated with embedded SQL.

You need to check the SQLCODE value to make sure you have actually found data, if SQLCODE=0 trust the data, if SQLCODE=100 the query didn't find any data, any other value should probably throw an error as there will be a problem with the query.

More here...

https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=RERR_sql_noerr

I think Andew was looking for the Options to be escaped like so...

{"ID":1,"Name":"Smith, John","Options":"{\"Color\":\"Blue\",\"Count\":20}"}

Hence mentioning the CONCAT trick that does give the desired results...

select JSON_OBJECT('Name':Name, 'Raw': {fn CONCAT(Raw,' ')} )
from Foo.JSON

But given that he doesn't know if the field contains JSON or not he sounds a bit stuck with this approach.

The only thing I can think of with JSON_OBJECT is to append a space to known JSON before storing it, whitespace is valid and any consumer would ignore it.

"<>W" will strip whitespace so it doesn't end up in your global keys, more here on this...

https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=RCOS_fzstrip

Globals have a tree like structure, you can have many combinations of branches in the structure, but eventually your end branches (or leaves) will have to contain a value, even if that value is an empty string. It is not possible to set these end branches without a value, so you will always end up with a global looking like this...

^People("Customers", "Acc.divison", 1234.567)=""
^People("Customers", "Acc.divison", 1235.987)=""
^People("Customers", "Acc.divison", 3214.879)=""


Note also that the last key is a numeric value, so it will be automatically sequenced in numerical order, before any string values.

There is a post here that goes into more detail on globals...

https://community.intersystems.com/post/globals-are-magic-swords-managing-data-part-1

Hi Eric,

Assuming you don't have escaped characters in the first or second field, you can just paste the following three lines into the terminal.

set file=##class(%Stream.FileCharacter).%New()
do file.LinkToFile("c:\Temp\file.csv")
for  quit:file.AtEnd  set ^People("Customers", "Acc.division",$zstrip($piece(file.ReadLine(),",",2),"<>W"))=""


You will end up with a global that looks like this...

^People("Customers","Acc.division",1234)=""
^People("Customers","Acc.division",1235)=""
^People("Customers","Acc.division",3214)=""


If you have more complex / escaped data then here is an example of a CSV reader that will safely traverse the data (look at the Test examples)

https://gist.github.com/SeanConnelly/cb4ff970c2df5266d24c8802d56f48da

Perhaps something along these lines...

 ClassMethod UpsertXML(xml, wrapper, class, id, Output object) As %Status
{
  set reader=##class(%XML.Reader).%New()
  $$$QuitOnError(reader.OpenString(xml))
  do reader.Correlate(wrapper,class)
  do reader.Next(.object,.sc)
  $$$QuitOnError(sc)
  if id'="" do object.%IdSet(id)
  quit object.%Save()
}

Usage...

w ##class(Foo.Person).UpsertXML("<Person><FirstName>Bob</FirstName><LastName>Smith</LastName><City>Paris</City></Person>","Person","Foo.Person",1)

Hi Anthony,

Your custom header is being prefixed with "HTTP_" after it hits the gateway.

One simple thing you can do is dump all of the CGI variables in a test page...

classMethod OnPage() As %Status [ ServerOnly = 1 ]
{
  set var=$order(%request.CgiEnvs(""))
  while var'="" {
    write !,var," = ",$order(%request.CgiEnvs(var)),"</br>"
    set var=$order(%request.CgiEnvs(var))
  } 
  quit $$$OK
}

Hi Bharath,

CallInterval is in seconds.

You can set this to -1 which will bypass waiting between calls. Theoretically there is no upper limit, but you should probably take a look at the Schedule setting if you want a high value.

As the description mentions, this setting is only for polling adapters such as the built in Email, FTP, File and SQL inbound adapters.

It would probably help to understand how and why the call interval is being used.

A polling adapter should try and do two things, yield to its host as often as possible and sleep when there is nothing to do. If it does not yield very often then a production shutdown will not be able to bring down the adapter cleanly. If the adapter never goes to sleep then its going to hammer the CPU and IO 24/7 even when there is nothing to do.

To get a balance between going to sleep and working, the adapter can set a property called %WaitForNextCallInterval. This can immediately re-invoke the adapters on task method. The adapter would normally set this to 0 when its finding items, and to 1 when there are no items left. By setting it to 1 it gives other service a better share of the CPU and IO.

If your using one of the above adapters then this behaviour is built in. Even if you have thousands of items to collect, they will all be collected without any call delay, again, only when there are none left will it sleep.

You can find some more information here...

https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=EGDV_busservice

Sean.

I've created a Gist containing the source code for a CSV reader.

It will load CSV data from a file, stream or string, exposing each record via a Next() record method and Get() and GetAt() field methods.

It implements various options for changing the field and EOL delimiter, automatic encoding from UTF8 files, quote stripping and normalisation of EOL character(s) to a preferred internal EOL character(s).

https://gist.github.com/SeanConnelly/cb4ff970c2df5266d24c8802d56f48da

I've been using some ugly data and looks to be working good enough, here is output from the  Display() method...

Record No : 1
 address = 1 long street, somewhere, north pole
 poetry =
 
"Poetry"
========
 
From the "Anglo-Saxon" Rune Poem (Rune version):
"ᚠᛇᚻ᛫ᛒᛦᚦ᛫ᚠᚱᚩᚠᚢᚱ᛫ᚠᛁᚱᚪ᛫ᚷᛖᚻᚹᛦᛚᚳᚢᛗ
ᛋᚳᛖᚪᛚ᛫ᚦᛖᚪᚻ᛫ᛗᚪᚾᚾᚪ᛫ᚷᛖᚻᚹᛦᛚᚳ᛫ᛗᛁᚳᛚᚢᚾ᛫ᚻᛦᛏ᛫ᛞᚫᛚᚪᚾ
ᚷᛁᚠ᛫ᚻᛖ᛫ᚹᛁᛚᛖ᛫ᚠᚩᚱ᛫ᛞᚱᛁᚻᛏᚾᛖ᛫ᛞᚩᛗᛖᛋ᛫ᚻᛚᛇᛏᚪᚾ"᛬
 
From Laȝamon's Brut (The Chronicles of England, Middle English, West Midlands):
 
"An preost wes on leoden, Laȝamon was ihoten
He wes Leovenaðes sone -- liðe him be Drihten.
He wonede at Ernleȝe at æðelen are chirechen,
Uppen Sevarne staþe, sel þar him þuhte,
Onfest Radestone, þer he bock radde."
 
(The third letter in the author's name is Yogh, missing from many fonts; CLICK HERE for another Middle English sample with some explanation of letters and encoding).
 
From the Tagelied of Wolfram von Eschenbach (Middle High German):
 
"Sîne klâwen durh die wolken sint geslagen,
er stîget ûf mit grôzer kraft,
ich sih in grâwen tägelîch als er wil tagen,
den tac, der im geselleschaft
erwenden wil, dem werden man,
den ich mit sorgen în verliez.
ich bringe in hinnen, ob ich kan.
sîn vil manegiu tugent michz leisten hiez."
 
Some lines of Odysseus Elytis (Greek):
 
Monotonic:
 
"Τη γλώσσα μου έδωσαν ελληνική
το σπίτι φτωχικό στις αμμουδιές του Ομήρου.
Μονάχη έγνοια η γλώσσα μου στις αμμουδιές του Ομήρου.
από το Άξιον Εστί
του Οδυσσέα Ελύτη"
 
Polytonic:
 
"Τὴ γλῶσσα μοῦ ἔδωσαν ἑλληνικὴ
τὸ σπίτι φτωχικὸ στὶς ἀμμουδιὲς τοῦ Ὁμήρου.
Μονάχη ἔγνοια ἡ γλῶσσα μου στὶς ἀμμουδιὲς τοῦ Ὁμήρου.
ἀπὸ τὸ Ἄξιον ἐστί
τοῦ Ὀδυσσέα Ἐλύτη
The first stanza of Pushkin's Bronze Horseman (Russian):
На берегу пустынных волн
Стоял он, дум великих полн,
И вдаль глядел. Пред ним широко
Река неслася; бедный чёлн
По ней стремился одиноко.
По мшистым, топким берегам
Чернели избы здесь и там,
Приют убогого чухонца;
И лес, неведомый лучам
В тумане спрятанного солнца,
Кругом шумел."
 
Šota Rustaveli's Veṗxis Ṭq̇aosani, ̣︡Th, The Knight in the Tiger's Skin (Georgian):
 
"ვეპხის ტყაოსანი შოთა რუსთაველი
ღმერთსი შემვედრე, ნუთუ კვლა დამხსნას სოფლისა შრომასა, ცეცხლს, წყალსა და მიწასა, ჰაერთა თანა მრომასა; მომცნეს ფრთენი და აღვფრინდე, მივჰხვდე მას ჩემსა ნდომასა, დღისით და ღამით ვჰხედვიდე მზისა ელვათა კრთომაასა."
 
Tamil poetry of Subramaniya Bharathiyar: சுப்ரமணிய பாரதியார் (1882-1921):
 
"யாமறிந்த மொழிகளிலே தமிழ்மொழி போல் இனிதாவது எங்கும் காணோம்,
பாமரராய் விலங்குகளாய், உலகனைத்தும் இகழ்ச்சிசொலப் பான்மை கெட்டு,
நாமமது தமிழரெனக் கொண்டு இங்கு வாழ்ந்திடுதல் நன்றோ? சொல்லீர்!
தேமதுரத் தமிழோசை உலகமெலாம் பரவும்வகை செய்தல் வேண்டும்."
 
Kannada poetry by Kuvempu — ಬಾ ಇಲ್ಲಿ ಸಂಭವಿಸು
 
"ಬಾ ಇಲ್ಲಿ ಸಂಭವಿಸು ಇಂದೆನ್ನ ಹೃದಯದಲಿ
ನಿತ್ಯವೂ ಅವತರಿಪ ಸತ್ಯಾವತಾರ
ಮಣ್ಣಾಗಿ ಮರವಾಗಿ ಮಿಗವಾಗಿ ಕಗವಾಗೀ...
ಮಣ್ಣಾಗಿ ಮರವಾಗಿ ಮಿಗವಾಗಿ ಕಗವಾಗಿ
ಭವ ಭವದಿ ಭತಿಸಿಹೇ ಭವತಿ ದೂರ
ನಿತ್ಯವೂ ಅವತರಿಪ ಸತ್ಯಾವತಾರ || ಬಾ ಇಲ್ಲಿ ||"
 
 spaceship =
 
 
       _________
      (=========)
      |=========|
      |====_====|
      |== / \ ==|
      |= / _ \ =|
   _  |=| ( ) |=|
  /=\ |=|,,,,,|=| /=\
  |=| |=| USA |=| |=|
  |=| |=|,,,,,|=| |=|
  |=| |=| | | |=| |=|
  |=| |=| | | |=| |=|
  |=| |=| | | |=| |=|
  |=| |/  | |  \| |=|
  |=|/    | |    \|=|
  |=/NASA |_| NASA\=|
  |(_______________)|
  |=| |_|__|__|_| |=|
  |=|   ( ) ( )   |=|
 /===\           /===\
|||||||         |||||||
-------         -------
 (""")           (""")
 
 size = Big
 qty = 5.7

Hi Keshav,

%ID is a psuedo field that will always reference the RowID, by default this is named as ID, but could also be ID1, ID2 .. IDn

More about it here...

https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GSQL_tables#GSQL_tables_idfield

Not sure about your error, would need to see your full code.

If you are not naming properties as ID, then just use ID.

Sean.