La capacidad de crear un generador de código para la API para salvar a la generación futura de la necesidad de crear constantemente los mismos controladores, modelos, enrutadores, middleware, migraciones, esqueletos, filtros, validaciones, etc. manualmente (incluso en el contexto de marcos familiares y convenientes), me pareció interesante.
Estudié la tipificación y las sutilezas de la especificación OpenAPI, me gustó por su linealidad y capacidad para describir la estructura y los tipos de cualquier entidad en 1-3 niveles de profundidad. Como en ese momento ya estaba familiarizado con Laravel (Yii2 se usaba antes, CI, pero eran menos populares), así como con el formato de salida de datos json-api: toda la arquitectura se me vino a la cabeza con un gráfico conectado.

Pasemos a los ejemplos.
Supongamos que tenemos la siguiente entidad descrita en la OEA:
ArticleAttributes: description: Article attributes description type: object properties: title: required: true type: string minLength: 16 maxLength: 256 facets: index: idx_title: index description: required: true type: string minLength: 32 maxLength: 1024 facets: spell_check: true spell_language: en url: required: false type: string minLength: 16 maxLength: 255 facets: index: idx_url: unique show_in_top: description: Show at the top of main page required: false type: boolean status: description: The state of an article enum: ["draft", "published", "postponed", "archived"] facets: state_machine: initial: ['draft'] draft: ['published'] published: ['archived', 'postponed'] postponed: ['published', 'archived'] archived: [] topic_id: description: ManyToOne Topic relationship required: true type: integer minimum: 1 maximum: 6 facets: index: idx_fk_topic_id: foreign references: id on: topic onDelete: cascade onUpdate: cascade rate: type: number minimum: 3 maximum: 9 format: double date_posted: type: date-only time_to_live: type: time-only deleted_at: type: datetime
Si ejecutamos el comando
php artisan api:generate oas/openapi.yaml --migrations
entonces obtenemos los siguientes objetos generados:
1) Controlador de entidad
<?php namespace Modules\V1\Http\Controllers; class ArticleController extends DefaultController { }
Él ya conoce GET / POST / PATCH / DELETE, para lo cual irá a la tabla a través del modelo, cuya migración también se generará. DefaultController siempre está disponible para el desarrollador, por lo que es posible implementar la funcionalidad para todos los controladores.
2) Modelo de entidad del artículo
<?php namespace Modules\V2\Entities; use Illuminate\Database\Eloquent\SoftDeletes; use rjapi\extension\BaseModel; class Article extends BaseModel { use SoftDeletes;
Como puede ver, los comentarios aparecieron aquí // >>> accesorios >>> y // >>> métodos >>>: son necesarios para separar el espacio de código del espacio de código del usuario. También hay una relación etiqueta / tema: belognsToMany / belongTo, respectivamente, que conectará la entidad Artículo con etiquetas / temas, brindando la oportunidad de acceder a ellos en las relaciones json-api con una sola solicitud GET o cambiarlos actualizando el artículo.
3) Migración de entidades, con soporte de reversión (reflexión / atomicidad):
<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateArticleTable extends Migration { public function up() { Schema::create('article', function(Blueprint $table) { $table->bigIncrements('id'); $table->string('title', 256); $table->index('title', 'idx_title'); $table->string('description', 1024); $table->string('url', 255); $table->unique('url', 'idx_url');
El generador de migración admite todos los tipos de índices (incluidos los compuestos).
4) Enrutador para solicitudes de desplazamiento:
Las rutas se crearon no solo para consultas básicas, sino también relaciones con otras entidades, que se extraerán mediante 1 consulta y extensiones como operaciones masivas para la capacidad de crear / actualizar / eliminar datos en lotes.
5) FormRequest para preprocesamiento / validación de solicitudes:
<?php namespace Modules\V1\Http\Requests; use rjapi\extension\BaseFormRequest; class ArticleFormRequest extends BaseFormRequest {
Aquí todo es simple: las reglas para validar propiedades y relaciones se generan para conectar la entidad principal con entidades en el método de relaciones.
Finalmente, la mejor parte son los ejemplos de consulta:
http:
Muestre un artículo, ajuste todas sus etiquetas en relaciones, paginación en la página 2, con un límite de 10, y ordene por edad.
Si no necesitamos mostrar todos los campos del artículo:
http:
Ordenar por múltiples campos:
http:
Filtrado (o lo que corresponda a la cláusula WHERE):
http:
Un ejemplo de creación de una entidad (en este caso, artículos):
POST http://laravel.loc/v1/article { "data": { "type":"article", "attributes": { "title":"Foo bar Foo bar Foo bar Foo bar", "description":"description description description description description", "fake_attr": "attr", "url":"title title bla bla bla", "show_in_top":1 } } }
La respuesta es:
{ "data": { "type": "article", "id": "1", "attributes": { "title": "Foo bar Foo bar Foo bar Foo bar", "description": "description description description description description", "url": "title title bla bla bla", "show_in_top": 1 }, "links": { "self": "laravel.loc/article/1" } } }
Ver el enlace en links-> self? puedes de inmediato
GET http://laravel.loc/article/1
o guárdelo para referencia futura.
GET http://laravel.loc/v1/article?include=tag&filter=[["updated_at", ">", "2017-01-03 12:13:13"], ["updated_at", "<", "2019-01-03 12:13:15"]] { "data": [ { "type": "article", "id": "1", "attributes": { "title": "Foo bar Foo bar Foo bar Foo bar 1", "description": "The quick brovn fox jumped ower the lazy dogg", "url": "http://example.com/articles_feed 1", "show_in_top": 0, "status": "draft", "topic_id": 1, "rate": 5, "date_posted": "2018-02-12", "time_to_live": "10:11:12" }, "links": { "self": "laravel.loc/article/1" }, "relationships": { "tag": { "links": { "self": "laravel.loc/article/1/relationships/tag", "related": "laravel.loc/article/1/tag" }, "data": [ { "type": "tag", "id": "1" } ] } } } ], "included": [ { "type": "tag", "id": "1", "attributes": { "title": "Tag 1" }, "links": { "self": "laravel.loc/tag/1" } } ] }
Devolvió una lista de objetos, en cada uno de los cuales el tipo de este objeto, su identificación, el conjunto completo de atributos, luego un enlace a sí mismo, las relaciones solicitadas en la URL a través de
include = tag, de acuerdo con la especificación, no hay restricciones para incluir relaciones, es decir,
include = tag, tema, ciudad y todos ellos se incluirán en el bloque de
relaciones , y sus objetos se almacenarán en
incluido .
Si queremos obtener 1 artículo y todas sus relaciones / relaciones:
GET http://laravel.loc/v1/article/1?include=tag&data=["title", "description"] { "data": { "type": "article", "id": "1", "attributes": { "title": "Foo bar Foo bar Foo bar Foo bar 123456", "description": "description description description description description 123456", }, "links": { "self": "laravel.loc/article/1" }, "relationships": { "tag": { "links": { "self": "laravel.loc/article/1/relationships/tag", "related": "laravel.loc/article/1/tag" }, "data": [ { "type": "tag", "id": "3" }, { "type": "tag", "id": "1" }, { "type": "tag", "id": "2" } ] } } }, "included": [ { "type": "tag", "id": "3", "attributes": { "title": "Tag 4" }, "links": { "self": "laravel.loc/tag/3" } }, { "type": "tag", "id": "1", "attributes": { "title": "Tag 2" }, "links": { "self": "laravel.loc/tag/1" } }, { "type": "tag", "id": "2", "attributes": { "title": "Tag 3" }, "links": { "self": "laravel.loc/tag/2" } } ] }
Y aquí hay un ejemplo de agregar relaciones a una entidad existente: una solicitud:
PATCH http://laravel.loc/v1/article/1/relationships/tag { "data": { "type":"article", "id":"1", "relationships": { "tag": { "data": [{ "type": "tag", "id": "2" },{ "type": "tag", "id": "3" }] } } } }
La respuesta es:
{ "data": { "type": "article", "id": "1", "attributes": { "title": "Foo bar Foo bar Foo bar Foo bar 1", "description": "The quick brovn fox jumped ower the lazy dogg", "url": "http://example.com/articles_feed 1", "show_in_top": 0, "status": "draft", "topic_id": 1, "rate": 5, "date_posted": "2018-02-12", "time_to_live": "10:11:12" }, "links": { "self": "laravel.loc/article/1" }, "relationships": { "tag": { "links": { "self": "laravel.loc/article/1/relationships/tag", "related": "laravel.loc/article/1/tag" }, "data": [ { "type": "tag", "id": "2" }, { "type": "tag", "id": "3" } ] } } }, "included": [ { "type": "tag", "id": "2", "attributes": { "title": "Tag 2" }, "links": { "self": "laravel.loc/tag/2" } }, { "type": "tag", "id": "3", "attributes": { "title": "Tag 3" }, "links": { "self": "laravel.loc/tag/3" } } ] }
Puede transferir opciones adicionales al generador de consola:
php artisan api:generate oas/openapi.yaml --migrations --regenerate --merge=last
Por lo tanto, le dice al generador: cree un código con migraciones (ya lo vio) y vuelva a generar el código, almacenándolo con los últimos cambios del historial guardado, sin afectar las secciones personalizadas del código, pero solo aquellos que se generaron automáticamente (es decir, solo aquellos , que están resaltados por bloques especiales con comentarios en el código). Es posible especificar los pasos hacia atrás, por ejemplo:
--merge = 9 (revertir la generación 9 pasos hacia atrás), las fechas de generación del código en el pasado
--merge = "2017-07-29 11:35:32" .
Uno de los usuarios de la biblioteca sugirió generar pruebas funcionales para consultas; al agregar la opción
--tests , puede ejecutar pruebas para asegurarse de que su API funcione sin errores.
Además, puede usar muchas opciones (todas están configuradas de manera flexible a través del configurador, que se encuentra en el módulo generado, por ejemplo:
/Modules/V2/Config/config.php ):
<?php return [ 'name' => 'V2', 'query_params'=> [
Naturalmente, todas las configuraciones pueden activarse / desactivarse si es necesario. Para obtener más información sobre las características adicionales del generador de código, consulte los enlaces a continuación. Las contribuciones son siempre bienvenidas.
Gracias por su atención, éxito creativo.
Recursos del artículo: