For one-off applications, what you've done is just fine. If you're going to go through the trouble of making some code reusable, it'd better take you less time than writing out the extra "fluffy" code. If you're manually writing the username and password in the hash, just write it manually in the 2nd location as well.
It's hard to say what the Right Way[TM] is to do what you want without more information about what else you're doing. You can use the generator that mob showed. The "most right" way is probably to make it an object and make the headers key a method call.
{ package MyEndpoint;
sub new {
my $class = shift;
my $self = { @_ };
return bless $self, $class;
}
sub get_headers {
my self = shift;
my %headers = %{$self->{-headers}};
if ($self->{-auth} eq "basic") {
$headers{Authorization} = sprintf "Basic %s",
encode_base64(join ":", @{$self}{qw/-username -password/});
}
return %headers;
}
my %api_hash = (
api_endpoint1 => MyEndpoint->new(
-username => 'foo',
-password => 'bar',
-api_url => 'https://192.168.1.10:9200',
-auth => 'basic',
-headers => {Accept => 'application/json'},
},
...
);
## Later on when using the endpoint
foreach my $endpoint (values %api_hash) {
my @headers = $endpoint->get_headers;
...
}
But to directly answer your question, to use values from a data structure while you're defining it, you have to abuse the parser.
my %api_hash;
for (1, 2) {
%api_hash = (
'api_endpoint1' => {
'username' => 'foo',
'password' => 'bar',
'api_url' => 'https://192.168.1.10:9200',
'headers' => {Accept => 'application/json',
Authorization => 'Basic ' . encode_base64(
$api_hash{api_endpoint1}{username} . ':' . $api_hash{api_endpoint1}{password}
)}
},
'api_endpoint2' => {
'username' => 'bah',
'password' => 'wizz',
'api_url' => 'https://192.168.1.20:9182',
'headers' => {Accept => 'application/json',
Authorization => 'Basic ' . encode_base64(
$api_hash{api_endpoint2}{username} . ':' . $api_hash{api_endpoint2}{password}
)}
}
);
}
That's right, you execute the assignment twice with a loop. The first pass sets all the plain values; at this point all the self references are undef. On the second pass all the plain keys and values now exist so that the self references will resolve to the real values. You see why it's parser abuse. You're defining and overwriting the entire thing twice to get at those self references. For something small and quick and dirty that is just fine. This is Perl. However it's also wasteful and lame for Real Code[TM].
It's better to build it up from discreet variables or make it an object. This is one of the main reasons objects are awesome. You can shove all the boilerplate into a module and generate things only when you actually need them.
HTH