Download the PHP package rjapi/raml-json-api without Composer
On this page you can find all versions of the php package rjapi/raml-json-api. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Informations about the package raml-json-api
api-generator
PHP-code generator (based on OAS) for Laravel framework, with complete support of JSON-API data format
- Getting started Demo
- CRUD Demo
- Relation links Demo
- Migrations Demo
- API docs Demo
- Installation
- Configuration
- Optional settings
- Running generator
- Docker repo
- Open API Types and Declarations
- Open API Docs generator
- Generated files content
- Module Config
- Controllers
- FormRequests
- Models
- Routes
- Migrations
- Tests
- Relationships
- Bulk Extension
- Query parameters
- Security
- Static access token
- JWT
- Caching
- Soft Delete
- Tree structures
- Finite-state machine
- Spell check
- Bit mask
- Custom SQL
- Custom business logic
- Regeneration
Installation via composer:
First of all - create Laravel project if you didn't do that yet:
then in your project directory run:
It will automatically register Laravel ServiceProvider by adding console command api:generate
(you should see it when running php artisan
)
and also publish "laravel-modules" provider.
Autoloading
By default Controllers, entities or repositories are not loaded automatically. You can autoload your modules using psr-4
.
For example :
refresh changes by running:
Optional settings
To provide Json API compatible error handler one can add ErrorHandler
trait to app/Exceptions/Handler
class
and return return $this->renderJsonApi($request, $exception);
from standard Laravel render
method,
complete example of Handler
class will look something like this:
As you may noticed it returns Illuminate\Http\JsonResponse
Laravel object to output data appropriately e.g.:
The default Laravel installation has an api
prefix for API routes.
If you want to access generated json api routes via their prefix first ex.: /v2/article
or /myshop/basket
,
you will need to remove the prefix from the mapApiRoutes()
method in your RouteServiceProvider
.
Running generator
Run in console:
This command creates the whole environment for you to proceed building complex API based on OAS/Laravel/JSON API, in particular: directories for modular app, Controllers/FormRequests/Models+Pivots to support full MVC, Routes (JSON API compatible) and even migrations to help you create RDBMS structure.
- file in oas directory in the root of your project, which should be prepared before or you may wish to just try by copying an example from and probably rewrite it for your needs.
You can also use .json
ext/format to produce the same results if required or more convenient for your environment.
Options:
is an option to create migrations (create_entityName_table) for every entity + pivots if there are ManyToMany relationships.
use this if you need to rewrite all files generated previously. By default generated files preserved to prevent overwriting of added/modified content.
The output will look something like this:
After that u can see the following dirs and files module structure in your project:
Docker repository
Another way of installing and playing with api-generator (in sandbox fashion) is via https://github.com/SoliDry/laravel-api. Clone repository and run:
You can see Dockerfile
and docker-compose.yml
files there.
PS Any contributions to build a better containers are welcome.
Open API Types and Declarations
OAS (Open API Specification) was developed as merge of Swagger and RAML specs by two groups of developers (they tired of arguing with each other :smile:), thus it became quite popular and has been implemented for api-generator
or in json:
U can set multiple servers as well as multiple files into the main openapi.yaml
, thus code will be generated for every server module e.g.: Modules/v2, Modules/v3, Modules/v4
and there will be other Types from different files.
Basic and custom Types are declared under
or in json:
Types are special helper Types - !required
You can easily add string
IDs to entities you'd like for example SID
can be placed in Article
entity like that id: SID
- api-generator
will produce migrations, relations and models respectively.
or in json:
Special data type - !required
or in json:
defined in every relationship custom type
Attributes are defined for every custom Object ex.:
or in json:
Relationships custom type definition semantics
Complete composite Object looks like this:
That is all that api-generator needs to provide code structure that just works out-fo-the-box within Laravel framework, where may any business logic be applied.
To use multiple files processing add (as root element):
all files will be generated as if they were one composite object.
To set default values for GET query parameters - set QueryParams like this:
it will be used on requests similar to:
where no params were passed.
Complete directory structure after generator will end up it`s work will be like:
Open API Docs generator
OAS *Controllers based documentation is generated out of the box, thus you don't need to create it manually let's see a couple examples:
All generated methods (when expanded) will look like this: There is no magic in it at all - just look into your generated controllers there are pre-generated annotations for every method e.g.:
Generated files content
Module Config
Controllers
Entity controller example:
By default every controller works with any of GET - index/view, POST - create, PATCH - update, DELETE - delete methods. Thus you don't need to implement anything special here.
DefaultController example:
To provide developer-based (user-space) implementation of certain logic for all Controllers.
FormRequests
Validation BaseFormRequest example:
Models
BaseModel example:
Routes
Routes will be created in file, for every entity defined in yaml:
As you may noticed there are relationships api-calls and bulk Extension batch queries support.
Migrations
Generated migrations will look like standard migrations in Laravel:
Note, that U have an ability to make any ranges for varchar, integer types through minLength/maxLength and minimum/maximum respectively.
For instance, integer can be set to unsigned smallint with
minimum: 1
(any number > 0) and maximum: 2
(any number <= 3 to fit smallint db type range).
If double/float types used, then maximum goes for display length (or M) and minimum for precision (or D) in SQL e.g.: DOUBLE(M, D)
All migrations for specific module will be placed in
To execute them all - run:
Also worth to mention - Laravel uses table_id convention to link tables via foreign key.
So U can either follow the default - add to yaml an id that matches to the table name
(just like in example: topic_id
-> in article table for topic table id
, see ArticleAttributes
in OAS Types and Declarations)
or make your own foreign key and add it to parameter in generated BaseModel entity.
Additionally, to specify index for particular column you can add a facets
property like this:
to existing columns.
However, there are situations where you have to create composite indices:
an example for foreign key would be like:
Tests
To provide convenient way for integration/functional testing, one can generate tests by providing --tests
command option, e.g.:
in command output you'll see the following files have been created:
For more info on how to set an environment for functional tests in Laravel - see https://codeception.com/for/laravel
Relationships particular qualities
To let generator know about what a particular relationship to apply (ex.: ManyToMany, OneToMany, OneToOne) set the property in an Entity like so - for ex. let's see how to set ManyToOne relationship between Article and Tag entities.
Define Article with relationships like:
and Tag with relationships like:
This way you telling to generator: "make the relation between Article and Tag OneToMany from Article to Tag" The idea works with any relationship you need - ex. ManyToMany: , OneToOne:
You can also bind several relationships to one entity, for instance - you have an Article entity that must be bound to TagRelationships and TopicRelationships, this can be done similar to:
or vise versa
Generator will independently detect all relationships between entities.
Query parameters
You may want to use additional query parameters to fetch includes and/or pagination, for instance:
You may not wish to drag all the attributes/fields:
Note: data array items MUST be set in double quotes.
or you may want to ORDER BY several columns in different directions:
Also, you have an ability to filter results this way:
those arrays will be put to Laravel where clause and accordingly protected by param bindings.
The dynamic module name similar to: v1, v2 - will be taken on runtime as the last element of the array in file, if you, by strange circumstances, want to use one of the previous modules, just set one of previously registered modules as the last element of an array.
An example of auto-generated :
To get configuration parameters at runtime generator will create content in file:
Bulk Extension
Multiple resources can be created by sending a POST request to a URL that represents a collection of resources.
Multiple resources can be updated by sending a PATCH request to a URL that represents a collection of resources to which they all belong.
Multiple resources can be deleted by sending a DELETE request to a URL that represents a collection of resources to which they all belong.
A request completely succeed or fail (in a single "transaction").
Therefore, any request that involves multiple operations only succeed if all operations are performed successfully. The state of the server will not be changed by a request if any individual operation fails.
Security
Static access token
In you can declare the property, that will be placed to . Generator will create FormRequest.
To activate this check on every request - add ApiAccessToken FormRequest to , ex.:
Generated configuration part:
JWT (Json Web Token)
To support a JWT check, you need to add to any users, employees, customers like table the and properties:
The parameter is important, because of varchar-type sql field will be created with length 512.
The value should be equal precisely ' ' - empty string with space.
JWT specific configuration will be appended by generator in :
U can change those activate
and expires
time settings as needed.
To protect key verification in JWT token - place JWT_SECRET
variable to .env configuration file with secret key value assigned
(secret can be any string at any length, but be wise to use strong one, ex.: hashed with sha1/sha2 etc).
Then put the value to global configuration file config/app.php
, we need this to apply best practices for caching configs environment.
As for any standard Laravel middleware register it in :
And just use this middleware in any requests u need defining it in , ex:
To declare JWT check only for one specific route:
To declare JWT check for routes group:
JWT will be created on POST and updated on PATCH request to the entity you've been created, for instance, if you send POST request to with the following content:
Response will be similar to:
Note if JWT , password will be hashed with and saved to password field internally. Do not bother with attribute it is unset before output for safety. You can add additional checks on password or other fields ex.: length, strength etc in Model on before/afterSave events.
An example for JWT refresh - :
Note that password and jwt set to true are required.
Response:
Regular request with JWT will look like:
The algorithm to sign the token is HS256, it can be changed in future releases with additional user-defined options to let developers choose another. However, HMAC SHA-256 is the most popular these days.
Caching
API ships with caching ability (via Redis) out of the box, the only thing you need to do is to declare cache settings:
and set the cache
property in any custom entity, for instance:
one can set multiple instances of Redis servers, if they have clusters or replica-set.
Another option is to make your services resistant to Cache Stampede (or dog-piling) by applying
corresponding stampede properties to cache
entity,
stampede_xfetch
turns on the xfetch implementation and stampede_beta
should be 0.5<=beta<=2.0 (where > 1.0 schedule a recompute earlier, < 1.0 schedule a recompute later),
ttl property is also required in this case.
Generated config output will look similar to:
All specific settings including host/port/password, replication, clusters etc can be easily configured via Laravel standard Redis cache settings. Read more on this here - Redis Laravel configuration
After cache settings configured - index
and view
requests (ex.: /api/v1/article/1?include=tag&data=["title", "description"]
or /api/v1/article?include=tag&filter=...
)
will put resulting data into cache with hashed key of a specified uri, thus providing a unique key=value storage mechanism.
In Redis db instance you'll see serialized objects with keys like:
Soft Delete
When models are soft deleted, they are not actually removed from your database.
Instead, a deleted_at
attribute is set on the model and inserted into the database.
If a model has a non-null deleted_at
value, the model has been soft deleted.
To enable soft deletes for a model just add deleted_at
property on any custom type you need, ex.:
Special generated properties/traits will appear for the specified types in folder, also related migration field will be created.
Model example:
Migration example:
It will be then automatically applied for delete requests and models won't be collected for view/index.
Turn off JSON API support
If you are willing to disable json api specification mappings into Laravel application (for instance - you need to generate MVC-structure into laravel-module and make your own json schema, or any other output format), just set property in DefaultController to false:
As this class inherited by all Controllers - you don't have to add this property in every Controller class. By default JSON API is turned on.
Tree structures
You can easily build a tree structure by declaring it as Trees
custom type:
and adding parent_id
to the targeted table, ex.:
the entire tree will be placed in meta
json-api root element,
while all the parent elements (stored as parent_id=0) will reside in data root element.
This was done to keep steady json-api structure and it's relations.
Meta data response example:
Children elements stuck in every parent's children
property array and it is empty if there are none.
To get a sub-trees of a top most ancestors - simply execute GET request for the item, ex.: http://example.com/api/v1/menu/1
.
See wiki page for real-world examples with Postman.
Finite-state machine
To add finite-state machine to a field(column) of an entity(table) - add definition into your OAS file like this:
The only required particular item in state_machine
declaration is an initial
value of state machine.
After generation process will pass, you'll get the following content in config.php
:
It will be processed on POST
and PATCH
requests respectively.
You can easily disable state machine by setting enabled
to false
.
There is an ability to add state machines in different tables.
Spell check
Installation
The spell checking functionality provided by robust and versatile linux library GNU aspell
and it's dictionaries as extension for PHP.
To install an extension for Linux (ex.: Ubuntu):
To install an additional language db run:
Usage
You may want to set spell check on particular field/column:
Generator output in Modules/{VersionName}/Config/config.php
will look like this:
As in other settings - spell check can be disabled with enabled
set to false.
If there is no info preset about language - the en
will be used as default value.
In responses from methods POST/PATCH (create/update)
you'll get the meta
content back with filled array of failed checks in it:
Bit Mask
To use bit mask with automatic flags fragmentation/defragmentation you can define additional facets to an integer field like this:
thus the config entity bit_mask
will be generated and used on runtime within requests to process data.
Generated config snippet:
And the request/response will be:
Recall that U can always hide ex.: permissions
field in index/view GET requests if U'd like.
Custom SQL
If by any reason you need to use custom sql query - just define it in Modules/V1/Config/config.php
:
as U can see there are query
, bindings
(where has been passed a secured param-bound values) and enabled
parameters for desired entity.
Custom sql query will be executed only for index
API method,
so if U need ex. delete
or update
specific extra rows - call those methods with previously selected ids.
Don't forget to add Laravel specific $fillable
or $guarded
array to let fill-in the object (mass-assignment rule) ex.::
Note: you need an id
field to be present, because of json-api serializer.
Custom business logic
You can add any business logic you need, the best place for your custom-code is in pre-generated controllers ex.:
to add specific sanitizers on fields for ArticleController
and modified output you can override create
method like this:
There can be situations where you need to add workaround in particular method or init logic for all requests of that type index/view/create/update/delete,
it can be easily achieved by placing code in DefaultController
the same way it is for any other Controllers. The inheritance model made specifically for
those purposes will gracefully perform any ops before/after etc. For instance:
As u may noticed there is an access to either Route and Request properties.
In next chapter you'll know how to place custom code in Models/FormRequest preserving it from code regeneration override.
Regeneration
It is an important feature to regenerate your code based on generated history types and the current state of OpenApi document, which can be easily achieved by running:
This command will merge the last state/snapshot of document from .gen
directory
and the current document (in this case from oas/openapi.yaml
),
then creates files for models and FormRequest, merging it with user added content between generated props and methods.
Moreover, it will add the new columns to newly created migration files with their indices.
Controller state:
Example of regenerated FormRequest:
As you can see all user content was preserved and merged with regenerated.
Custom business logic content saves it's state when --regenerate
option is present, either with or without other options.
The same is true for Eloquent model:
Example of regenerated migration:
If you don't want to save history on every run add --no-history
option.
There are also more things you can do, about rewinding history:
- by passing option like this
--merge=9
generator will get back for 9 steps --merge="2017-07-29 11:35:32"
generator gets to the concrete files by time in history
Although, if you need to totally rollback the state of a system - use --rollback
option, with the same keys as in merge.
==== Infection code coverage ====
Metrics:
Mutation Score Indicator (MSI): 81%
Mutation Code Coverage: 86%
Covered Code MSI: 93%
==========
HTTP request/response examples can be found on WiKi page - https://github.com/SoliDry/api-generator/wiki
Laravel project example with generated files can be found here - https://github.com/SoliDry/laravel-api
To get deep-into specification - https://swagger.io/specification/
To get deep-into specification - http://jsonapi.org/format/ JSON-API support is provided, particularly for output, by Fractal package - http://fractal.thephpleague.com/
Happy coding ;-)
PS The purpose of this repo is to prevent doing the same things over and over again, expecting different results. (Thx to Albert Einstein)
Supporters gratitude:
All versions of raml-json-api with dependencies
ext-json Version *
ext-pdo Version *
illuminate/container Version >=5.8
lcobucci/jwt Version ^3.2
league/fractal Version ~0.14
nwidart/laravel-modules Version >=3.1
predis/predis Version ^1.1
raml-org/raml-php-parser Version ^4.1