Minimized JSON.stringify() for SWI-Prolog?

By default the result of JavaScript JSON.stringify(<json>) doesn’t pretty
print, i.e. gives non-pretty result. To get a pretty printed result, one can
for example use JSON.stringify(<json>, null, 2):

space Optional
A string or number that’s used to insert white space (including
indentation, line break characters, etc.) into the output JSON
string for readability purposes.
JSON.stringify() - JavaScript | MDN

In SWI-Prolog it seems to me its the other way around. The default is
pretty printing. Is there also an option to switch off pretty printing? Here
is an example result that shows that spaces and newline is inserted:

?- atom_json_term(Request, _{model:'text-davinci-003',
      prompt:'Generate a single random multiple choice quizz about Switzerland',
      max_tokens:100,
      temperature:0.7,
      n:1}, []).
Request = '{\n  "max_tokens":100,\n  "model":"text-davinci-003",\n  "n":
1,\n  "prompt":"Generate a single random multiple choice quizz about 
Switzerland",\n  "temperature":0.7\n}'.

Use the option width(0)

Note that atom_json_term/3 is probably something you rarely want. It may create giant atoms that will eventually be garbage collected, but still …

Yep, the width(0) option seems to be accepted:

?- atom_json_term(Request, _{model:'text-davinci-003',
      prompt:'Generate a single random multiple choice quizz about Switzerland',
      max_tokens:100,
      temperature:0.7,
      n:1}, [width(0)]).
Request = '{"max_tokens":100, "model":"text-davinci-003", "n":
1, "prompt":"Generate a single random multiple choice quizz about
Switzerland", "temperature":0.7}'.

I used it here the Request variable, whats the alternative?

Maybe I should use library(http/http_json) ?

This server accepts requests using JSON “post” (the client is in JavaScript):

Its reply_with_json/1 uses reply_json_dict/2 with [width(0)] to make the reply.

The library(http/http_json) acts as plugin for both the HTTP server and client libraries. It will make http_get/3 translate JSON into a Prolog term. It causes http_open/3 to allow for post(json(JSONTermOrDict)). http_post/4 can do the complete POST of a JSON term and parsing the returned JSON reply.

All you may need should be there: JSON I/O, HTTP authentication, cookies, keep-alive connections. All both for the client and the server.

1 Like

I wrote the sample swipl-server-js-client package because the existing “tutorial” (How to create a web service easily?) was out of date and didn’t take advantage of some newer functionality (and also . I had previously written a more complex client/server using the new features; the sample package was created by from the “real life” code by removing most of the code that processed the requests.

I hope my code uses the most up-to-date features; if it doesn’t, please tell me.

Peter Ludeman (@peter.ludemann ), your code is a server, not a client. It has nowhere http_open/3. Or as Jan W. (@jan ) pointed out http_get/3 or http_post/4. Why do you think it would be relevant?

After all the Request object I am creating is used here, for this purpose:

Interestingly Jan W. suggestion is yet from another library library(http/http_client). And the conveniencies http_get/3 or http_post/4 call http_open/3 in turn.

But I guess further solution could be using as(String) in atom_json_term/3. An as(String) payload could have the advantage that it can be submitted via in the HTTP request:

Content-Length: <Length>   /* Header */

<payload>   /* Body */

And doesn’t need a HTTP Request:

Transfer-Encoding: chunked   /* Header */

<payload chunk 1>         /* Body Begin */ 
<payload chunk 2>
... 
<payload chunk n>  
<terminator>              /* Body End */ 

Have to check what http_open/3 and friends does.

What about

post(json(#{name:"Bob", age:42}))

That should work fine, provided you both load library(http/http_open) and
library(http/http_json).

http_post/4 and friends from library(http/http_client) implement an older interface before http_open/3 existed. Later the library was reimplemented on top of http_open/3. They take care of the stream and use a pluggable framework to convert the returned data into a Prolog term based on the Content-Type header. That is often convenient. http_open/3 gives more control to decide how to process the reply based on the header and allows processing unlimited amounts of data in streaming mode.

True. Except for documentation I can see little wrong with that. A lot of the stuff is used both for server and client. We also want plugins per content type. We want plugins to deal with transfer encodings, authentication, TLS, proxies, etc.

The main thing I wonder about is whether it would have been a better idea to implement the client as a C wrapper around the curl library :slight_smile: That is mostly history though. When I wrote the first client HTTP was a lot simpler than it is now.

I might be also wrong that the mime type application/json would allow charset.
This is more found for text/* types. In as far this stackoverflow page
gives me mixed signals:

What does “Content-type: application/json; charset=utf-8” really mean?
11. IANA Considerations
Note: No “charset” parameter is defined for this registration.
https://stackoverflow.com/q/9254891/17524790

And this stackoverflow page, gives me a code snippted where the mime
type application/json is added as an exception mime type, that has
nevertheless charset:

Which Mime Types contain charset=utf-8 directive?

if(outputContentType.startsWith("text/") || 
specialCase.includes(outputContentType)) {

https://stackoverflow.com/q/70643383/17524790

We are sending, so we decide the charset. Once upon a time there was an Accept-charset header, but this is deprecated and notably UTF-8 is considered to be accepted by any client.

Possibly it should be an option, but it all gets complicated and SWI-Prolog itself can only write text in the native locale (a bad choice), ASCII, ISO-Latin-1, UTF-8, UTF-16 (be/le) and UTF-32 (be/le). Obviously UTF-8 is the best choice.

But the server is accepting. What if the server does not accept our choice?

How would we know? I thought possibly using the preflight OPTIONS method, but in the examples that do does not specify the charsets accepted by the server. So, it seems we can only get it from the documentation. And yes, maybe that would stop us to communicate with a server that only accepts POST request with some odd charset. For now, I’d say bad luck :slight_smile:

Can libcurl be compiled with emscripten? And a wrapper would probably require using the “multi” API to libcurl, which brings its own complications. OTOH, you’d get support for gopher, ftp, imap, pop3, HTTP proxy tunneling, etc. etc.

If all you want is a proxy server, they already exist, e.g. https://ubuntu.com/server/docs/proxy-servers-squid

As to gopher, ftp, etc. - I was making a bad joke, but I suppose it wasn’t obvious. (Does anyone use Gopher or FTP these days? I suppose there are some ancient examples out there, just as there are probably some people still using IE6)

That is not the HTTP API, though - it is About Swagger Specification | Documentation | Swagger

Yes, its a YAML specification of an API. You need to invoke a generator.
There are two types of users. Those that use the Swagger UI for the API.
And those that use the request handlers of the API.

I guess request handlers can be accessed via http:, i.e. HTTP with or
without REST, and via ws:, i.e. WebSockets, right? Does Swagger
support both? AWS Cloud seems to support both protocols.