You need to sign in to do that
Don't have an account?
Paulo Proença
Try to insert data from api using batch
I´m trying to get data from PokeAPI and insert in a Customo object and this is what i have so far.
public with sharing class PokemonBatch implements Database.Batchable<SObject>,Database.AllowsCallouts{
public Iterable<SObject> start(Database.BatchableContext context){
return Database.getQueryLocator('SELECT Id FROM Pokemon__c');
}
public void execute(Database.BatchableContext context,List<SObject> scope){
List<Pokemon__c> pokemonList = new List<Pokemon__c>();
for (Object obj : scope) {
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint('https://pokeapi.co/api/v2/pokemon?limit=905');
request.setMethod('GET');
HttpResponse response = http.send(request);
// Check if Connection was successful
if (response.getStatusCode() == 200) {
//deserialize response
Map<String,Object> responseData = (Map<String,Object>) JSON.deserializeUntyped(response.getBody());
List<Object> results = (List<Object>) responseData.get('results');
//get url of pokemon's endpoints
for (Object result : results) {
Map<String,Object> pokemonData = (Map<String,Object>) result;
String pokemonUrl = (String) pokemonData.get('url');
//Make call to new endpoint
HttpRequest detailsRequest = new HttpRequest();
detailsRequest.setEndpoint(pokemonUrl);
detailsRequest.setMethod('GET');
HttpResponse detailsResponse = new Http().send(detailsRequest);
// Check if Connection to the new endpoint was successful
if (detailsResponse.getStatusCode() == 200) {
//deserialize response
Map<String,Object> detailData = (Map<String,Object>) JSON.deserializeUntyped(detailsResponse.getBody());
// get fields from detail data
//***** get the id
Integer id = (Integer) detailData.get('id');
//***** Check if the id is greater than the number of pokemons we want to get
//***** we only want the pokemons until the 8th generation
if(id > 905){
return;
}
//***** get and convert height and weight to the correct units
Double height = (Double) detailData.get('height')/10;
Double weight = (Double) detailData.get('weight')/10;
//***** get the name
String name = (String) detailData.get('name');
//***** get and handle multiple types
List<Object> types = (List<Object>) detailData.get('types');
List<String> typeList = new List<String>();
for (Object type : types) {
Map<String,Object> typeData = (Map<String,Object>) type;
Map<String,Object> typeName = (Map<String,Object>) typeData.get('type');
String nameType = (String) typeName.get('name');
typeList.add(nameType);
}
//***** get species url to adquire the generation
Map<String,Object> species = (Map<String,Object>) detailData.get('species');
String speciesUrl = (String) species.get('url');
// make a call to the species endpoint
HttpRequest speciesRequest = new HttpRequest();
speciesRequest.setEndpoint(speciesUrl);
speciesRequest.setMethod('GET');
HttpResponse speciesResponse = new Http().send(speciesRequest);
// Check if Connection to the new endpoint was successful
if (speciesResponse.getStatusCode() == 200){
//deserialize response
Map<String,Object> speciesDetails = (Map<String,Object>) JSON.deserializeUntyped(speciesResponse.getBody());
//***** get the generation url and extract the the generation number from the end
Map<String,Object> generationDetails = (Map<String,Object>) speciesDetails.get('generation');
String generationUrl = (String) generationDetails.get('url');
String generation = generationUrl.substring(generationUrl.length() - 2, generationUrl.length() -1);
//***** get the sprites
Map<String,Object> sprites = (Map<String,Object>) detailData.get('sprites');
String spriteUrl = (String) sprites.get('front_default');
//***** create a new pokemon object and insert the data extratted fom the API
Pokemon__c pokemon = new Pokemon__c(Name=name.capitalize(),
PokeIndex__c=id,
Peso__c = String.valueOf(weight + ' kg'),
Altura__c = String.valueOf(height + ' mts'),
Tipo__c = String.join(typeList, ';'),
Geracao__c = Integer.valueOf(generation),
Foto_URL__c = spriteUrl
);
pokemonList.add(pokemon);
}
}
//***** insert list of records only if the list is not empty
}
}
}
if (!pokemonList.isEmpty()) {
insert pokemonList;
}
}
public void finish(Database.BatchableContext context){
// nothing
}
}
but the batch do not insert anything it shows completed but 0 batches processed. Any thoughts?
public with sharing class PokemonBatch implements Database.Batchable<SObject>,Database.AllowsCallouts{
public Iterable<SObject> start(Database.BatchableContext context){
return Database.getQueryLocator('SELECT Id FROM Pokemon__c');
}
public void execute(Database.BatchableContext context,List<SObject> scope){
List<Pokemon__c> pokemonList = new List<Pokemon__c>();
for (Object obj : scope) {
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint('https://pokeapi.co/api/v2/pokemon?limit=905');
request.setMethod('GET');
HttpResponse response = http.send(request);
// Check if Connection was successful
if (response.getStatusCode() == 200) {
//deserialize response
Map<String,Object> responseData = (Map<String,Object>) JSON.deserializeUntyped(response.getBody());
List<Object> results = (List<Object>) responseData.get('results');
//get url of pokemon's endpoints
for (Object result : results) {
Map<String,Object> pokemonData = (Map<String,Object>) result;
String pokemonUrl = (String) pokemonData.get('url');
//Make call to new endpoint
HttpRequest detailsRequest = new HttpRequest();
detailsRequest.setEndpoint(pokemonUrl);
detailsRequest.setMethod('GET');
HttpResponse detailsResponse = new Http().send(detailsRequest);
// Check if Connection to the new endpoint was successful
if (detailsResponse.getStatusCode() == 200) {
//deserialize response
Map<String,Object> detailData = (Map<String,Object>) JSON.deserializeUntyped(detailsResponse.getBody());
// get fields from detail data
//***** get the id
Integer id = (Integer) detailData.get('id');
//***** Check if the id is greater than the number of pokemons we want to get
//***** we only want the pokemons until the 8th generation
if(id > 905){
return;
}
//***** get and convert height and weight to the correct units
Double height = (Double) detailData.get('height')/10;
Double weight = (Double) detailData.get('weight')/10;
//***** get the name
String name = (String) detailData.get('name');
//***** get and handle multiple types
List<Object> types = (List<Object>) detailData.get('types');
List<String> typeList = new List<String>();
for (Object type : types) {
Map<String,Object> typeData = (Map<String,Object>) type;
Map<String,Object> typeName = (Map<String,Object>) typeData.get('type');
String nameType = (String) typeName.get('name');
typeList.add(nameType);
}
//***** get species url to adquire the generation
Map<String,Object> species = (Map<String,Object>) detailData.get('species');
String speciesUrl = (String) species.get('url');
// make a call to the species endpoint
HttpRequest speciesRequest = new HttpRequest();
speciesRequest.setEndpoint(speciesUrl);
speciesRequest.setMethod('GET');
HttpResponse speciesResponse = new Http().send(speciesRequest);
// Check if Connection to the new endpoint was successful
if (speciesResponse.getStatusCode() == 200){
//deserialize response
Map<String,Object> speciesDetails = (Map<String,Object>) JSON.deserializeUntyped(speciesResponse.getBody());
//***** get the generation url and extract the the generation number from the end
Map<String,Object> generationDetails = (Map<String,Object>) speciesDetails.get('generation');
String generationUrl = (String) generationDetails.get('url');
String generation = generationUrl.substring(generationUrl.length() - 2, generationUrl.length() -1);
//***** get the sprites
Map<String,Object> sprites = (Map<String,Object>) detailData.get('sprites');
String spriteUrl = (String) sprites.get('front_default');
//***** create a new pokemon object and insert the data extratted fom the API
Pokemon__c pokemon = new Pokemon__c(Name=name.capitalize(),
PokeIndex__c=id,
Peso__c = String.valueOf(weight + ' kg'),
Altura__c = String.valueOf(height + ' mts'),
Tipo__c = String.join(typeList, ';'),
Geracao__c = Integer.valueOf(generation),
Foto_URL__c = spriteUrl
);
pokemonList.add(pokemon);
}
}
//***** insert list of records only if the list is not empty
}
}
}
if (!pokemonList.isEmpty()) {
insert pokemonList;
}
}
public void finish(Database.BatchableContext context){
// nothing
}
}
but the batch do not insert anything it shows completed but 0 batches processed. Any thoughts?
A single Apex transaction can make a maximum of 100 callouts to an HTTP request or an API call.
How many records are in that object?
How large a batch size are you specifying when you launch the batch process?
Trying to determine what you're actually wanting to accomplish, it seems that maybe you're calling out to obtain a list of records you want to insert into your Pokemon__c data object.
How many pokemon can be returned by that callout? If it's under 2000, you can simply call-out, build a list and insert them all at once.
If you're expecting 20,000 (for example), then you would need to batch the insert statements, not a query over an empty object.
Could it be that what you really want is to perform the callout in your start method, build a list of pokemon__c records in the start method and return that list to the batch process, Then the execute method would simply perform the insert?
I already kind of solve the problem by using the scope has a loop allways getting the scope.get(0) a put it on the endpoint so it get one at a time but it removes the point of the batch because my batch has size 1, so i´m still looking for a cleaner and efficient solution.
To resolve these issues, you need to update your code logic to ensure that you are processing the records from the scope list correctly and making the necessary API calls to retrieve the Pokemon data. You should iterate over the scope list and use each record to determine the specific Pokemon you need to fetch data for and then insert the relevant Pokemon records into the pokemonList before finally inserting them.
Here's an updated version of the execute method that should help you get started: You'll need to update the code within the for loop to fetch the specific Pokemon data based on the pokemonRecord and create new Pokemon__c records with the extracted data. Ensure that you properly populate the pokemonList with the newly created records before inserting them.
Hope this helps !
Thank you.
public class PopulatePokemonBatch implements Database.Batchable<String>, Database.AllowsCallouts {
public Iterable<String> start(Database.BatchableContext bc)
{
List<String> pokeList = new List<String>();
//Make API call
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint('https://pokeapi.co/api/v2/pokemon?limit=905');
request.setMethod('GET');
HttpResponse response = http.send(request);
// Check if Connection was successful
if (response.getStatusCode() == 200)
{
//deserialize response
Map<String,Object> responseData = (Map<String,Object>) JSON.deserializeUntyped(response.getBody());
List<Object> results = (List<Object>) responseData.get('results');
//get url of pokemon's endpoints
for (Object result : results)
{
Map<String,Object> pokemonData = (Map<String,Object>) result;
String pokeName = (String) pokemonData.get('name');
pokeList.add(pokeName);
}
}
return pokeList;
}
public void execute(Database.BatchableContext bc,List<String> scope)
{
List<Pokemon__c> pokemonList = new List<Pokemon__c>();
for(String record : scope){
String pokeName = record;
HttpRequest detailsRequest = new HttpRequest();
detailsRequest.setEndpoint('https://pokeapi.co/api/v2/pokemon/'+pokeName);
detailsRequest.setMethod('GET');
HttpResponse detailsResponse = new Http().send(detailsRequest);
// Check if Connection to the new endpoint was successful
if (detailsResponse.getStatusCode() == 200)
{
//deserialize response
Map<String,Object> detailData = (Map<String,Object>) JSON.deserializeUntyped(detailsResponse.getBody());
// get fields from detail data
//***** get the id
Integer id = (Integer) detailData.get('id');
//***** Check if the id is greater than the number of pokemons we want to get
//***** we only want the pokemons until the 8th generation
//***** get and convert height and weight to the correct units
Double height = (Double) detailData.get('height')/10;
Double weight = (Double) detailData.get('weight')/10;
//***** get the name
// String name = (String) detailData.get('name');
//***** get and handle multiple types
List<Object> types = (List<Object>) detailData.get('types');
List<String> typeList = new List<String>();
for (Object type : types)
{
Map<String,Object> typeData = (Map<String,Object>) type;
Map<String,Object> typeName = (Map<String,Object>) typeData.get('type');
String nameType = (String) typeName.get('name');
typeList.add(nameType);
}
//***** get species url to adquire the generation
Map<String,Object> species = (Map<String,Object>) detailData.get('species');
String speciesUrl = (String) species.get('url');
// make a call to the species endpoint
HttpRequest speciesRequest = new HttpRequest();
speciesRequest.setEndpoint(speciesUrl);
speciesRequest.setMethod('GET');
HttpResponse speciesResponse = new Http().send(speciesRequest);
// Check if Connection to the new endpoint was successful
if (speciesResponse.getStatusCode() == 200)
{
//deserialize response
Map<String,Object> speciesDetails = (Map<String,Object>) JSON.deserializeUntyped(speciesResponse.getBody());
//***** get the generation url and extract the the generation number from the end
Map<String,Object> generationDetails = (Map<String,Object>) speciesDetails.get('generation');
String generationUrl = (String) generationDetails.get('url');
String generation = generationUrl.substring(generationUrl.length() - 2, generationUrl.length() -1);
//***** get the sprites
Map<String,Object> sprites = (Map<String,Object>) detailData.get('sprites');
String spriteUrl = (String) sprites.get('front_default');
//***** create a new pokemon object and insert the data extratted fom the API
Pokemon__c pokemon = new Pokemon__c(Name=pokeName.capitalize(),
PokeIndex__c=id,
Peso__c = String.valueOf(weight + ' kg'),
Altura__c = String.valueOf(height + ' mts'),
Tipo__c = String.join(typeList, ';'),
Geracao__c = Integer.valueOf(generation),
Foto_URL__c = spriteUrl
);
pokemonList.add(pokemon);
}
}
}
if(!pokemonList.isEmpty()){
insert pokemonList;
}
}
public void finish(Database.BatchableContext bc)
{
system.debug('batch finished');
}
}