API-INSEE-Sirene

 view release on metacpan or  search on metacpan

lib/API/INSEE/Sirene.pm  view on Meta::CPAN

    defined $proxy ? $self->{'user_agent'}->proxy([ 'http', 'https' ], $proxy) : $self->{'user_agent'}->env_proxy;
}

sub setTimeout {
    my ($self, $timeout) = @_;

    $timeout //= DEFAULT_TIMEOUT;
    $self->{'user_agent'}->timeout($timeout);
}

sub setCurrentEndpoint {
    my ($self, $endpoint) = @_;

    $self->{'current_endpoint'} = $endpoint;
}

sub _dumpRequest {
    my ($self, $request, $response) = @_;

    my $dump = sprintf "Sent request:\n%s\n", $request->as_string;
    $dump .= sprintf "Received response:\n%s\n", $response->as_string if defined $response;

    return $dump;
}

sub _initUserAgent {
    my $self = shift;

    $self->{'user_agent'} = LWP::UserAgent->new(protocols_allowed => [ 'http', 'https' ]);

    $self->{'user_agent'}->agent("Perl API::INSEE::Sirene V$VERSION");
    $self->{'user_agent'}->default_header('Accept' => 'application/json');
}

sub _getToken {
    my $self = shift;

    croak 'Please provide your credentials.' if !defined $self->{'credentials'};

    my $request = POST API_AUTH_URL,
        Authorization => "Basic $self->{'credentials'}",
        Content       => [ grant_type => 'client_credentials' ];

    my $response = $self->{'user_agent'}->request($request);
    my $json_obj;

    if ($response->content_type =~ m/^application\/json/) {
        $json_obj = decode_json($response->content);
    }
    else {
        return 1, $self->_dumpRequest($request, $response); # the API may return xml intead of json...
    }

    switch ($response->code) {
        case HTTP_OK {
            $self->{'token_expiration'} = time + $json_obj->{'expires_in'};
            $self->{'user_agent'}->default_header( Authorization => "Bearer $json_obj->{'access_token'}" );
            return 0;
        }
        case HTTP_UNAUTHORIZED { # wrong credentials
            return 1 , $json_obj->{'error_description'};
        }
        else { # oh dear we are in trouble
            return 1, $self->_dumpRequest($request, $response);
        }
    }
}

sub _sendRequest {
    my ($self, $parameters) = @_;

    my $request;
    if (!exists $parameters->{'q'}) {
        my @url_parameters;

        foreach my $key (keys %{ $parameters }) {
            push @url_parameters, join '=', $key, $parameters->{$key};
        }

        my $endpoint = join '?', $self->{'current_endpoint'}, join '&', @url_parameters;
        $request = GET join '/', API_BASE_URL, $endpoint;
    }
    else {
        $request = POST join('/', API_BASE_URL, $self->{'current_endpoint'}),
            Content => [ %{ $parameters } ];
    }

    if ($self->{'debug_mode'}) { # Requests will not be sent in debug mode
        return 0, $self->_dumpRequest($request);
    }

    if (!defined $self->{'token_expiration'} || $self->{'token_expiration'} < time) {
        my ($err, $msg) = $self->_getToken();
        croak $msg if $err;
    }

    my $response = $self->{'user_agent'}->request($request);

    switch ($response->code) {
        case [ HTTP_OK, HTTP_NOT_FOUND ] {
            return 0, $response->content;
        }
        case HTTP_MOVED_PERMANENTLY { # duplicated legal unit/ establishment
            return 1, sprintf "%s\n%s", $response->message, $response->header('Location');
        }
        case [
            HTTP_REQUEST_URI_TOO_LARGE, HTTP_TOO_MANY_REQUESTS,
            HTTP_UNAUTHORIZED, HTTP_FORBIDDEN,
            HTTP_SERVICE_UNAVAILABLE
        ] {
# There is no syntax error in request, the http message should be sufficient to understand the problem
            return 1, $response->message;
        }
        else { # case HTTP_BAD_REQUEST || HTTP_INTERNAL_SERVER_ERROR
            return 1, $self->_dumpRequest($request, $response);
        }
    }
}

sub _buildParameters {
    my ($self, $usefull_fields, $desired_fields, $criteria) = @_;

# Parameters names come from the documentation
    my $parameters = {
        date   => strftime('%Y-%m-%d', localtime),
        nombre => $self->{'max_results'},
    };
    $parameters->{'champs'} = $self->_buildFields($usefull_fields, $desired_fields) if (defined $desired_fields && $desired_fields ne 'all');
    $parameters->{'q'}      = sprintf('(%s)', $criteria) if defined $criteria;

    return $parameters;
}

sub _buildFields {
    my ($self, $usefull_fields, $desired_fields) = @_;

    if (defined $desired_fields) {
        return $self->_mapAliases($desired_fields);
    }
    else {
        return join ',', @{ $usefull_fields };
    }
}

sub _mapAliases {
    my ($self, $desired_fields) = @_;

    my @desired_fields = ref $desired_fields eq 'ARRAY' ? @{ $desired_fields } : $desired_fields;

    foreach my $desired_field (@desired_fields) {
        if (exists $useful_fields_aliases->{$desired_field}) {
            if (ref $useful_fields_aliases->{$desired_field} eq 'ARRAY') {
                $desired_field = join ',', @{ $useful_fields_aliases->{$desired_field} };
            }
            else {
                $desired_field = $useful_fields_aliases->{$desired_field};
            }
        }
    }

    return join ',', @desired_fields;
}

sub getCustomCriteria {
    my ($self, $field_name, $value, $search_mode) = @_;

    croak 'No endpoint specified.' if !defined $self->{'current_endpoint'};

    $search_mode //= 'aproximate';
    if (exists $useful_fields_aliases->{$field_name}) {
        if (ref $useful_fields_aliases->{$field_name} eq 'ARRAY') {

lib/API/INSEE/Sirene.pm  view on Meta::CPAN


Search all establishments which SIRET number is begining by the number given in parameter.

=head2 searchLegalUnitBySIREN

Search all legal units which SIREN number is begining by the number given in parameter.

=head2 setCredentials

You can set your credentials separately from the instantiation if you need to (but this must be done before any call to the search methods).

  $sirene->setCredentials('Y29uc3VtZXIta2V5OmNvbnN1bWVyLXNlY3JldA==');

=head2 setCurrentEndpoint

Used to specifie the reached API endpoint.

=head2 setDebugMode

Enables the debug mode. When enabled, all the requests built by the module are displayed instead of being sent.

  $sirene->setDebugMode(1);

=head2 setMaxResults

Used to override the B<< DEFAULT_MAX_RESULTS >> value to get more results, within the limit of B<< HARD_MAX_RESULTS >> value.

  $sirene->setMaxResults(30);

=head2 setProxy

You can define which proxy server must be used to send requests. The system's proxy settings are used by default.

  $sirene->setProxy('https://myproxy.com:1234');

=head2 setTimeout

Used to override the B<< DEFAULT_TIMEOUT >> value.

  $sirene->setTimeout(40);

=head1 PARAMETERS

All search methods take an optional C<< $desired_fields >> parameter that comes in three differents flavours:

  my $fields_that_interest_me = ['dateCreationUniteLegale', 'sigleUniteLegale'];
  my $response_json = $sirene->getLegalUnitBySIREN(123456789, $fields_that_interest_me);

  # or
  my $response_json = $sirene->getLegalUnitBySIREN(123456789, 'dateCreationUniteLegale');

  # or
  my $response_json = $sirene->getLegalUnitBySIREN(123456789, 'all');

When you don't specify any desired field, the module returns a selection of fields that are most likely to interest you. (see C<$useful_fields_legal_unit> and C<$useful_fields_establishment> in source code to find out which ones)

If you want all fields, you have to specify it explicitly by passing the value 'all' as parameter.

=head1 RETURN VALUES

Each method returns a list of two elements: a return code, which is 0 in case of success, or something else in case of failure; and the result of the request (some json or an error message). In case of problem when calling API (malformed request for ...

The module may launch a croak if the crendentials are not initialized or if the SIREN/SIRET numbers are not given in a correct format.

=head1 ALIAS

Some fields have more user-friendly aliases:

  my $useful_fields_aliases = {
    nicSiege                        => 'nicSiegeUniteLegale',
    nom                             => [ 'denominationUniteLegale', 'nomUniteLegale' ],
    dateCreation                    => 'dateCreationUniteLegale',
    sigle                           => 'sigleUniteLegale',
    categorieJuridique              => 'categorieJuridiqueUniteLegale',
    nomenclatureActivitePrincipale  => 'nomenclatureActivitePrincipaleUniteLegale',
    activitePrincipale              => 'activitePrincipaleUniteLegale',
    numvoie                         => 'numeroVoieEtablissement',
    typevoie                        => 'typeVoieEtablissement',
    nomvoie                         => 'libelleVoieEtablissement',
    codePostal                      => 'codePostalEtablissement',
    nomCommune                      => 'libelleCommuneEtablissement',
    adresseComplete                 => [
                                        'numeroVoieEtablissement',
                                        'typeVoieEtablissement', 'libelleVoieEtablissement',
                                        'codePostalEtablissement', 'libelleCommuneEtablissement'
                                    ],
  };

B<Usage:>

  my $response_json = $sirene->getLegalUnitBySIREN(123456789, 'nom');

is equivalent to

  my $response_json = $sirene->getLegalUnitBySIREN(123456789, 'denominationUniteLegale');

=head1 AUTHOR

Justin Fouquet <jfouquet at lncsa dot fr>

=head1 COPYRIGHT AND LICENSE

Copyright 2018-2021 by Les Nouveaux Constructeurs

This library is free software; You can redistribute it and/or modify it under the same terms as Perl itself.

=cut



( run in 0.444 second using v1.01-cache-2.11-cpan-bbc515a03b3 )