I'm trying to connect to a REST web service with Drupal 7. Data is supplied via a url and I want to pull it into the D7 site to create and populate nodes. I'm using the feeds module to map the content and the JSONPath parser as the parser. I have also included Feeds HTTPFetcher Append Headers module so that I can add custom headers in to make sure it is JSON being returned and not badly formatted xml which I was getting before.
Custom headers:
Accept|application/json
Content-Type|application/json
I have a url that looks like http://192.136.0.31:8080/places/getAll
Further to the above I have the Devel module in place which is returning the feed array in the page using the code below in my template.php:
$request = drupal_http_request('http://192.136.0.31:8080/places/getAll', $options);
dpm(drupal_json_decode($request->data));
This is what Devel returns:
... (Array, 1192 elements)
0 (Array, 17 elements)
Address1 (String, 19 characters ) 1-2 The Road name
Address2 (String, 9 characters ) Shuinnad
The problem I'm having is getting this into feeds and mapping to the relevant fields. I don't know what should go in the context field - I have tried $...*, $.*, $...[*] but no luck.
When I click on an Array element from the devel output it shows $...[0]['Address1'] which suggests that should be the context - no luck.
Quick Update - using the drupal_json_decode function I can split the array out how I need to using php
foreach ($json as $section => $items) {
foreach ($items as $key => $value) {
//if ($key == 'Address1') {
echo "$section:\t$key\t: $value<br>";
//}
// check whether the current item is an array!
if(is_array($value)) {
echo "$key is sub array:<br />";
foreach($value as $subKey => $subValue)
echo "$subKey:\t$subValue<br />";
}
}
}
The question still stands, how do I replicate that in Feeds using the JSON parser?
You may need to try this module: Feeds JSONPath Parser
See this tutorial
Context: is where you put the JSONPath expression that represents the path to the array representing your data. For instance, in my file, this would be $.albums.data.*. If this were a PHP array, that would be basically
foreach($facebook['albums']['data'] as $value);
See more at: http://glassdimly.com/blog/tech/drupal-7-feeds-extensible-parsers-jsonpath-map-json-fields/feeds-extensible-parsers#sthash.BrIutjfl.dpuf
Related
There is an application that generates multiple records per day, containing different types of attributes like EmpName, EmpDesig etc. and stores it in JSON format. This application then needs to make a call towards external REST api to POST this data that is in JSON format. The external application will read the JSON file, parse it, and store each record in the PostgreSQL database. How do I write a REST api in Perl for this requirement? Do I need any Perl framework like Mojolicious or Catalyst or Perl modules like JSON, Rest::Client are enough for this requirement? Please suggest.
If you do want to use a framework, it'll simplify your code a lot.
You could do it with the Dancer framework in a single line:
perl -e 'use Dancer; any "/", sub{ warn to_dumper from_json request->body; return "ok" }; start'
However, this answer is just a start, it's not robust nor contains any checks.
You don't strictly need a framework. It's easiest to get started with Plack::Request. The next step up would be adding a router like Router::Resource. Upgrading to a framework makes sense when you find this style of programming too tedious.
use Plack::Request qw();
use HTTP::Status qw(
HTTP_NO_CONTENT HTTP_NOT_FOUND HTTP_METHOD_NOT_ALLOWED
HTTP_UNSUPPORTED_MEDIA_TYPE HTTP_UNPROCESSABLE_ENTITY
HTTP_INTERNAL_SERVER_ERROR
);
use JSON::MaybeXS qw(decode_json);
use Syntax::Keyword::Try;
require IO::Handle;
use DBI qw();
require DBD::Pg;
my $app = sub {
my ($env) = #_;
my $req = Plack::Request->new($env);
return $req->new_response(HTTP_NOT_FOUND)->finalize
unless '/receive_json' eq $req->path_info;
return $req->new_response(HTTP_METHOD_NOT_ALLOWED)->finalize
unless 'POST' eq $req->method;
return $req->new_response(HTTP_UNSUPPORTED_MEDIA_TYPE)->finalize
unless $req->content_type =~ m'^application/.*json$';
my $body = do {
IO::Handle->input_record_separator(undef);
$req->input->getline;
};
my $json;
try {
$json = decode_json $body;
} catch {
warn "could not decode JSON: $#";
return $req->new_response(HTTP_UNPROCESSABLE_ENTITY)->finalize;
}
my $dbh;
try {
$dbh = DBI->connect(
"dbi:Pg:dbname=$ENV{PGDATABASE}",
$ENV{PGUSER},
$ENV{PGPASSWORD},
{pg_enable_utf8 => 1, RaiseError => 1}
);
} catch {
warn "could not connect to database: $#";
return $req->new_response(HTTP_INTERNAL_SERVER_ERROR)->finalize;
}
my $sth = $dbh->prepare(
'insert into sometable(EmpName, EmpDesig) values (?,?)'
);
try {
$sth->execute($json->{EmpName}, $json->{EmpDesig});
} catch {
warn "could not insert: $#";
return $req->new_response(HTTP_INTERNAL_SERVER_ERROR)->finalize;
}
return $req->new_response(HTTP_NO_CONTENT)->finalize;
};
Following is the code snippet where I am observing error: "malformed JSON string, neither array, object, number, string or atom, at character offset 0 (before "(end of string)") at"
Error observed is at the decode_json line. Can someone point out what is the error?
my $serverurl = "http://mycompany.net/rest/api/2/";
my $username = 'my.email#domain.com';
my $password = "mypassword\#2019";
my $i ;
my $test;
my $headers = {Accept => 'application/json', Authorization => 'Basic ' .encode_base64($username . ':' . $password)};
my $client = REST::Client->new();
my $idartinstance;
my $idartinstance1;
if (!$idartinstance)
{
print " Trying to Connect to URL using REST client interface \n\n";
$idartinstance1 = $client->GET($serverurl."serverinfo",$headers);
$idartinstance = decode_json($idartinstance1->responseContent());
}
When I print $idartinstance, I get this:
REST::Client=HASH(0x8682024)->responseContent()
Does this mean, it is not able to find REST client?
[EDIT] I have modified the script as below and no difference in the errors.
my $serverurl = "https://mycompany.net/rest/api/3/";
my $username = 'my.email#domain.com';
my $password = 'pf9fCdkGXmi4pMHiwIh74A0D';
my $headers = {Accept => 'application/json', Authorization => 'Basic ' . encode_base64($username . ':' . $password)};
my $client = REST::Client->new();
if (!$idartinstance)
{
print " Trying to Connect to JIRA using REST client interface \n\n";
$client->GET($serverurl."serverInfo", $headers);
print $client->responseContent();
$idartinstance = decode_json($client->responseContent());
}
Now I have used encoded password. Error is same: malformed JSON string, neither array, object, number, string or atom, at character offset 0 (before "(end of string)"). Tried accessing "https://mycompany.net/rest/api/3/serverInfo" via web browser and able to get the details.
Once you get a response, you have to check that its what you want.
if( $client->responseCode() eq '200' ){
print "Success\n";
}
You may also want to check that the content-type is what you expect. If it's supposed to be JSON, check that it is:
if( $client->responseHeader('Content-Type') =~ m|\Aapplication/json\b| ) {
print "Got JSON\n";
}
Once you've established that you have what you wanted, pass the message body off to the JSON decoder.
my $data = decode_json($client->responseContent());
You might also try to catch errors where you should have valid JSON but don't. The block eval can handle that (and see the many sources of the proper employment of eval for its best use):
my $data = eval { decode_json(...) };
I find that I tend to get the wrong content in two situations:
the wrong endpoint, from which a 404 handler returns HTML
a captive portal, which also returns HTML
I think you're misreading the documentation for the module. From the synopsis there, the example that most closely resembles yours is the first one:
my $client = REST::Client->new();
$client->GET('http://example.com/dir/file.xml');
print $client->responseContent();
Notice, in particular, that this example does nothing with the return value from GET(). In your example you do the equivalent of this:
my $client = REST::Client->new();
my $resp = $client->GET('http://example.com/dir/file.xml');
print $resp->responseContent();
As it happens, although there is no documented return value from GET() [Update: I was wrong here - see the first comment - but the return value is really only intended for chaining method calls], it actually returns the object that it was passed, so your approach should work. But it's generally a bad idea to not follow the documentation.
So what is actually going wrong? Well, I'm not sure. As I said, your approach should (accidentally) work. But the error message you're getting tells us that what you're passing to decode_json() is a REST::Client object, not a string containing JSON. I don't think that's how your code should work. Perhaps the code you've shown us isn't actually the code you're running.
The best approach to debug this is to follow the advice from Quentin in the first comment on your question - print the value that you're trying to pass to decode_json() before passing it to the function. In fact, that's good general programming advice - originally write out your code step by step, and only combine steps once you know that the individual steps are working correctly.
Using your variable names, I think your code should look like this:
my $client = REST::Client->new();
# ...other code...
$client->GET($serverurl."serverinfo", $headers);
print $client->responseContent();
# And, only once you've established that
# $client->responseContent() returns what
# you expect, you can add this:
$idartinstance = decode_json($client->responseContent());
If the print() statement doesn't show you JSON, then update your question to add whatever is printed and we'll take a further look.
So I have a wordpress Ajax function that retrieves MySQL data as JSON and logs it. However I want to not directly get the data back on the page where my AJAX function is, but I want to save the data to a JSON file instead, so I can use it for a wider variety of purposes.
Here is my AJAX function:
$.get(
ajax_url,
data,
function(data) { // AJAX callback
fill_json(data);
}// End AJAX callback
);
The fill_json() is a function to echo the JSON data in a table I wrote myself.
Now here is what happens inside my AJAX hook:
$sql_search = $wpdb->get_results(" a complicated mysql search here ");
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
$result = json_encode($result);
echo $result;
} else {
header("Location: ".$_SERVER["HTTP_REFERER"]);
}
underneath echo $result; in my Ajax hook I tried the following piece of code, but I don't know how I can see if it worked or not:
$json_path = "/var/www/vhosts/jtc.ae/httpdocs/pre/wp/wp-content/themes/Amazing_japan_HP/new/search.json";
file_put_contents($json_path, $result);
My question:
Is this the correct way to save the data to a JSON file, and how can I get this data on my main page then?
Extra question: Will saving $result to a JSON file conflict with multiple users using the AJAX at the same time?
All you did is right .. please make sure the steps below :
Pass write permission to the folder /new inside "Amazing_japan_HP" (chmod -R 666 /new)
To save the data in file use file_put_contents($file, $current);
To get the data from the file use $current = file_get_contents($file);
For all newly created files try to use umask. It provides required permission to the files for writing content in it
umask() sets PHP's umask to mask & 0777 and returns the old umask.
When PHP is being used as a server module, the umask is restored when
each request is finished.
How, do I implement code igniter rest API that outputs with ajax outputting the JSON. I'm unsure how to use the REST API for deleting and adding with the JSON. How to delete a item from the JSON and then from the database.
1. Rest API routing
Let's start with the routing of your API - If you apply best practice to your API you will want to use HTTP verbs (POST/PUT/GET...). (Read more on HTTP Verbs and REST here)
If you are on Codeigniter 2.x then read this SO question and answer
If you are on Codeigniter 3.x then read this documentation
On the other side, if you are planning to use the API only internally and the scope of the project is limited you can just ignore HTTP verbs and simply make POST and GET calls to your controllers.
2. Creating JSON response
Generally you will not need to use views - you can have your controllers echo the JSON response. Here is an example of a fictional API that has an API call to get an actor from a database of actors.
/* ----------------------------------------------
| Example of an API Method to get an actor from
| a database of actors:
| call: http://example.com/api/GetActorById
| parameter: actor_id
| Method: POST
*/
public function GetActorById(){
// Let's first get the actor ID from the POST data
$actor_id = $this->input->post('actor_id');
// If the API Method would be GET you would get the
// actor ID over the URI - The API call would look
// like this: http://example.com/api/GetActorById/<actor_id>
// In that case you take your actor ID from the segment:
$actor_id = $this->uri->segment(3);
// Do your database query magic here!
// ...
// ...
// Let's create an array with some data
// In real life this usually comes from a DB query above
$data = array(
'Firstname' => 'Michael',
'Lastname' => 'Fox',
'IsActor' => True,
'UserId' => 1234567
);
// Now let's convert the array into a JSON
$json = json_encode($data);
// if the API is accessed from a different domain
// you will want to allow cross domain access
header('Access-Control-Allow-Origin: *');
// Now let's return the json
echo $json;
}
The output will look like this:
{"Firstname":"Michael","Lastname":"Fox","IsActor":true,"ActorID":123456789}
Hope this helps - Good luck with your project!
I intending to get a json response without rendering a view with eZ Publish.
So I trying to use a custom module to do that:
function jsonConvert(){
$articles = eZFunctionHandler::execute(
'content',
'tree',
array(
'parent_node_id' => '59'
)
);
header("Content-Type: application/json");
return json_encode($articles);
}
echo jsonConvert();
How can I compile this module without using a basic URL that rendering a view like domain.com/module/view/ in order to get a json response without any HTML code?
echo json_encode( YOUR ARRAY );
eZExecution::cleanExit();
It's all what you need in your custom module/view php file to return json.
If I were you :
use the builtin feature that allows you to use a different layout to render a content view. Create a new layout 'MYLAYOUT' within a layout.ini.append.php override (see https://doc.ez.no/eZ-Publish/Technical-manual/4.x/Reference/Configuration-files/layout.ini) and then call your view using /layout/set/MYLAYOUT/your/content/uri
specify the content type in the layout configuration to match your requirements (application/json as the content type)
create a pagelayout.tpl template used by your newly created layout which basically only contains {$module_result.content}
create a template operator to convert your contents into a 'readable' json and call it from the template rendering your content (probably a /node/view/full.tpl override)
alternative (but not that sexy) to #4 => call json_encode directly in your template by allowing the php function to be called in your templates (see https://doc.ez.no/eZ-Publish/Technical-manual/4.x/Reference/Configuration-files/template.ini/PHP/PHPOperatorList)
To get a blank pagelayout in your module, and set a json content type, you can add this following lines in your module php file :
header("Content-Type: application/json");
$Result = array();
$Result['content'] = json_encode($articles);
$Result['pagelayout'] = false;