[HN Gopher] Laravel Transporter
___________________________________________________________________
Laravel Transporter
Author : mooreds
Score : 35 points
Date : 2021-06-24 13:39 UTC (9 hours ago)
(HTM) web link (www.juststeveking.uk)
(TXT) w3m dump (www.juststeveking.uk)
| zerof1l wrote:
| I don't see value in using this wrapper library over Laravel's
| HTTP Client or Guzzle. What Laravel includes is more than
| adequate already. Also, I never hardcode URLs and tokens. There's
| a config in Laravel for that. Nobody is going to call Guzzle or
| HTTP directly every time anyway. It will be a Service or a Client
| class that exposes each endpoint as a method and abstracts all
| underlying logic.
|
| What's more important when doing API implementation seriously is
| defining and enforcing API contract and getting an exception as
| soon as the contract is broken. I'm thinking about something
| similar to BaseModel from pydantic in Python. This library
| provides nothing of this kind.
| preya2k wrote:
| Please fix the contrast ratio of quotes and inline code segments
| in dark mode on this website. It's black text on dark blue
| background, which is barely readable.
| cortexio wrote:
| Hmm, baseurl shouldnt be a setting foreach request. And i think
| ctrl+c / ctrl+v is probably as fast as using a generator.
| grzes wrote:
| totally agree with other commenters - guy just over-engineered
| non-existent problem
| spheroidmethod wrote:
| I do appreciate the structural parity that this has with
| Laravel's Eloquent ORM models--that is, a class to represent a
| specific database resource. It makes API requests feel like a
| close analogue to that Laravel-esque functionality.
|
| That said, REST API endpoint are effectively just functions--you
| pass in params, you get a response. They only have a single
| operation possible on them, unlike ORM models which can do many
| things.
|
| Whenever I've implemented a custom API client in PHP, boring old
| OOP seems to solve the problems stated in the article reasonably
| well: class ApiConsumer { function
| __construct($baseUrl, $credentials); function
| operationFoo($paramOne, $paramTwo): FooResponse; function
| operationBar($paramOne, $paramTwo): BarResponse; }
| chipotle_coyote wrote:
| I'll half-agree and half-disagree with other comments, I think.
|
| First, I think this _is_ a clever way to wrap API requests in
| what strikes me as the modern PHP style, which these days seem to
| largely driven by the de facto standards of PHP-FIG in general
| and Laravel and Symfony in particular. Use a CLI tool to generate
| a class that extends your base class and adds configuration,
| extend _that_ class to build new more granular methods, maybe
| make a static facade to call everything. This is just super
| Laravel-ish and absolutely what I expect from modern PHP apps in
| 2021.
|
| Second, it _is_ overengineered, because _that is what modern PHP
| apps do._ Spend a bit of time tracing just how much goes into
| encapsulating a PSR-7-compliant request, and think about how
| often code that 's using those requests literally doesn't need
| anything more than the $REQUEST superglobal. (Gasp! They said
| "global!" Think of the children!) It's great to have standards
| for packages, but it seems like I'm spending way, way more time
| -- and occasionally writing more actual code -- figuring out how
| to do things The Right Way (tm).
|
| In the argument for Laravel Transporter, Mr. McDougall shows a
| bit of pretty clear code and then says, "But, this is very
| procedural." I mean, yes? It's kind of a procedure? "What happens
| if the URL changes? What happens if the query parameters change?"
| If I was insistent on wrapping this up in a class, I'd probably
| just _write an API class_ that you call with something like
| $api = new FooApi(); $todo = $api->getCompletedTodos();
| // or if I am feeling all static $todo =
| Api::getCompletedTodos();
|
| and if the URL changes or the query parameters change, I still
| basically only have one place to change it.
|
| I'm not saying I pine for the days of 100% Procedural All Pasta
| All The Time. I'm just wondering whether maybe PHP developers
| should spend some more time with languages that not only aren't
| PHP, but aren't Java, then come back to PHP -- and start
| questioning the orthodoxy a little.
| dgb23 wrote:
| On the other hand PHP has this wonderful feature in associative
| arrays. Easily serializable, fast, deep equality, plain and
| simple, generic and flexible data structures that seamlessly
| convert to JSON (and thus schema) and have well supported
| language constructs.
| Liquidor wrote:
| Isn't this package just a different solution for a Repository
| Pattern?
|
| Create a repository class which contains all the objects and
| methods for the API and then use this repository as a bridge
| between the API and your controllers.
|
| Business and data access logic can be tested separately and it's
| easier to maintain.
| mtnGoat wrote:
| I deal mostly in PHP and never thought that making API requests
| was hard. Am I lost?
|
| The hard part is dealing with the fact that APIs are not
| standardized, even within the same company.
| deweller wrote:
| It is not difficult but it can end up being more hard-coded
| than it should be.
|
| The author of this package is attempting to help Laravel users
| standardize their API client code and centralize those hard-
| coded bits in one place.
|
| It isn't groundbreaking, but it could be useful in larger
| projects or across several projects.
| 9dev wrote:
| My feeling is the opposite- this is just overengineering,
| adding more code to test and maintain. The simple solution is
| what countless others have suggested - build a simple client,
| configure it using standard Laravel mechanisms and dependency
| injection. An API Call is just a method on the service class.
| debarshri wrote:
| A bit more standard way of generating HTTP API clients, would be
| to use openapi spec [1] and then generate php client. It makes
| you app client independent of framework and also language itself.
|
| [1] https://github.com/OpenAPITools/openapi-generator
| mradmin wrote:
| This is the approach I use, but I've always found some sort of
| issue in every generator I use. A valid openapi spec does not
| imply a generator will be able to handle it. You'd think have a
| specification would mean the generators are "bug free" but it's
| not the case, and bug reports are lost in a sea of issues:
| https://github.com/OpenAPITools/openapi-generator/issues so i
| don't see things improving anytime soon.
|
| I've also wondered if the "logic-less" template approach is the
| right approach for these generators. You can't fix bugs or add
| workarounds just by providing a custom template, you need to
| change the underlying Java code to provide the correct data
| models to the logic-less templates.
| rob74 wrote:
| I find the naming of "Laravel Forge" a bit unfortunate. When I
| read code like "use App\Transporter\Forge\ForgeRequest", one of
| two things come to mind:
|
| - "what's a Forge? Is this a fancy name for the Factory pattern?"
|
| - "are they forging (as in forgery) requests here? Or further on,
| 'services.forge.token' - sounds strange?!"
| jpswade wrote:
| This feels like over-engineering a problem at it's finest. Taking
| 3 lines of ubiquitous code and abstracting in a new way, when it
| already does what you need out of the box.
|
| The base url and header details such as api token can all be set
| in the client in an OOP way already[1]
|
| > What happens if the URL changes?
|
| Cool urls don't change. Use configs.
|
| [1] https://docs.guzzlephp.org/en/stable/quickstart.html
| hospadar wrote:
| >> What happens if the URL changes?
|
| > Cool urls don't change. Use configs.
|
| I also kinda think that for many webapps, the risk of this is
| somewhat overstated. I've got tons of apps with a few hard-
| coded URL paths that point at other internal apps that I own.
| They don't break because I don't randomly remove URL paths from
| services. When I do need to change something, find-and-replace
| + an integration test keep me safe 99.99% of the time (and the
| blast radius from a failure like this is usually very small -
| obvious 404 error bubbles up immediately the first time someone
| hits something broken).
|
| That said, I agree that keeping constants like URL paths in
| configs is a fine idea. I also feel that common sense is
| required - a tiny webservice which makes a single request to
| one URL path probably is fine to just hard-code it (and in fact
| putting all constants into config might be overly obfuscating),
| but a big app which makes dozens or hundreds of calls obviously
| benefits from a config-oriented approach
| theli0nheart wrote:
| Exactly what I came here to say.
|
| You don't sprinkle URLs throughout your codebase, as the OP
| apparently assumes one would normally do. You create a single
| class (or something similar) which abstracts the API calls. If
| the endpoint changes, you change it in one place.
|
| I honestly don't see how this solution makes this easier. If
| anything, I feel like it makes things more complicated and
| harder to understand.
| dhbanes wrote:
| The endpoint URL should probably be stored in the
| environmental variable file.
| theli0nheart wrote:
| > _The endpoint URL should probably be stored in the
| environmental variable file._
|
| As I mentioned, _if the endpoint changes, you change it in
| one place._ Storing your endpoint URLs in an env file is
| your personal preference, but that 's all. _Should_ has no
| place here.
|
| It doesn't matter whether it's an environmental variable
| file, a YAML configuration, a JSON file, or a secure remote
| KV-store. Barring low water marks, it doesn't really matter
| where you store your configuration--just make sure to store
| it in one place.
| that_guy_iain wrote:
| To be fair it does seem to fit the way I think Laravel
| applications are built.
| CptKriechstrom wrote:
| Seems like a Solution in search for a Problem. Instead of
| hardcoding the URL to the Request it can be set in the config
| like it was done with jsonplaceholder.api.token.
|
| And creating a Request for every API-Endpoint instead of a single
| API-Client Class seems overkill.
| apocalyptic0n3 wrote:
| I think it makes sense if you're doing the same 5 requests over
| and over throughout your application. As it stands, I generally
| build a service class for these scenarios:
| class GoogleMapsApiService { public function
| geocodeAddress(string $address); public function
| getDirections(string $address); }
|
| That sort of thing. It's all reusable and I can just call
| `app(GoogleMapsApiService::class)->getDirections('123 Main
| St')` to request the data. This just goes a step further and
| makes it more flexible (and probably more testable) by turning
| it into a class. Creating the class is a simple command line
| run (if you're familiar with Laravel, much of your application
| is scaffolded this way).
|
| I think it loses its effectiveness/value if you're using it for
| 20 different requests that are only used once each, but for a
| scenario where you're making 1 request in 10 different places
| like you might be with geocoding, it's not a bad implementation
| in my opinion.
___________________________________________________________________
(page generated 2021-06-24 23:02 UTC)