Over time, as builders, now we have at all times regarded for ways in which we will automate our documentation, from PHPDoc to Swagger and past. Lately that has been a major shift within the API world to undertake a extra design-first-led method to API documentation. This was primarily spurred by the creation of the OpenAPI specification, which is the alternative for Swagger.
As builders, we frequently haven’t got the time or inclination to dive right into a design-first method to our APIs – that is only a reality. Whereas it may be greatest follow, and what everyone seems to be saying. In actuality, we’re paid to construct and ship options, so we frequently skip steps. What if I instructed you that you may add one small step to your workflow that will permit you to construct API documentation as you go?
Let’s get began. On this tutorial, I’ll construct an completely fictional API with no objective, and it will not be how I might usually construct an API. That is for a motive, although, as I would like you to focus purely on the steps I take.
I will not undergo the preliminary setup steps, as this has been coated loads up to now. I’ll make many assumptions on this tutorial – principally round you realizing the best way to arrange and set up Laravel, but in addition about utilizing artisan to generate courses.
We now have a Laravel venture open in our IDE, and we have to add some performance. I discover it useful when constructing APIs to evaluate the aim of the API. Attempt to perceive why it’s being constructed and what it’s being constructed for. This permits us to know what will be helpful for our API and stops us from including extra endpoints that merely aren’t wanted.
We shall be constructing a easy bookshelf API on this tutorial. It can permit us to create some fairly primary performance – in order that now we have a objective for what we’re constructing. This API goals at shoppers who can connect with our API to handle their books. An important factor to those customers is a solution to see their books and add books rapidly. There can be different performance accessible finally however at all times begin an API with what’s the main objective that each person will want.
Create a brand new mannequin, migration, and manufacturing facility for the Guide mannequin. This would be the main mannequin inside our API. The attributes you need on this mannequin aren’t that vital for this tutorial – however I’ll stroll by them anyway:
1public perform up(): void
2{
3 Schema::create('books', static perform (Blueprint $desk): void {
4 $desk->id();
5Â
6 $desk->string('title');
7 $desk->string('subtitle')->nullable();
8 $desk->textual content('description');
9 $desk->string('language');
10Â
11 $desk->unsignedBigInteger('pages');
12Â
13 $desk->json('authors');
14 $desk->json('classes');
15 $desk->json('pictures');
16 $desk->json('isbn');
17Â
18 $desk->date('published_at');
19 $desk->timestamps();
20 });
21}
This displays the Google Books API considerably. We now have a ebook title and subtitle, which is the ebook’s identify. The outline and language clarify what the ebook is about and in what language. We now have a web page depend to see whether or not it’s a massive ebook. Then now we have authors, classes, pictures, and ISBNs so as to add additional info. Lastly, there’s the printed date.
Now that now we have the mannequin and database, we will begin wanting into the API itself. Our first step shall be to put in a package deal that lets us generate our API documentation. There is a superb package deal referred to as Scribe that you need to use, which works in each Laravel and easy PHP functions. You may set up it utilizing the next composer command:
1composer require --dev knuckleswtf/scribe
After getting put in this, you may observe the setup directions to get this working inside your software. As soon as that is put in, and the configuration is printed – you are able to do a take a look at run of the API doc technology to make sure it really works as anticipated. It is best to get one thing like this out of the field:
1openapi: 3.0.3
2information:
3 title: Laravel
4 description: ''
5 model: 1.0.0
6servers:
7 -
8 url: 'http://localhost:8000'
9paths: []
10tags: []
Now that we all know it’s working, we will look so as to add just a few routes to make sure that they’re used within the OpenAPI technology.
Allow us to begin with our first routes round fetching books, getting an inventory of books, and getting a single ebook.
1Route::prefix('books')->as('books:')->middleware(['api'])->group(static perform (): void {
2 Route::get(
3 '/',
4 AppHttpControllersApiBooksIndexController::class,
5 )->identify(
6 identify: 'index',
7 );
8Â
9 Route::get(
10 '{ebook}',
11 AppHttpControllersApiBooksShowController::class,
12 )->identify(
13 identify: 'present',
14 );
15});
We now have two routes underneath the books
prefix, and each are GET
routes that require no authentication. These shall be a part of the general public API that anybody can entry.
Now now we have the routes and controllers in place. We’d like to consider how we wish to deal with these routes. We wish to type and filter our requests in order that we will request particular lists of books. To attain this, we are going to use the Spatie Laravel Question Builder package deal, offering a clear interface to go looking and filter what we want. Let’s get this put in utilizing the next composer command:
1composer require spatie/laravel-query-builder
As soon as this has been put in, we can take into consideration the best way to filter our API requests to get the proper record of books. With all good APIs, there’s pagination. To attain this, we may use the built-in paginator from Laravel. Nevertheless, Aaron Francis created a paginator referred to as Quick Paginate which is rather more performant – one thing vital in the case of an API. You may set up this utilizing the next composer command:
1composer require hammerstone/fast-paginate
Let’s mix these two issues so we will construct up a group and return a paginated end result.
1return QueryBuilder::for(
2 topic: Guide::class,
3)->allowedFilters(
4 filters: ['language', 'pages', 'published_at'],
5)->fastPaginate();
This works effectively for our use case – nonetheless, I’m not a fan of returning question outcomes straight out of your API. We must always at all times rework the response utilizing an API useful resource to a controllable format. Laravel has built-in assets, or you need to use the PHP Leagues Fractal package deal, which is fairly good. On this instance, I’ll use a package deal I’ve written about earlier than, so I will not go into element. Finally, we should always find yourself with a controller that appears like the next or at the least carefully resembles it:
1last class IndexController
2{
3 public perform __invoke(Request $request): JsonResponse
4 {
5 return new JsonResponse(
6 knowledge: BookResource::assortment(
7 useful resource: QueryBuilder::for(
8 topic: Guide::class,
9 )->allowedFilters(
10 filters: ['language', 'pages', 'published_at'],
11 )->fastPaginate(),
12 ),
13 );
14 }
15}
Up to now, it will solely register our route within the OpenAPI specification, which is healthier than nothing. However with some additional work, we will doc the parameters and group issues, making much more sense. In Scribe, you are able to do this utilizing both DocBlocks or Attributes. I want to make use of DocBlocks myself for this, as there aren’t attributes for the entire fields you’d wish to use. Let me present you an instance, and I’ll stroll you thru all the things I’ve accomplished.
1last class IndexController
2{
3 /**
4 * @group Guide Assortment
5 *
6 * Get all Books from the API.
7 *
8 * @queryParam filter[language] Filter the books to a selected language. filter[language]=en
9 * @queryParam filter[pages] Filter the books to these with a specific amount of pages. filter[pages]=1000
10 * @queryParam filter[published_at] Filter the books to these printed on a sure date. filter[published_at]=12-12-1992
11 *
12 */
13 public perform __invoke(Request $request): JsonResponse
14 {
15 return new JsonResponse(
16 knowledge: BookResource::assortment(
17 useful resource: QueryBuilder::for(
18 topic: Guide::class,
19 )->allowedFilters(
20 filters: ['language', 'pages', 'published_at'],
21 )->fastPaginate(),
22 ),
23 );
24 }
25}
We begin by including @group Guide Assortment
which can group this endpoint underneath a “Guide Assortment” permitting for simpler navigation of your API documentation. We then add “Get all Books from the API.” which describes the precise endpoint. We then can add further @queryParam
entries to doc the accessible question parameters this endpoint takes. A lot simpler than writing YAML, proper!
The Scribe documentation has rather more info, and you may go in-depth with what info you add. I’ve solely brushed the fundamentals right here – however already you may see how helpful this may be. What do you utilize to your API Documentation? Tell us on Twitter!