calvient / puddleglum
Transform Laravel models, routes, and controllers into a Typescript API client
Installs: 10 756
Dependents: 0
Suggesters: 0
Security: 0
Stars: 3
Watchers: 1
Forks: 0
Open Issues: 0
Requires
- php: ^8.3
- doctrine/dbal: ^3.1
- illuminate/contracts: ^8.37|^9.0|^10.0|^11.0
- spatie/laravel-package-tools: ^1.11.0
Requires (Dev)
- brianium/paratest: ^6.2
- larastan/larastan: ^2.7
- nunomaduro/collision: ^5.3|^6.1.0|^7.0|^8.0
- orchestra/testbench: ^6.15|^7.0.1
- phpunit/phpunit: ^9.3|^10.0
README
Puddleglum allows you to automatically generate TypeScript interfaces from your Laravel models and requests as well as a typesafe Axios implementation for your API routes.
This package is based on lepikhinb/laravel-typescript. Special thanks for such an awesome package!
Introduction
If you, like Calvient, have a Laravel backend with a TS front-end (be it React, Vue, or something else), you might have noticed that you have to manually keep your TypeScript interfaces in sync with your Laravel models and requests. You might also have noticed that you have to manually keep your Axios implementation in sync with your Laravel routes.
Puddleglum is a Laravel package that solves these problems by automatically generating Typescript interfaces and a simple API implementation based on Axios.
Installation
Laravel 8 and PHP 8 are required. You can install the package via composer:
composer require --dev calvient/puddleglum
You can publish the config file with:
php artisan vendor:publish --provider="Calvient\Puddleglum\PuddleglumServiceProvider" --tag="puddleglum-config"
This is the contents of the published config file:
return [ 'output' => resource_path('ts/puddleglum.ts'), ];
Usage
Generate TypeScript interfaces.
php artisan puddleglum:generate
Defining your requests
In Laravel, you might define your requests from the command line like this:
php artisan make:request StoreUser
If you do this (i.e., your requests extend FormRequest), Puddleglum will automatically generate TypeScript interfaces for your requests. The program reads the rules from your FormRequest and generates TypeScript interfaces for your requests.
For example:
class UserLogin extends FormRequest { public function authorize() { return true; } public function rules() { return [ 'email' => 'required|email', 'password' => [ 'required', Password::min(8)->mixedCase()->letters()->numbers()->symbols()->uncompromised(), ], ]; } }
Becomes:
export interface UserLogin { email: string; password: string; }
If you don't want to define a FormRequest (e.g., you want to use a request validator directly in your controller), you can use the GlumRequest attribute before your controller.
Example;
#[GlumRequest(['name' => 'string', 'email' => 'string', 'password' => 'string'])] public function register(Request $request) { $request->validate([ 'name' => 'required|string|max:255', 'email' => 'required|string|email|max:255|unique:users', 'password' => Password::min(8) ->letters() ->mixedCase() ->numbers() ->symbols() ->uncompromised(), ]); }
Defining Responses
Defining a response is a bit trickier, because PHP lacks support for generics. However, Puddleglum can still generate TypeScript interfaces for your responses.
We accomplish this by using a PHP attribute.
Example:
#[GlumResponse(['user' => 'User', 'message' => 'string'])] public function show(User $user): User { return response()->json([ 'user' => $user, 'message' => 'Hello, world!', ]); }
Using the Puddleglum Output in your TypeScript code
Import the Puddleglum client into your TypeScript code:
import {Puddleglum} from '../../puddleglum';
Then, you can use the Puddleglum client to make API calls:
const login = async (email: string, password: string) => { const reply = await Puddleglum.Auth.LoginController.login({email, password}); setUser(reply.data.user); };
The API client mirrors the PHP namespace. So, in the example
above, the login controller is at \App\Http\Controllers\Auth
and the method is named login
.
You can also import various models and requests.
import {User} from '../../puddleglum'; const [user, setUser] = React.useState<User>();
License
The MIT License (MIT). Please see License File for more information.