Transporter is a futuristic way to send API requests in PHP

Overview

Transporter

Latest Version on Packagist GitHub Tests Action Status Total Downloads

Transporter is a futuristic way to send API requests in PHP. This is an OOP approach to handle API requests.

This package is still a work in progress

Installation

You can install the package via composer:

composer require juststeveking/laravel-transporter

Generating Request

To generate an API request to use with Transporter, you can use the Artisan make command:

php artisan make:api-request NameOfYourRequest

This will by default publish as: app/Transporter/Requests/NameOfYourRequest.php

Usage

Transporter Requests are an extention of Laravels PendingRequest so all of the methods available on a Pending Request is available to you on your requests.

Also when you send the request, you will receive a Illuminate\Http\Client\Response back, allowing you to do things such as collect($key) and json() and failed() very easily. We are simply just shifting how we send it into a class based approach.

TestRequest::build()
    ->withToken('foobar')
    ->withData([
        'title' => 'Build a package'
    ])
    ->send()
    ->json();

When building your request to send, you can override the following:

  • Request Data using withData(array $data)
  • Request Query Params using withQuery(array $query)
  • Request Path using setPath(string $path)

Testing

To run the tests in parallel:

composer run test

To run the tests with a coverage report:

composer run test-coverage

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.

Comments
  • Move destination overrides in a `to()` method

    Move destination overrides in a `to()` method

    In the current API I have to override the path with the same method I also adjust the payload. This feels wrong as changing the path is first something super rare as it's against the principle of that package. And You don't do the request with a path but to a path. So an API like to(path: '/foo/bar') feels better. This could also allow adjusting the fragment and other URI segments.

    opened by Gummibeer 15
  • Authentication strategies

    Authentication strategies

    When I am building a request with transporter, and it needs authentication, I typically add a method onto my Request that looks like:

    public function authenticate(): static
    {
        $this->request->withToken(config('services.service-name.token'));
    
      return $this;
    }
    

    Which allows me to use it on requests as required:

    MyRequest::build()->authenticate()->send();
    

    It works, and works well. But I can't help feel something is missing here. If we are really going for an OOP approach to API requests, surely there is something I could do here? My initial thoughts, that I would like some feedback on are:

    class MyRequest extends Request
    {
      protected AuthStrategy $authStrategy;
    
      public function send(): Response
      {
        $this->authStrategy->apply($this->request);
        
        /** Rest of method */
      }
    }
    

    Allowing us to create our own AuthStrategies as required:

    interface AuthStrategy
    {
      public function apply(PendingRequest $request): void;
    }
    

    Which allows:

    class ApiTokenStrategy implements AuthStrategy
    {
      public function __construct(
        protected string $token,
      ) {}
    
      public function apply(PendingRequest $request): void
      {
        $request->withToken($this->token);
      }
    }
    

    The last step is something I need to figure out, how to get it to be added nicely, I had thought perhaps a Trait - but I am not sure. I am open to suggestions from others here.

    enhancement ideas 
    opened by JustSteveKing 12
  • Prevent multiple `withQuery()` calls from overwriting data...

    Prevent multiple `withQuery()` calls from overwriting data...

    When calling withQuery(), it's possible to overwrite previous entries inadvertently.

    Consider implementing a request that allows for JSON:API pagination using a page-based strategy. Perhaps you have the following methods:

        public function pageNumber(int $pageNumber)
        {
            $this->withQuery(['page' => ['number' => $pageNumber]]);
    
            return $this;
        }
    
        public function pageSize(int $pageSize)
        {
            $this->withQuery(['page' => ['size' => $pageSize]]);
    
            return $this;
        }
    

    If withQuery() uses array_merge(), then the page key is always overwritten. So, if a user specifies the page number and then the page size, then $this->query will have the following value: ['page' => ['size' => ???]].

    I believe changing array_merge() to array_merge_recursive() will resolve this.

    I'm not 100% sure, but there may be reason to look into this with some of the other array-merging functionality.

    Please let me know if you have any questions or concerns. 🤓

    hacktoberfest-accepted 
    opened by telkins 7
  • View the payload?

    View the payload?

    I'm currently debugging an issue and would like to see what exactly is being send to the third party API.

    So is there any way to view the full raw output of what is being send?

    enhancement question ideas 
    opened by mitchellholzmann 4
  • Change default namespace to `App\Transporter`

    Change default namespace to `App\Transporter`

    Right now the default namespace is App\Http\API\Requests which at first looks cool but the classes inside are totally unrelated to my apps HTTP responsibilities. These are classes describing a third-party API request, which will use HTTP as transport layer but in my app the responsibility is Guzzle/curl. These classes are in no way related to my app controllers, requests, resources, middleware or the apps HTTP kernel. Mixing them will only lead to trouble, misconceptions and a lot of brain hacking if you talk about app HTTP requests.

    An alternative would be App\Transporter - it won't conflict with other packages (package name as namespace) and makes it clear that the classes inside are something totally custom.

    opened by Gummibeer 4
  • Sending XML

    Sending XML

    Hey @JustSteveKing!

    Love this package :)

    This isn't really an issue, but I have an API where I need to send XML for some requests and was hoping to use this package, so I created this trait that I thought might be worth sharing:

    <?php
    
    namespace App\Transporter;
    
    use Illuminate\Http\Client\Response;
    
    trait SendsXml
    {
        public function withXml(string $xml): static
        {
            $this->request
                ->withHeaders(['Accept' => 'application/xml'])
                ->withBody($xml, 'application/xml');
    
            return $this;
        }
    
        public function send(): Response
        {
            return $this->request->send(
                $this->method,
                $this->getUrl()
            );
        }
    }
    

    I don't think it quite handles all of the use cases Transporter is designed for, but for my case it worked a treat.

    The usage in the request then looks something like this:

    <?php
    
    declare(strict_types=1);
    
    namespace App\Transporter\Requests;
    
    use App\Transporter\SendsXml;
    use JustSteveKing\Transporter\Request;
    
    class MyXmlRequest extends Request
    {
        use SendsXml;
    
        protected string $method = 'POST';
    
        protected string $path = '/my-endpoint';
    }
    

    And then using the request looks something like this:

    MyXmlRequest::build()->withXml($xml)->send();
    

    Feel free to do whatever you like with it and to close this issue whenever you like.

    enhancement ideas 
    opened by jessarcher 3
  • Get path without accessed-before-initialization errors

    Get path without accessed-before-initialization errors

    If descendants don't specify $this->path, then calling path() will fail with an error: Typed property JustSteveKing\Transporter\Request::$path must not be accessed before initialization

    This is one way to resolve the problem. Another option is to initialize the variable when it's declared:

        protected string $path = '';
    

    Not sure which way is best/preferable...or if there's some other even better way to go. 🤓

    opened by telkins 3
  • Internal Server Errors with API

    Internal Server Errors with API

    Hey Steve,

    When utilising transporter within an API, I receive a server error, but when called manually it works without any issues.

    CraftheadRequest

    abstract class CraftheadRequest extends Request
    {
        protected string $method = 'GET';
        protected string $baseUrl = 'https://crafthead.net/';
    }
    

    Then, my main request that extends..

    class NameToUUIDRequest extends CraftheadRequest
    {
        public function username(string $username)
        {
            $this->setPath("profile/{$username}");
    
            return $this;
        }
    }
    

    And use it, like so..

            $response = NameToUUIDRequest::build()->username($username)->send();
    
            if ($response->failed()) {
                return null;
            }
    
            return $response->json('id');
    

    Any reason for this? I considered it may be the user agent, but tried it and same thing, and even manually tried API without agent and worked.

    opened by heychazza 3
  • withToken() method does not exist despite mentioned many times in Readme.md

    withToken() method does not exist despite mentioned many times in Readme.md

    Tried to call this method as the readme says, but it is not found (withToken())

    MyRequest::build()->withToken($token)->send()

    Im dealing with an API where i need a new token every transaction, so I need to call the authenticate api first, get the token then call the transaction API each time

    opened by ziming 2
  • Add concurrency feature.

    Add concurrency feature.

    Issue Reference

    #11

    PR Documentation

    • Added feature to run concurrent request.
    • Code refactor.
    • Updated README.md with concurrency example.

    How to test

    Run test cases.

    P.S. : it would be cool if you add hacktoberfest to the repo's topics.

    opened by AbdullahFaqeir 2
  • Prefer local baseUrl over global config setting...

    Prefer local baseUrl over global config setting...

    I believe that the local baseUrl setting, if set, should be preferred over any global value that might be set via configuration file.

    Before this change, if someone wants to use the config setting and some one-off local settings, then for each of the one-off instance, setBaseUrl() will have to be called explicitly.

    After this change, someone can set the config setting and know that it will be used everywhere except for those one-off instances where it is set locally. There is no longer any need to call setBaseUrl() explicitly.

    Please let me know if you have any questions/concerns.

    opened by telkins 2
  • feat: add basic cache support

    feat: add basic cache support

    This PR adds basic support for remembering request responses. I often need to implement it myself when dealing with 3rd party APIs, and I thought it would be nice to have this built in.

    SomeRequest::build()->remember(now()->addMinute());
    

    This could be further improved by adding configurable properties to the Request class, but I wanted to keep it simple, at least for now. I also wanted to inject the cache manager to Request, but I think this could be a breaking change, so I opted for using service locator via the cache() helper instead.

    opened by innocenzi 0
  • feat: add `$throws` to requests

    feat: add `$throws` to requests

    This PR adds a convenient $throws property to JustSteveKing\Transporter\Request to avoid having to call ->throw after each ->send call.

    Currently, I have the following in all my base Request classes:

    public function send(): Response
    {
        return parent::send()->throw();
    }
    

    After this PR, I may simply override the $throws property and set it to true.

    I also updated the development dependencies, otherwise I couldn't use Http::fake in the tests.

    opened by innocenzi 0
  • Suggestions for Improvements

    Suggestions for Improvements

    Hello, @JustSteveKing thank you for this great package once again and also for the quick fixes from yesterday. I was thinking about some ways you could improve the package. Below is an example:

    I'm working on an app that consumes solely on an API developed in Laravel, now for crud operations like Post management, I would have to create a Transport Request class for all the crud operations which is how the current package works (I stand to be corrected). I would have wished to just create one class e.g UpsertPosts or PostTransporter which will take care of all the crud operations instead of creating different classes for Create, Read, Update and Delete.

    In the end, I would love to be able to do something like this:

    <?php
    
    namespace App\Http\Controllers;
    
    $post = PostTransporter::build()
    ->method('Post') or ->post (making it possible to overwrite the method via this constructor
    ->send();
    

    Also instead of adding ->withData(['title' => $request->title]), I would like to be able to pass the data instead inside the PostTransporter class to keep things clean maybe via the constructor like so:

    <?php
    
    declare(strict_types=1);
    
    namespace App\Transporter\Requests\Sour\Posts;
    
    use JustSteveKing\Transporter\Request;
    use App\Http\Requests\UpsertPostRequest;
    
    class Post extends Request
    {
        protected string $method = 'GET';
        protected string $path = '/v1/post/{id}';
    
    
        public function __construct(UpsertPostRequest $request) {
            'title' => $request->id,
            'description' => $request->description,
            'release_date' => $request->release_date,
        }
    
        public function rules(): array
        {
            return [
                'title' => 'required',
                'description' => 'required',
                'release_date' => 'required',
                'rating' => 'required',
                'ticket_price' => 'required',
                'country' => 'required',
                'genre' => 'required',
                'photo' => 'required',
            ];
        }
    }
    

    NB: So one can define the validation rule via the function above or just import their validation request as I did in the construct

    I hope I was able to explain myself well. This would have been super amazing to have. Once again thanks for all the hard work.

    enhancement 
    opened by VimKanzoGH 2
  • SendsXml for Concurrently

    SendsXml for Concurrently

    How can I implement SendsXml using Concurrently?

    class AdequateShopRequest extends Request
    {
        use SendsXml;
        protected string $method = 'POST';
        protected string $baseUrl = 'https://webservice.com';
        protected array $data = [];
    }
    
    
    $responses = Concurrently::build()->setRequests([
            AdequateShopRequest::build()->setPath('/something')->withXml($xml_body),
    ])->run();
    

    Error: Typed property JustSteveKing\Transporter\Request::$request must not be accessed before initialization ../vendor/juststeveking/laravel-transporter/src/Concerns/SendsXml.php:17

    Or if there is a way to set the contentType as property and just pass the body, something like this:

    class AdequateShopRequest extends Request
    {
        protected string $method = 'POST';
        protected string $baseUrl = 'https://webservice.com';
        protected string $contentType = 'application/xml';
    }
    
    $responses = Concurrently::build()->setRequests([
            AdequateShopRequest::build()->setPath('/something')->setBody($xml_body),
    ])->run();
    
    opened by osroflo 1
Releases(1.2.0)
  • 1.2.0(Oct 4, 2022)

    This release add the ability to use appendPath to fluently append an ID or similar to the path of Transporter requests

    What's Changed

    • Adding append path method by @JustSteveKing in https://github.com/JustSteveKing/laravel-transporter/pull/36

    Full Changelog: https://github.com/JustSteveKing/laravel-transporter/compare/1.1.0...1.2.0

    Source code(tar.gz)
    Source code(zip)
  • 1.1.0(Jul 12, 2022)

    What's Changed

    • Fixed setting baseUrl on request when using concurrently with as by @muhsenmaqsudi in https://github.com/JustSteveKing/laravel-transporter/pull/32

    New Contributors

    • @muhsenmaqsudi made their first contribution in https://github.com/JustSteveKing/laravel-transporter/pull/32

    Full Changelog: https://github.com/JustSteveKing/laravel-transporter/compare/1.0.0...1.1.0

    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Feb 11, 2022)

  • 0.9.6(Jan 18, 2022)

    Some fixes have been applied to the pending request so that changes are applied to each member of a pool of requests - thanks to @fred-oranje

    Source code(tar.gz)
    Source code(zip)
  • 0.9.5(Nov 11, 2021)

    Thanks to so good points on issues and a great suggestion by Jess Archer - we can now handle XML requests in a very specific way, and also view the payload before sending for debugging purposes.

    Source code(tar.gz)
    Source code(zip)
  • 0.9.4(Nov 3, 2021)

    Thanks to a PR by @telkins we have switched the baseUri setting so that local (class based) baseUri takes presidence over the global config drive baseUri - a great edition!

    Source code(tar.gz)
    Source code(zip)
  • 0.9.3(Oct 26, 2021)

  • 0.9.2(Oct 21, 2021)

  • 0.9.1(Oct 5, 2021)

  • 0.9.0(Sep 28, 2021)

    This release bringing control to status code on faked requests, allowing you to test how you handle different status codes in a request.

    The usage is:

    TestRequest::fake(
        status: 200,
    )->send();
    

    This release also refactors the test suite to pestPHP

    Source code(tar.gz)
    Source code(zip)
  • 0.8.0(Aug 13, 2021)

    This release includes improvements to the way wqe can fake requests.

    Now every request can be faked by default, instead of enabling a request to be faked. To fake a request, all you need to do is replace the build method call with a call to the fake method instead:

    TestRequest::fake()
        ->withToken('foobar')
        ->withData([
            'title' => 'Build a package'
        ])->withFakeData([
            'data' => 'faked'
        ])->send();
    

    After having used this library on a few projects of my own, and on some packages of my own, I was increasingly frustrated on how the faking a requets worked for testing.

    I hope you find this as useful as I did!

    Source code(tar.gz)
    Source code(zip)
  • 0.7.0(Jul 8, 2021)

    This release brings to option to set a global base url by using the .env in your Laravel project. Simply set TRANSPORTER_BASE_URL= to the value you require it to be, and all transporter requests will use this as their base url.

    Optionally if you integrate with several APIs using transporter, you can now use the built in helper to set or override the base url during the construction of your request:

    YourRequest::build()
      ->setBaseUrl(
        baseUrl: 'https://api.your-domain/com',
      )->send();
    

    These are two options which will allow you to easily set and change the base url on requests where required.

    Source code(tar.gz)
    Source code(zip)
  • 0.6.0(Jun 28, 2021)

    Huge thanks to @listefano for his 2 PRs, one which refactored the internal switch statement to a match statement - and for the other one which adds support for faking requests, and providing a faked response on a request by request basis.

    Docs for this will follow shortly.

    Source code(tar.gz)
    Source code(zip)
  • 0.5.0(Jun 23, 2021)

  • 0.4.0(May 28, 2021)

    This release is a major refactor where a lot of the code has completely disappeared. Instead the Transporter is no longer needed, as we are simply wrapping Laravels PendingRequest in a buildable API - allowing you to still access all of the methods you could do on a PendingRequest such as withToken and asForm. It also returns an Illuminate\Http\Client\Response so you have direct access to json failed collect and other methods available on the Response class.

    Source code(tar.gz)
    Source code(zip)
  • 0.3.0(May 28, 2021)

    This release moves the artisan make command output from app/Http/API/Requests to app/Transporter/Requests as per a request in #1 which makes a lot of sense.

    Source code(tar.gz)
    Source code(zip)
  • 0.2.0(May 27, 2021)

  • 0.1.0(May 27, 2021)

Owner
Steve McDougall
Consultant CTO, Freelance Software Engineer, Community Advocate. Founder at @PHPSouthWales Co-organiser at @BlueConf CTO at @Lila-Fuches
Steve McDougall
A simple PHP project to make API requests on your cPanel installation

A simple PHP project to make API requests on your cPanel installation. This allows you to call modules inside the installation and interact with them to add, show or list data such as domains, e-mail accounts, databases and so on.

Elias Häußler 0 Sep 15, 2022
Facebook Query Builder: A query builder for nested requests in the Facebook Graph API

A query builder that makes it easy to create complex & efficient nested requests to Facebook's Graph API to get lots of specific data back with one request.

Sammy Kaye Powers 92 Dec 18, 2022
CORS (Cross-Origin Resource Sharing) for your Symfony/Laravel requests

CORS for PHP (using the Symfony HttpFoundation) Library and middleware enabling cross-origin resource sharing for your http-{foundation,kernel} using

Fruitcake 91 Dec 22, 2022
Laravel package to easily send events to Google Analytics

Laravel Analytics Event Tracking https://twitter.com/pascalbaljet/status/1257926601339277312 Laravel package to easily send events to Google Analytics

Protone Media 212 Dec 22, 2022
A simple way of authenticating your RESTful APIs with API keys using Laravel

ApiGuard This package is no longer maintained This package is no longer maintained as Laravel already has a similar feature built-in since Laravel 5.8

Chris Bautista 691 Nov 29, 2022
This is an attempt to re-write the official TRA VFD's API in a developer friendly way.

TRA VFD API Documentation This is an attempt to re-write the official TRA VFD's API in a developer friendly way. The current documentation is written

Alpha Olomi 15 Jan 7, 2022
Simple and effective multi-format Web API Server to host your PHP API as Pragmatic REST and / or RESTful API

Luracast Restler ![Gitter](https://badges.gitter.im/Join Chat.svg) Version 3.0 Release Candidate 5 Restler is a simple and effective multi-format Web

Luracast 1.4k Dec 14, 2022
An Unleash bundle for Symfony applications to provide an easy way to use feature flags

Unleash Bundle An Unleash bundle for Symfony applications. This provide an easy way to implement feature flags using Gitlab Feature Flags Feature. Ins

Stogon 7 Oct 20, 2022
MY WAY , it is an Online bus ticket reservation system

MY WAY , it is an Online bus ticket reservation system. It is supposed to execute the common function of bus ticket reservation in reality. It is a Web based application that works within a centralized network. This project will have the facility which is used to reserve seats, cancellation of reservation and different types of route enquiries used on securing quick reservations.

Sh Tanmoy 2 Feb 12, 2022
微信支付 API v3 的 PHP Library,同时也支持 API v2

微信支付 WeChatPay OpenAPI SDK [A]Sync Chainable WeChatPay v2&v3's OpenAPI SDK for PHP 概览 微信支付 APIv2&APIv3 的Guzzle HttpClient封装组合, APIv2已内置请求数据签名及XML转换器,应

null 275 Jan 5, 2023
Simple PHP API client for tube-hosting.com rest API

Tube-Hosting API PHP client Explanation This PHP library is a simple api wrapper/client for the tube-hosting.com api. It is based on the provided docu

null 4 Sep 12, 2022
Chargebee API PHP Client (for API version 2 and Product Catalog version 2.0)

chargebee-php-sdk Overview This package provides an API client for Chargebee subscription management services. It connects to Chargebee REST APIs for

GLOBALIS media systems 8 Mar 8, 2022
This API aims to present a brief to consume a API resources, mainly for students in the early years of Computer Science courses and the like.

Simple PHP API v.1.0 This API aims to present a brief to consume a API resources, mainly for students in the early years of Computer Science courses a

Edson M. de Souza 14 Nov 18, 2021
This API provides functionality for creating and maintaining users to control a simple To-Do-List application. The following shows the API structure for users and tasks resources.

PHP API TO-DO-LIST v.2.0 This API aims to present a brief to consume a API resources, mainly for students in the early years of Computer Science cours

Edson M. de Souza 6 Oct 13, 2022
API documentation API SCB EASY APP

SCB-API-EASY V3.0 API documentation SIAM COMMERCIAL BANK PUBLIC COMPANY LTD. API SCB Easy V3 endpoint = https://fasteasy.scbeasy.link 1.0. Get balance

SCB API Esay team 2 Sep 28, 2021
Courier API adalah project API untuk mengetahui ongkos kirim Logistik-logistik pengiriman barang antar kota & International

Courier API Courier API adalah project API untuk mengetahui ongkos kirim Logistik-logistik pengiriman barang antar kota (dalam negeri) & International

Rangga Darmajati 2 Sep 24, 2021
Laravel api tool kit is a set of tools that will help you to build a fast and well-organized API using laravel best practices.

Laravel API tool kit and best API practices Laravel api tool kit is a set of tools that will help you to build a fast and well-organized API using lar

Ahmed Esa 106 Nov 22, 2022
LaraBooks API - Simple API for iOS SwiftUI app tests.

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

Konrad Podrygalski 1 Nov 13, 2021
Best resources restful api for developers (with JSON:API standar specification design)

List API Best resources restful api for developers (with JSON:API standar specification design). API Resource Endpoint Name Resource Description Al Qu

Noval 2 Jan 18, 2022