Skip to content

Commit

Permalink
Merge pull request #13 from nspalo/feature/BWA-5-weather-app-api-serv…
Browse files Browse the repository at this point in the history
…ice-refactor

feature/BWA-5-weather-app-api-service-refactor
  • Loading branch information
nspalo authored Sep 8, 2023
2 parents ac17ac0 + 7797013 commit d99af59
Show file tree
Hide file tree
Showing 13 changed files with 282 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,19 @@ public function __invoke(Request $request): JsonResource
$responseGeolocation = $this->geoapifyGeocodingService->getGeolocation($location);

$responseCurrentWeather = $this->weatherApiServiceFactory->make(WeatherTypeEnum::Current)
->getWeatherData($responseGeolocation['lon'], $responseGeolocation['lat']);
->getWeatherData($responseGeolocation);

$responseForecastWeather = $this->weatherApiServiceFactory->make(WeatherTypeEnum::Forecast)
->getWeatherData($responseGeolocation['lon'], $responseGeolocation['lat']);
->getWeatherData($responseGeolocation);

return new JsonResource([
$data = [
'geolocation' => $responseGeolocation,
'weather' => [
'geolocation' => $responseGeolocation,
'current' => $responseCurrentWeather->json(),
'forecast' => $responseForecastWeather->json(),
],
]);
'current' => $responseCurrentWeather->getResponse(),
'forecast' => $responseForecastWeather->getResponse(),
]
];

return new JsonResource($data);
}
}
37 changes: 35 additions & 2 deletions src/app/Http/Controllers/WeatherApp/WeatherUpdateController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,46 @@

namespace App\Http\Controllers\WeatherApp;

use App\Enums\WeatherTypeEnum;
use App\Http\Controllers\Controller;
use App\Services\GeoapifyApi\Interfaces\GeoapifyApiServiceInterface;
use App\Services\OpenWeatherApi\Interfaces\OpenWeatherApiServiceFactoryInterface;
use Illuminate\Http\Request;
use Illuminate\View\View;

class WeatherUpdateController extends Controller
{
public function index(): View
protected GeoapifyApiServiceInterface $geoapifyGeocodingService;
protected OpenWeatherApiServiceFactoryInterface $weatherApiServiceFactory;

public function __construct(
GeoapifyApiServiceInterface $geoapifyGeocodingService,
OpenWeatherApiServiceFactoryInterface $weatherApiServiceFactory
) {
$this->geoapifyGeocodingService = $geoapifyGeocodingService;
$this->weatherApiServiceFactory = $weatherApiServiceFactory;
}

public function index(Request $request): View
{
return view('weather-app/weather-update');
$location = $request->get('location') ?? \config('services.api.geoapify.default_search');

$responseGeolocation = $this->geoapifyGeocodingService->getGeolocation($location);

$responseCurrentWeather = $this->weatherApiServiceFactory->make(WeatherTypeEnum::Current)
->getWeatherData($responseGeolocation);

$responseForecastWeather = $this->weatherApiServiceFactory->make(WeatherTypeEnum::Forecast)
->getWeatherData($responseGeolocation);

$data = [
'geolocation' => $responseGeolocation,
'weather' => [
'current' => $responseCurrentWeather->getResponse(),
'forecast' => $responseForecastWeather->getResponse(),
]
];

return view('weather-app/weather-update', $data);
}
}
27 changes: 27 additions & 0 deletions src/app/Http/Resources/Resource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

declare(strict_types=1);

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

abstract class Resource extends JsonResource
{
/**
* Return this resource as an array
*
* @noinspection PhpMissingParentCallCommonInspection
*
* @param Request $request
*
* @return string[]
*/
public function toArray($request): array
{
return $this->getResponse();
}

abstract public function getResponse(): array;
}
12 changes: 3 additions & 9 deletions src/app/Services/GeoapifyApi/GeocodingService.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use App\Services\ConfigurationMapper\Interfaces\ServiceConfigurationMapperInterface;
use App\Services\GeoapifyApi\Interfaces\GeoapifyApiServiceInterface;
use App\Services\GeoapifyApi\Resources\GeolocationResource;
use App\Services\UrlQueryStringBuilder\Interfaces\UrlQueryStringBuilderServiceInterface;
use Illuminate\Support\Facades\Http;

Expand Down Expand Up @@ -42,20 +43,13 @@ private function buildGeoapifyApiUrl(string $location): string
return 'https://' . $serviceApiUri . '?' . $queryString;
}

public function getGeolocation(string $location): array
public function getGeolocation(string $location): GeolocationResource
{
$geolocationUrl = $this->buildGeoapifyApiUrl($location);

$responseGeolocation = Http::get($geolocationUrl);
$data = $responseGeolocation->json('results');

return [
'city' => $data[0]['city'],
'country' => $data[0]['country'],
'country_code' => $data[0]['country_code'],
'formatted' => $data[0]['formatted'],
'lon' => $data[0]['lon'],
'lat' => $data[0]['lat'],
];
return new GeolocationResource($data);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

namespace App\Services\GeoapifyApi\Interfaces;

use App\Services\GeoapifyApi\Resources\GeolocationResource;

interface GeoapifyApiServiceInterface
{
public function getGeolocation(string $location): array;
public function getGeolocation(string $location): GeolocationResource;
}
31 changes: 31 additions & 0 deletions src/app/Services/GeoapifyApi/Resources/GeolocationResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace App\Services\GeoapifyApi\Resources;

use App\Http\Resources\Resource;

class GeolocationResource extends Resource
{
public function __construct($resource)
{
$resource = $resource[0];

parent::__construct($resource);
}

public function getResponse(): array
{
return [
'city' => $this->resource['city'],
'country' => $this->resource['country'],
'country_code' => $this->resource['country_code'],
'formatted' => $this->resource['formatted'],
'coordinate' => [
'lon' => $this->resource['lon'],
'lat' => $this->resource['lat'],
],
];
}
}
66 changes: 66 additions & 0 deletions src/app/Services/OpenWeatherApi/AbstractOpenWeatherApiService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

declare(strict_types=1);

namespace App\Services\OpenWeatherApi;

use App\Enums\WeatherTypeEnum;
use App\Http\Resources\Resource;
use App\Services\ConfigurationMapper\Interfaces\ServiceConfigurationMapperInterface;
use App\Services\GeoapifyApi\Resources\GeolocationResource;
use App\Services\OpenWeatherApi\Interfaces\WeatherResourceInterface;
use App\Services\UrlQueryStringBuilder\Interfaces\UrlQueryStringBuilderServiceInterface;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;

abstract class AbstractOpenWeatherApiService
{
private ServiceConfigurationMapperInterface $serviceConfigurationMapper;

private UrlQueryStringBuilderServiceInterface $urlQueryStringBuilderService;

public function __construct(
ServiceConfigurationMapperInterface $serviceConfigurationMapper,
UrlQueryStringBuilderServiceInterface $urlQueryStringBuilderService
) {
$this->serviceConfigurationMapper = $serviceConfigurationMapper;
$this->urlQueryStringBuilderService = $urlQueryStringBuilderService;

$this->serviceConfigurationMapper->loadConfig('services.api.open_weather');
}

protected function buildOpenWeatherApiQueryString(GeolocationResource $geolocation, WeatherTypeEnum $weatherApiServiceType): string
{
$mapping = [
'units' => 'unit',
'lang' => 'lang',
'appid' => 'key',
];

if ($weatherApiServiceType === WeatherTypeEnum::Forecast) {
$mapping['cnt'] = 'max_output';
}

$queryParam = $this->serviceConfigurationMapper->map($mapping);
$queryParam = array_merge(
$queryParam, [
'lon' => $geolocation['lon'],
'lat' => $geolocation['lat'],
]
);

return $this->urlQueryStringBuilderService->build($queryParam);
}

protected function sendRequest(GeolocationResource $geolocation, WeatherTypeEnum $apiServiceType): Response
{
$apiServiceUri = $this->serviceConfigurationMapper->getByKey('uri');
$apiServiceQueryParam = $this->buildOpenWeatherApiQueryString($geolocation, $apiServiceType);

$openWeatherApiServiceUrl = 'https://' . $apiServiceUri . '/' . $apiServiceType->value . '?' . $apiServiceQueryParam;

return Http::get($openWeatherApiServiceUrl);
}

abstract public function getWeatherData(GeolocationResource $geolocation): WeatherResourceInterface;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
namespace App\Services\OpenWeatherApi\Interfaces;

use App\Enums\WeatherTypeEnum;
use Illuminate\Http\Client\Response;
use App\Services\GeoapifyApi\Resources\GeolocationResource;

interface OpenWeatherApiServiceInterface
{
public function supports(WeatherTypeEnum $weatherApiType): bool;
public function getWeatherData(float $lon, float $lat): Response;
public function getWeatherData(GeolocationResource $geolocation): WeatherResourceInterface;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace App\Services\OpenWeatherApi\Interfaces;

interface WeatherResourceInterface
{
}
46 changes: 46 additions & 0 deletions src/app/Services/OpenWeatherApi/Resources/WeatherResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

declare(strict_types=1);

namespace App\Services\OpenWeatherApi\Resources;

use App\Http\Resources\Resource;
use App\Services\OpenWeatherApi\Interfaces\WeatherResourceInterface;

class WeatherResource extends Resource implements WeatherResourceInterface
{
public function getResponse(): array
{
return [
// Location Info
'country_code' => $this->resource['sys']['country'],
'country_city' => $this->resource['name'],
'timestamp' => $this->resource['dt'],
'timezone' => $this->resource['timezone'],
'coordinate' => [
'lon' => $this->resource['coord']['lon'],
'lat' => $this->resource['coord']['lat'],
],

// Current Weather Data
'type' => $this->resource['weather'][0]['main'], // (Rain, Snow, Clouds etc.)
'description' => $this->resource['weather'][0]['description'],
'icon' => $this->resource['weather'][0]['icon'],

// Main
'temp' => $this->resource['main']['temp'],
'temp_min' => $this->resource['main']['temp_min'],
'temp_max' => $this->resource['main']['temp_max'],
'feels_like' => $this->resource['main']['feels_like'],
'humidity' => $this->resource['main']['humidity'],

// Wind
'wind_speed' => $this->resource['wind']['speed'],
'wind_direction' => $this->resource['wind']['deg'],

// sys
'sunrise' => $this->resource['sys']['sunrise'],
'sunset' => $this->resource['sys']['sunset'],
];
}
}
36 changes: 36 additions & 0 deletions src/app/Services/OpenWeatherApi/Resources/WeatherResources.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace App\Services\OpenWeatherApi\Resources;

use App\Http\Resources\Resource;
use App\Services\OpenWeatherApi\Interfaces\WeatherResourceInterface;

class WeatherResources extends Resource implements WeatherResourceInterface
{
public function getResponse(): array
{
$weatherForecast = $this->resource['list'];

$forecast = [];
foreach ($weatherForecast as $weather) {
$forecast[] = new WeatherResource([
'coord' => $this->resource['city']['coord'],
'weather' => $weather['weather'],
'main' => $weather['main'],
'wind' => $weather['wind'],
'dt' => $weather['dt'],
'sys' => [
'country' => $this->resource['city']['country'],
'sunrise' => $this->resource['city']['sunrise'],
'sunset' => $this->resource['city']['sunset'],
],
'timezone' => $this->resource['city']['timezone'],
'name' => $this->resource['city']['name'],
]);
}

return $forecast;
}
}
Loading

0 comments on commit d99af59

Please sign in to comment.