This question might be considered opinionated but I really can't seem to find a straight answer. So either I'm missing something or I'm asking the wrong questions. So, I'm an undergrad student and new in the whole Spring app development and I'm currently creating an app with React acting as the frontend and building a RESTful API using Spring in order to support it with necessary operations for the backend. Among other services, the backend API I'm building is used as a middle-man forwarding calls to the Google Geocoding API and other 3rd party APIs. **My biggest question since I started this is, is this a valid strategy? ** (at least, something acceptable by industry professionals)
My Research
- The biggest pro that this method has is that it allows me to effectively hide my API keys from the client rendering any attacks impossible.
- At the same time, this whole process adds (I believe) unnecessary complexity and delay in the overall responses resulting in a possible hindered user experience.
- Something I'm not quite sure yet would be that I'll have to add
asynccapabilities to the services exposed by my own API in order to facilitate multiple users. (This last part might be entirely wrong but I haven't been able to understand how multiple users are handled when querying the same endpoint concurrently.) - I have used Apache JMeter to test the performance of the app on concurrent POST calls and it seems to be able to handle them on around 170ms. (I'll post screenshots of the results below.)
Code
I'll try to include code demonstrating the controller that's responsible for the calls to the Geocoding API.
@RestController
@RequestMapping("/api")
@Slf4j
@RequiredArgsConstructor
@Component
public class GeocodingController {
private final OkHttpClient httpClient = new OkHttpClient();
@PostMapping(value = "/reversegeocoding")
public String getReverseGeocode(@RequestBody LatLng latlng) throws IOException, ExecutionException, InterruptedException {
String encodedLatLng = latlng.toString();
Request request = new Request.Builder()
.url("https://maps.googleapis.com/maps/api/geocode/json?" +
"language=en&result_type=street_address&latlng=" + encodedLatLng +
"&key=MY_API_KEY")
.build();
CallbackFuture future = new CallbackFuture();
httpClient.newCall(request).enqueue(future);
Response response = future.get();
return response.body().string();
}
}
The getReverseGeocode() method takes in as an argument the following object:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LatLng {
double lat;
double lng;
public String toString() {
return lat + "," + lng;
}
}
So, the Request Body is mapped onto the above object once the request arrives.
Finally the CallbackFuture is just an adapter class based on this answer.
public class CallbackFuture extends CompletableFuture<Response> implements Callback {
@Override
public void onFailure(Call call, IOException e) {
super.completeExceptionally(e);
}
@Override
public void onResponse(Call call, Response response) {
super.complete(response);
}
}


