API - Create a new PID

This API uses JSON as the primary exchange format. All implementations MUST be able to produce and consume JSON.

Create a new PID - Description

You want to create a new PID. There are two ways to create - generate a new PID

HTTP PUT can be used for both resource creation and resource updates . So if you want to be sure that you are going to create a new one you must first check if it exists. If you don’t check the existence of a PID based on the suffix it is possible that you will update the data of an existing one.

There is a way to make your HTTP PUT request “conditional” in the sense that it will only be executed if the URL doesn’t exist yet (which constitutes a create action), or that it does exist yet (which constitutes an update ).

Info In order to make the PUT request conditional use HTTP’s If-Match: * or If-None-Match:* headers.

Description Create a new PID
URL The API Service URL
HTTP Method PUT for manual generation of suffix name
HTTP Method POST for automatic generation of suffix name
Security Requires ownership of the PID. So you must authenticate before actually creating the PID

The data you must send in order to create are described in the following table

Type Description Required Default value Example value
suffix The local name of the handle in the system Yes None a) use a UUID generator via PUT method, b) automatic generation via POST method

The data you must send as json representation are described in the following table

Type Description Required Default value Example value
type Each handle has a set of values assigned to it. These handle values use a common data structure for its data. The data type defines the syntax and semantics of the data in its data field. Yes None URL
parsed_data A set of data that describes the resource identified by the handle. The syntax and semantics of parsed data are identified by the field. Yes None http://www.grnet.gr
timestamp The timestamp records the last time this Handle Value was updated at the server. The field contains elapsed time since 00:00:00 UTC, January 1970 in milliseconds. NO timestamp 2013-11-26T11:58:14Z
ttl_type the TTL type indicates whether the TTL value is absolute or relative. The absolute TTL value defines the time to live in terms of seconds since 00:00:00 UTC, January 1st 1970. A relative TTL specifies the time to live in terms of the number of seconds elapsed since the value was obtained by the client from any handle server. NO integer 0=relative, 1=absolute by default 0 0
ttl a number that specifies the Time-To- Live of the value record. A positive value defines the time to live in terms of seconds since 00:00:00 UTC, January 1st 1970. A negative value specifies the time to live in terms of the number of seconds elapsed since the value was obtained. (if ttl_type is absolute, then this indicates the date/time of expiration in seconds since Jan 1 0:00:00 1970.) NO integer seconds 86400
refs a list of references to other Handle Values No None [{‘idx’:’1’,’handle’:’11239/12’}] where idx is the value for index field of handle data, and handle is the referenced handle value

Example

In this example we are going to create a new handle via the PUT method in the following url https://epic.grnet.gr/handles/11239/UUIDGENERATE. There is an example via POST method at PID generation page

The request in curl


#!/bin/bash    

SUFFIX=`uuidgen`
curl -v -u "YOURUSERNAME:YOURPASSWORD" -H "Accept:application/json" -H "Content-Type:application/json" -X PUT --data '[{"type":"URL","parsed_data":"http://www.grnet.gr/"}]' https://epic.grnet.gr/api/v2/handles/11239/$SUFFIX 

The request in python

import urllib2
import uuid
import json

PIDSERVICE_URL="THE_SERVICE_URL_WITH_PREFIX"
PIDSERVICE_USER="YOURUSERNAME"
PIDSERVICE_PASSWD="YOURPASSWORD"
SUFFIX =str(uuid.uuid1());
URL_TO_OPEN=PIDSERVICE_URL+SUFFIX
DATAURL=''

# create a password manager
password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()

# Add the username and password.
password_mgr.add_password(None, PIDSERVICE_URL, PIDSERVICE_USER, PIDSERVICE_PASSWD)

handler = urllib2.HTTPBasicAuthHandler(password_mgr)

# create "opener" (OpenerDirector instance)
opener = urllib2.build_opener(handler)

# use the opener to fetch a URL
opener.open(PIDSERVICE_URL)

# Install the opener.
# Now all calls to urllib2.urlopen use the created opener.
urllib2.install_opener(opener)

#create the json data
JSONDATA = [{'type':'URL','parsed_data':'http://www.grnet.gr'}]
JSONDATATOSEND = json.dumps(JSONDATA);

REQUESTDATA = urllib2.Request(URL_TO_OPEN, data=JSONDATATOSEND)

#create the headers
REQUESTDATA.add_header('Content-Type','application/json')
REQUESTDATA.add_header('Content-Length',len(JSONDATATOSEND))

# creates the PUT method
REQUESTDATA.get_method = lambda: 'PUT'

try:
    DATAURL = urllib2.urlopen(REQUESTDATA)
    
except urllib2.URLError, e:
    print e
    if e.code == 404:
        print "404-Not found"
    if e.code == 401:
        print "401-Authentication failed"    
        #get http code of the request

if DATAURL:
    # Getting the code
    print "This gets the code: ", DATAURL.code

The request in php

$PIDSERVICE_URL="THE_SERVICE_URL_WITH_PREFIX";
$PIDSERVICE_USER="YOURUSERNAME";
$PIDSERVICE_PASSWD="YOURPASSWORD";
$UUID = gen_uuid(); //a function to generate a uuid
$URL_TO_OPEN = $PIDSERVICE_URL.$UUID;
$data = array(array('type' => 'URL','parsed_data'=>'http://www.grnet.gr/'));
$update_json=json_encode($data);

// Get cURL resource
$ch = curl_init();

//Set the headers to complete the request
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json','Content-Length: ' . strlen($update_json)));

//set the PUT Action
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");

//SET the postfield data
curl_setopt($ch, CURLOPT_POSTFIELDS,$update_json);

// Should cURL return or print out the data? (true = return, false = print)
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

//Set the url with the new name of the PID 
curl_setopt($ch, CURLOPT_URL, $URL_TO_OPEN);

// Set the authentication options
curl_setopt($ch, CURLOPT_USERPWD, $PIDSERVICE_USER.":".$PIDSERVICE_PASSWD);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);

$output = curl_exec($ch);
$info = curl_getinfo($ch);

// Download the given URL, and return output 

if( $info['http_code']==200) echo "HANDLE EXISTS";
if( $info['http_code']==201) echo "PID CREATED";
if( $info['http_code']==204) echo "PID UPDATED";
if( $info['http_code']==404) echo "HANDLE DOESNT EXIST";

curl_close($ch);

function gen_uuid() {
    return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
            // 32 bits for "time_low"
            mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),

            // 16 bits for "time_mid"
            mt_rand( 0, 0xffff ),

            // 16 bits for "time_hi_and_version",
            // four most significant bits holds version number 4
            mt_rand( 0, 0x0fff ) | 0x4000,

            // 16 bits, 8 bits for "clk_seq_hi_res",
            // 8 bits for "clk_seq_low",
            // two most significant bits holds zero and one for variant DCE1.1
            mt_rand( 0, 0x3fff ) | 0x8000,

            // 48 bits for "node"
            mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
    );
}

The request in perl

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;
use Getopt::Long;
use Switch 'Perl5', 'Perl6';
use JSON;
use WWW::Curl::Easy;

my $fullargv0 = $0;
my ($argv0) = $fullargv0 =~ /([^\/\\]+)$/;

my %settings = (
'debug' => 'False',
'handle' => {
	'action' =>'put',
	'credentials' 	=>	{
		'username'	=> 'empty',
		'password'	=> 'empty',
		'baseuri'	=> 'empty',
	},
	'data'	=>{
		'get'	=> '',
		'putpost'=> '',
	},
	'format' => 'none',
	'headerextra'	=> '',
	'type' => 'none',
	'url'=>	{
		'pid'=> 'ADD A PID',
	},
},
);

# Main subroutine
sub main {

	#Get the subroutine arguments
	my $settings_ref = shift;

	# Get the script arguments
	(my $returncode) = get_arguments($settings_ref);

	if( $returncode == 0 ) 
		 performPut($settings_ref);

	return($returncode);
}
 
# Subroutine to perform a PUT action
sub performPut {

	# Get the subroutine arguments
	my $settings_ref = shift;

	#construct url and headers
	my $url="$settings_ref->{handle}->{credentials}->{baseuri}$settings_ref->{handle}->{url}->{pid}";
	printf("The constructed url is        : %s\n",$url) if $settings_ref->{debug} =~ /True/ ;
	my @httpHeaders = ( 'Content-Type: application/json' );
	# add extra header info. f.i. "If-Match: *" or "If-None-Match: *"
	push(@httpHeaders, "$settings_ref->{handle}->{headerextra}" ) if $settings_ref->{handle}->{headerextra} ;

	#construct data
	my $data=$settings_ref->{handle}->{data}->{putpost};
	printf("The data is                   : %s\n",$data) if $settings_ref->{debug} =~ /True/ ;

	# perform action
	(my $returncode, my $response_code, my $response_content_type, my $response_body ) = httpPut($settings_ref, $url, \@httpHeaders, $data );

	# Looking at the results of the curl request
	if ($returncode == 0) {
		print('Transfer went ok\n') if $settings_ref->{debug} =~ /True/ ;

		# judge result and next action based on $response_code
		if ($response_code >= 200 && $response_code < 300 ) {
			print('The request went ok\n') if $settings_ref->{debug} =~ /True/ ;
		} else {
			print('The request went NOT ok\n') if $settings_ref->{debug} =~ /True/ ;
			print("$response_code\n");
		} 

	} else {
		print('An error happened\n');
	}
}

# reader helper calback function
sub read_callback {
	my ($maxlength,$pointer)=@_;
	# printf("The MAXLENGTH is     : \n", $maxlength);
	# printf("The POINTER is       : \n", $$pointer) ;
	my $data = $$pointer;
	$$pointer = "";
	return $data;
}

# Subroutine to post data via a http PUT
sub httpPut {

	# Get the subroutine arguments
	my $settings_ref = shift;
	my $url = shift;
	my $httpHeaders_ref = shift;
	my $data = shift;

	print('Entering httpPut              :\n')         if $settings_ref->{debug} =~ /True/;

	# local varables
	my $length = length ($data);
	my $body = "";
	my $header = "";
	my $response_body;
	my $response_code;
	my $response_content_type;

	my $curl = WWW::Curl::Easy->new;

	# set options for the curl http request
	$curl->setopt(CURLOPT_HEADER, 0);
	$curl->setopt(CURLOPT_HTTPHEADER, $httpHeaders_ref );
	$curl->setopt(CURLOPT_READFUNCTION, \&read_callback);
	$curl->setopt(CURLOPT_UPLOAD, 1);
	$curl->setopt(CURLOPT_INFILE, \$data);
	$curl->setopt(CURLOPT_INFILESIZE, length($data));
	$curl->setopt(CURLOPT_URL, $url);
	$curl->setopt(CURLOPT_USERNAME, $settings_ref->{handle}->{credentials}->{username});
	$curl->setopt(CURLOPT_PASSWORD, $settings_ref->{handle}->{credentials}->{password});

	#debugging
	#$curl->setopt (CURLOPT_VERBOSE, 1);

	# A filehandle, reference to a scalar or reference to a typeglob can be used here.
	open my $fh, '>', \$response_body or die "$!";
	$curl->setopt(CURLOPT_WRITEDATA, $fh);

	# Do the actual curl http request
	my $returncode = $curl->perform;

	# close file handle
	close($fh);

	# Looking at the results of the curl request
	if ($returncode == 0) {
		print('Transfer went ok\n') if $settings_ref->{debug} =~ /True/ ;

		$response_code         = $curl->getinfo(CURLINFO_HTTP_CODE);
		$response_content_type = $curl->getinfo(CURLINFO_CONTENT_TYPE);
		print("Received response code        : $response_code\n")         if $settings_ref->{debug} =~ /True/;
		print("Received response content type: $response_content_type\n") if $settings_ref->{debug} =~ /True/;

		# judge result and next action based on $response_code
		if ($response_code >= 200 && $response_code < 300 ) {
			print('The request went ok\n') if $settings_ref->{debug} =~ /True/ ;
			print("$response_body\n") if $settings_ref->{debug} =~ /True/ ;
		} else {
			print('The request went NOT ok\n') if $settings_ref->{debug} =~ /True/ ;
			print("$response_code\n") if $settings_ref->{debug} =~ /True/;
		} 

	} else {
		# Error code, type of error, error message
		print("An error happened: $returncode ".$curl->strerror($returncode)." ".$curl->errbuf."\n");
	}

	# Return the results
	return($returncode, $response_code, $response_content_type, $response_body );
}
# Subroutine to get and check all script arguments
sub get_arguments {

	# Get the subroutine arguments
	my $settings_ref = shift;

	# Define local variables
	my %arguments;
	my $username;
	my $password;
	my $baseUri;
	my $pidUrl;
	my $credentials;
	my $handleData;
	my $type;
	my $header;
	my $returncode=0;
	my $message;
	my @sources;

	GetOptions( 'h|help'    => \$arguments{help},
		'user=s'		=> \$username,
		'passwd=s'		=> \$password,
		'base=s'		=> \$baseUri,
		'pid=s'			=> \$pidUrl,
		'cred=s'		=> \$credentials,
		'data=s'		=> \$handleData,
		'type=s'		=> \$type,
		'header=s'		=> \$header,
		'get'			=> \$arguments{get},
		'put'			=> \$arguments{put},
		'delete'		=> \$arguments{delete},
		'post'			=> \$arguments{post},
		'pretty'		=> \$arguments{pretty},
		'd|debug'		=> \$arguments{debug},
	);

	# Check the help flag
	if( $arguments{help} ) {

		# Set the returncode
		$returncode=255;

		$message = print_help();
	}
	
	# Check the debug flag
	if( $arguments{debug} ) {

		$settings_ref->{debug} = 'True';
		printf('debug is                      : on\n') if $settings_ref->{debug} =~ /True/ ;

	}

	# Check the pretty flag
	if( $arguments{pretty} ) {

		$settings_ref->{handle}->{format} = 'pretty';
		printf('pretty format printing is     : on\n') if $settings_ref->{debug} =~ /True/ ;

	}

	# Check the action flag's (get,put,delete,post,search,nagios)
	if( $arguments{get} ) {

		$settings_ref->{handle}->{action} = 'get';
		printf("The action is                 : %s\n", $settings_ref->{handle}->{action}) if $settings_ref->{debug} =~ /True/ ;

	} elsif ( $arguments{put} ) {

		$settings_ref->{handle}->{action} = 'put';
		printf("The action is                 : %s\n", $settings_ref->{handle}->{action}) if $settings_ref->{debug} =~ /True/ ;

	} elsif ( $arguments{delete} ) {

		$settings_ref->{handle}->{action} = 'delete';
		printf("The action is                 : %s\n", $settings_ref->{handle}->{action}) if $settings_ref->{debug} =~ /True/ ;

	} elsif ( $arguments{post} ) {

		$settings_ref->{handle}->{action} = 'post';
		printf("The action is                 : %s\n", $settings_ref->{handle}->{action}) if $settings_ref->{debug} =~ /True/ ;

	}

	# check the username
	if( $username ) {

		$settings_ref->{handle}->{credentials}->{username} = $username;
		printf("The username is               : %s\n",$settings_ref->{handle}->{credentials}->{username}) if $settings_ref->{debug} =~ /True/ ;

	}

	# check the password
	if( $password ) {

		$settings_ref->{handle}->{credentials}->{password} = $password;
		printf("The password is               : %s\n",$settings_ref->{handle}->{credentials}->{password}) if $settings_ref->{debug} =~ /True/ ;

	}

	# check the base uri
	if( $baseUri ) {

		$settings_ref->{handle}->{credentials}->{baseuri} = $baseUri;
		printf("The base uri is               : %s\n",$settings_ref->{handle}->{credentials}->{baseuri}) if $settings_ref->{debug} =~ /True/ ;

	}

	# check the pid url
	if( $pidUrl ) {

		$settings_ref->{handle}->{url}->{pid} = $pidUrl;
		printf("The pid is                    : %s\n",$settings_ref->{handle}->{url}->{pid}) if $settings_ref->{debug} =~ /True/ ;
	
	}

	# check the handle data
	if( $handleData ) {

		$settings_ref->{handle}->{data}->{putpost} = $handleData;
		printf("The data is                   : %s\n",$settings_ref->{handle}->{data}->{putpost}) if $settings_ref->{debug} =~ /True/ ;
	
	}

	# check the type data
	if( $type ) {

		$settings_ref->{handle}->{type} = $type;
		printf("The type(s) to show is/are    : %s\n",$settings_ref->{handle}->{type}) if $settings_ref->{debug} =~ /True/ ;

	}
	
	# check the header data
	if( $header ) {

		$settings_ref->{handle}->{headerextra} = $header;
		printf("The extra header info is      : %s\n",$settings_ref->{handle}->{headerextra}) if $settings_ref->{debug} =~ /True/ ;
	
	}

	# check the credentials data
	if( $credentials ) {

		# read the credentials from the file
		my $filename = $credentials;
		my $json_text = do {
			open(my $json_fh, "<:encoding(UTF-8)", $filename)  or die("Can't open $filename: $!\n");
			local $/;
			<$json_fh>
		};

		# convert from json and put in correct place 
		my $json = JSON->new;
		$settings_ref->{handle}->{credentials} = $json->decode($json_text);

		printf("The username is               : %s\n",$settings_ref->{handle}->{credentials}->{username}) if $settings_ref->{debug} =~ /True/ ;
		printf("The password is               : %s\n",$settings_ref->{handle}->{credentials}->{password}) if $settings_ref->{debug} =~ /True/ ;
		printf("The base uri is               : %s\n",$settings_ref->{handle}->{credentials}->{baseuri}) if $settings_ref->{debug} =~ /True/ ;
	}

	# Print the message
	if( $message ) {

		print "$message\n";
	};

	# Return the results
	return($returncode);

};

The response:


HTTP/1.1 201 Created
Date: Mon, 25 Nov 2013 10:18:18 GMT
Content-Length: 2211
Location: https://epic.grnet.gr/api/v2/handles/11239/05C3DB56-5692-11E3-AF8F-1C6F65A666B5
ETag: "1B2M2Y8AsgTpgAmY7PhCfg"
Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT