Interacting with a REST API from Clojure - api

What would be the suggested way to send and receive requests to an external REST API without having to run a web server? I can't seem to find anything about making requests and parsing the resulting JSON. The only thing I have found so far is just the json parsing stuff (using the Cheshire library).
Any help would be greatly appreciated!

A good library for interacting with an external REST API is clj-http, which uses Apache HTTPClient). For JSON, there are a few options: clojure.data.json (a core lib) and cheshire being some popular ones. The lib clj-http has cheshire as a dependency and has JSON support baked in. Cheshire makes use of Jackson.
For example, using clj-http:
(ns my.core
(:require [clj-http.client :as client]))
(client/put my-url
{:form-params body
:content-type :json
:oauth-token #token
:throw-exceptions false
:as :json})

Related

Marshmallow and Flask-RESTPlus, how should they be used along?

I'm using Flask-Restplus to marshal responses in a Flask server. I also began using this package to parse HTTP requests from the client, when I stumbled about this huge warning on their site:
Warning
The whole request parser part of Flask-RESTPlus is slated for removal
and will be replaced by documentation on how to integrate with other
packages that do the input/output stuff better (such as marshmallow).
I then switched to Marshmallow to validate/parse the HTTP client requests. Thus, the workflow in my server is:
Client request (HTTP GET/POST) ...
--> process request with Marshmallow and validate/format data
--> do stuff with DB (read, update, create)
--> Format output response with Flask RESTPLUS
... Client response
So far this works well. However, is this the correct way to use Flask RESTPLUS and Marshmallow along? On the marshmallow website, there is no clear direction towards a specific use of this package. The documentation just says:
Marshmallow is an ORM/ODM/framework-agnostic library for converting
complex datatypes, such as objects, to and from native Python
datatypes.
I have seen examples in the web where people use Marshmallow to format the output response, and Flask to validate expected data (with #api.expect). Which approach is better?
Also, I wonder if this even makes sense to use Flask RESTPLUS at all? It seems the only interest of this library is to have the Swagger UI doc automatically generated. Other than that, Marshmallow can do everything that Flask RESTPLUS does. So maybe I missed out something, can anyone help or comment?
Thanks
Take further notice of the warning displayed on the website:
Don’t worry, if you have code using that now and wish to continue doing so, it’s not going to go away any time too soon.
The developers will post documentation how to integrate best Marshmellow in the future.
So far this works well. However, is this the correct way to use Flask RESTPLUS and Marshmallow along? On the marshmallow website, there is no clear direction towards a specific use of this package
Flask is a microframework: what this means for you is that much of the implementation of your application is up to the programmer because it lacks most of the functionality which is common to expect in a full-fledged web application framework (eg. Django, Pyramid et al.) and there's not "one way and only one way" of doing things in it. Implementation details like data validation are up to you to provide via plugins, libraries or even implementing them yourself (not recommended).
I wonder if this even makes sense to use Flask RESTPLUS at all?
From what I've seen in the Quick start page of Flask-RESTPlus, it provides useful models that facilitates exposing REST verbs for resources, endpoints, arg parsing and data formatting. But again, this question depends mostly on you and your application requirements.

Savon::UnknownOptionError: convert_dashes_to_underscores

I am using Savon 2.11.1 as a Ruby SOAP client.
Savon uses Nori to translate the SOAP response XML to a Hash. Nori supports the option convert_dashes_to_underscores which by default converts all dashes in SOAP response to underscores.
I tried to use this option in the client's constructor but I got the following error message
Savon::UnknownOptionError: Unknown global option: :convert_dashes_to_underscores.
Why is this option not supported for Savon? Any workaround?
Thanks
M
I don't know why it isn't supported. I guess because nobody needed it up until now. I propose you extend the code, create the unit tests, upload the sources to github and send a pull request to the main project. Simple as that.
You can also look into the documentation where you'll find that the following symbols are available to control conversion
:camelcase
:lower_camelcase
:upcase
:none
http://savonrb.com/version2/globals.html

Rails respond_with -- why does POST return a URL instead of the data?

This is a question "why does it work this way", not "how do I make this work".
My app is calling a third party REST API that returns JSON, and returning the result as part of my own JSON API.
I was using the Rails 3 respond_to and respond_with methods; in the case of GET requests, this works as I expect, just passing through the JSON.
In the case of POST, it does more, including making a URL from the object returned to pass in a :location option. But since my object is just JSON (not ActiveRecord), I get an error.
For example...
# POST /api/products.json with params id=:id
def create
query_string = "#{user_id}&id=#{params[:id]}"
#products = third_party_api_wrapper.products(query_string, 'POST')
respond_with #products
end
My wrapper for the 3rd party API makes a POST request, which comes back fine, then Rails returns a 500 error which is logged like this:
NoMethodError (undefined method `{"response":{"message":"product 4e1712d9ec0f257c510013f8 selected"}}_url' for #<MyController>
Rails want's my #products object to know how to make a location URL.
CLARIFICATION: The #products object returned by the third party API is pure JSON -- a string, which you can see embedded in the error log message above. This error is occurring because Rails seems to want the object to be something more -- in the Rails internal API support, it is an ActiveRecord object.
If I replace the new respond_with with sytax with the old-style
respond_to do |format|
format.json { render :json => #products } # note, no :location or :status options
end
then everything works. And this is what I have done, so I don't have a "how" problem, instead have a "why" question.
Ryan Daigle's post on the introduction explains that what's happening is expected.
My question is: why does respond_with expect anything other than data (and the HTTP status?), and apparently just for POST.
I am not saying it's wrong, just trying to understand the rationale for the Rails implementation.
Summary: Rails gets its rationale from HTTP and REST.
(Thanks for your updated question. Now I understand your core question: "I am not saying it's wrong, just trying to understand the rationale for the Rails implementation.")
Now for the explanation. The rationale for how Rails behaves is rooted in embracing HTTP and REST conventions.
Just to bridge from what you've read to what I'm about to elaborate on, I want to mention the relevant parts from Ryan Daigle's article on Default RESTful Rendering:
If the :html format was requested:
[some text removed]
[after PUT or POST and no validation errors] redirect to the resource location (i.e. user_url)
(The text [in brackets] was added by me.)
If another format was requested, (i.e. :xml or :json)
[some text removed]
If it was a POST request, invoke the :to_format method on the resource and send that back with the :created status and the :location of the new created resource"
Let me put this in my words about what Rails believes is good practice:
For human content (e.g. HTML), after a POST or PUT, the server should tell the browser to redirect via a 303 to the newly created resource. This is common practice -- a very useful thing because a user wants to see the updates resulting from their edits.
For machine content (e.g. JSON, XML), after a PUT, the server should just render a 201. The client, in this case, a program consuming an API, might decide to stop there. (After all, the client specified the request and got a 201, so all is honky dory.) This is why 201 (success), not 303 (redirect), is used. If the client wants to request the newly created resource, it can look it up using the Location header -- but a redirect should not be forced.
In either case note that the location of the newly created resource is required. This is why #products in your example above needs to contain both the data and the location.
For background, I've shared a little from the W3C Page on 201 Created:
10.2.2 201 Created
The request has been fulfilled and resulted in a new resource being created. The newly created resource can be referenced by the URI(s) returned in the entity of the response, with the most specific URI for the resource given by a Location header field. The response SHOULD include an entity containing a list of resource characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content-Type header field. The origin server MUST create the resource before returning the 201 status code. If the action cannot be carried out immediately, the server SHOULD respond with 202 (Accepted) response instead.
I hope this helps to explain the rationale. It is my (naive?) understanding that this rationale is well accepted across Web frameworks. Historically, I suspect that Rails was the fervent implementation-ground (new word alert!) for many fervent supporters of REST and the Resource Oriented Architecture.
The 'why' has been answered excellently by #david-james. This is just a short 'how' to answer via respond_with:
class Api::V1::UsersController < ApplicationController
respond_to :json
def create
#user = User.create(...)
respond_with #user, location: url_for([:api, :v1, #user])
end
end
To answer this question: "why should an API return anything other than data (and the HTTP status?). I am not saying it's wrong, just trying to understand the rationale."
I can think of no good rationale. More importantly, I can't see any way that an API could return anything except a data structure! (This question doesn't make sense to me!)
By definition, an API call must return a data structure. (It might be as simple as a string. It might be JSON. It might be XML.) It can use content negotiation to decide on the format. It may or may not be a strict schema, but at the very least a client library must be able to parse it. In any case, the API documentation should make this abundantly clear and stick to it. How else can client libraries expect to interoperate?
I think I'm missing the point here, this seems too obvious. (I suspect you are having another problem in your code above.)

How to use Ideone API in WSDL Format

I want to set up my own online compiler. I want to use Ideone Api for this. But its api is available in WSDL format. I tried very hard but could find any tutorial on how to extract data from WSDL. Please tell some way to use Ideone api.
Maybe a late answer but still may be useful for others. Here a simple example in PHP with it's native SOAP libray: http://ideone.com/3JBbt
Regretfully my server doesn't support PHP's SOAP library so I have used NuSOAP in the demo, now you have two ways to work with IDE One API.
Here a simple demo: http://rendon.x10.mx/files/ide1example/
And here is the code: http://rendon.x10.mx/files/ide1example.tar.gz
NOTE: You need provide your own user and password in ideone.php.
$params = array(
'user' => $user, // your user
'pass' => $pass, // your pass
'sourceCode' => $code,
'language' => $lang,
'input' => $input,
'run' => $run,
'private' => $private
);
For more info about the functions consult the API document: http://ideone.com/files/ideone-api.pdf
WSDL as name says, it describes functionality or the methods for communicating a webservice ,
As you said you have WSDL, then i would suggest you to create a WebService Client and start using it in your program.
For creating a WebService client, i would suggest you to use some tools such as Ex: http://cxf.apache.org/, they give you nice tools to create WS Clients like WS2js, WS2Java etc., kinda
As u've mentioned Ideone specifically , i'm working on it too, i would suggest you to look at creating a WSclient from WSDL in Netbeans(for this you need to download a plugin JAX-RPC)
or refer to this project http://code.google.com/p/ideone-cli/ , they've a working implementation of ideone WS Client.

Consuming a Restful WCF Service with Ruby ActiveResource

I'm trying to consume a RESTful WCF service in a Rails app using ActiveResource.
My ActiveResource class is:
class PartReferenceService < ActiveResource::Base
self.site = "http://localhost:1234/"
end
The WCF URL is
http://localhost:1234/PartReferenceService.svc/
and it returns XML like:
<ArrayOfReferenceDataModel xmlns="http://schemas.datacontract.org/2004/07/RemoteService.Model" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ReferenceDataModel>
<Description>0460-0054</Description>
<Id>147</Id>
</ReferenceDataModel>
<ReferenceDataModel>
<Description>0960-0095</Description>
<Id>145</Id>
</ReferenceDataModel>
</ArrayOfReferenceDataModel>
I'm getting a 404 when I do:
PartReferenceService.find(:all)
I also can't find the URL that is being requested in my development.log file.
Any suggestions on where I may be going wrong? I'm fairly new to ActiveResource, and WCF for that matter, but my guess is that ActiveResource is creating a url like,
http://localhost:1234/part_reference_service/
but as I can't see anything in the logs I'm flying blind.
I'm in control of both ends so am able to make any changes needed.
Any help is much appreciated.
Use Fiddler to see exactly what is going on in the http requests.
First thing with ActiveResource - alwasy set the ActiveResource::Base.logger. Typically I just do
ActiveResource::Base.logger = ActiveResource::Base.logger
in my environment.rb after the config block.
Second thing with ActiveResource - it's a pretty horrible library, especially to use with a HTTP over XML api other than one produced by Rails (like one from WCF like you have). I've rolled my own solution, perhaps you'll like it - it's called Wrest.