What is CI? What is CD?
CI – Continuous Integration – Continuous Integration Continuous integration (CI) is a software development method that requires team members to integrate work regularly. Every day, the members have to follow up and develop their work at least once. This will be automatically checked by another team, which will conduct retrieval testing to detect errors as quickly as possible. The team found that this approach alleviates more integration problems and allows for faster cohesive software development.
CD – Continuous Delivery Continuous Delivery is a continuous delivery, a set of techniques for implementing an integrated souce code on a staging environment (an environment very similar to production).
Config CI (phpcs, phpunit) for a simple Laravel project
1. Create the Laravel API
1. Create a laravel project
We just need to go to the terminal and run the following command
1 2 | composer create <span class="token operator">-</span> project <span class="token operator">--</span> prefer <span class="token operator">-</span> dist laravel <span class="token operator">/</span> laravel demo <span class="token operator">-</span> ci |
Next, the init project just created on git
1 2 3 4 5 6 7 8 | cd demo <span class="token operator">-</span> ci <span class="token operator">-</span> laravel git init git remote add origin <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> <span class="token punctuation">.</span> com <span class="token punctuation">:</span> lethu96 <span class="token operator">/</span> demo <span class="token operator">-</span> ci <span class="token punctuation">.</span> git git add <span class="token punctuation">.</span> git commit <span class="token operator">-</span> m <span class="token double-quoted-string string">"Init commit"</span> git push <span class="token operator">-</span> u origin master |
2. Config database
In this article SQLite will be used for testing and our main database. Usually, the main database is a more complex DBMS like MySQL or MSSQL but for simplicity’s sake. We will keep the configuration for the main database in the .env
file, and then create a .env.testing
file to keep the database configuration for testing.
In the nv.testing file we will configure the following:
1 2 3 4 5 6 7 | <span class="token constant">DB_CONNECTION</span> <span class="token operator">=</span> sqlite <span class="token constant">DB_HOST</span> <span class="token operator">=</span> <span class="token constant">null</span> <span class="token constant">DB_PORT</span> <span class="token operator">=</span> <span class="token constant">null</span> <span class="token constant">DB_DATABASE</span> <span class="token operator">=</span> database <span class="token operator">/</span> database <span class="token punctuation">.</span> sqlite <span class="token constant">DB_USERNAME</span> <span class="token operator">=</span> <span class="token constant">null</span> <span class="token constant">DB_PASSWORD</span> <span class="token operator">=</span> <span class="token constant">null</span> |
To be able to point to our SQLite database file as we have configured in the .env.testing
file, inside config/database.php
must also replace the SQLite configuration in the connections array with the config below:
1 2 3 4 5 6 | <span class="token single-quoted-string string">'sqlite'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'driver'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'sqlite'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'database'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token function">database_path</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'database.sqlite'</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'prefix'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">''</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> |
Then run the migrate command to check that our config was correct
1 2 | php artisan migrate |
Install token-based authentication with Passport
To authenticate authen I will use the laravel / passport package of Laravel
1 2 | composer <span class="token keyword">require</span> laravel <span class="token operator">/</span> passport v7 <span class="token punctuation">.</span> <span class="token number">5.1</span> |
After the installation is complete, run the migrate command again to configure the laravel / passport related tables:
1 2 | php artisan migrate |
Passport requires encryption keys to generate tokens, which need to be generated and stored in a database. To generate these keys, we run the command
1 2 | php artisan passport <span class="token punctuation">:</span> install |
After running the command successfully, you will see your Client secret
The next step is to add the LaravelPassportHasApiToken
trait to the AppUser
model. We will use the helper methods from package laravel/passport
to the app to help check user’s token and scopes. Open the file app/User.php
and replace its content with the code below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">App</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Notifications Notifiable</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Foundation Auth User</span> <span class="token keyword">as</span> Authenticatable <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Laravel Passport HasApiTokens</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">User</span> <span class="token keyword">extends</span> <span class="token class-name">Authenticatable</span> <span class="token punctuation">{</span> <span class="token keyword">use</span> <span class="token package">Notifiable</span> <span class="token punctuation">,</span> HasApiTokens <span class="token punctuation">;</span> <span class="token keyword">protected</span> <span class="token variable">$fillable</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'name'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'email'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'password'</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token keyword">protected</span> <span class="token variable">$hidden</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'password'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'remember_token'</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> </span> |
Next, we need to call the Passport::routes
method in the booth function of the app/Providers/AuthServiceProvider.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">App Providers</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Laravel Passport Passport</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Support Facades Gate</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Foundation Support Providers AuthServiceProvider</span> <span class="token keyword">as</span> ServiceProvider <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">AuthServiceProvider</span> <span class="token keyword">extends</span> <span class="token class-name">ServiceProvider</span> <span class="token punctuation">{</span> <span class="token keyword">protected</span> <span class="token variable">$policies</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'AppModel'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'AppPoliciesModelPolicy'</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">boot</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">registerPolicies</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> Passport <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">routes</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
The final configuration that Passport requires setting is the driver
option in the API authentication guard inside config / auth.php.
1 2 3 4 5 6 7 8 9 10 11 | <span class="token single-quoted-string string">'guards'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'web'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'driver'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'session'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'provider'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'users'</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'api'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'driver'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'passport'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'provider'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'users'</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> |
4. Create API endpoints
We will build a simple API for managing suser. User will have the following functions:
Sign up for a new account
Log in to their account using the user’s credentials
Fetch the user’s information
Sign out of the application
- First we need to declare the
routes/api.php
file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">use</span> <span class="token package">Illuminate Http Request</span> <span class="token punctuation">;</span> Route <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">group</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'prefix'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'auth'</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> Route <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">post</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'login'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">' <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> '</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> Route <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">post</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'signup'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">' <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> '</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> Route <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">group</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'middleware'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'auth:api'</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> Route <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'logout'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">' <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> '</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> Route <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">get</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'user'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">' <a class="__cf_email__" href="/cdn-cgi/l/email-protection">[email protected]</a> '</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> </span> |
- Next, create Controller
1 2 | php artisan make <span class="token punctuation">:</span> controller AuthController |
In AuthController we code the signup
, login
, logout
, and user
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">App Http Controllers</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Http Request</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Support Facades Auth</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Carbon Carbon</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">App User</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">AuthController</span> <span class="token keyword">extends</span> <span class="token class-name">Controller</span> <span class="token punctuation">{</span> <span class="token comment">/** * Create user * * @param [string] name * @param [string] email * @param [string] password * @param [string] password_confirmation * @return [string] message */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">signup</span> <span class="token punctuation">(</span> Request <span class="token variable">$request</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$request</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">validate</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'name'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'required|string'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'email'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'required|string|email|unique:users'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'password'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'required|string|confirmed'</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$user</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">User</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'name'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token variable">$request</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">name</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'email'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token variable">$request</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">email</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'password'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token function">bcrypt</span> <span class="token punctuation">(</span> <span class="token variable">$request</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">password</span> <span class="token punctuation">)</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$user</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">save</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">response</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'message'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'Successfully created user!'</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token number">201</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/** * Login user and create token * * @param [string] email * @param [string] password * @param [boolean] remember_me * @return [string] access_token * @return [string] token_type * @return [string] expires_at */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">login</span> <span class="token punctuation">(</span> Request <span class="token variable">$request</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$request</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">validate</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'email'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'required|string|email'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'password'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'required|string'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'remember_me'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'boolean'</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$credentials</span> <span class="token operator">=</span> <span class="token function">request</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'email'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'password'</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token operator">!</span> Auth <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">attempt</span> <span class="token punctuation">(</span> <span class="token variable">$credentials</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">response</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'message'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'Unauthorized'</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token number">401</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token variable">$user</span> <span class="token operator">=</span> <span class="token variable">$request</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">user</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$tokenResult</span> <span class="token operator">=</span> <span class="token variable">$user</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">createToken</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'Personal Access Token'</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$token</span> <span class="token operator">=</span> <span class="token variable">$tokenResult</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">token</span> <span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span> <span class="token variable">$request</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">remember_me</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$token</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">expires_at</span> <span class="token operator">=</span> Carbon <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">now</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">addWeeks</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token variable">$token</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">save</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">response</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'access_token'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token variable">$tokenResult</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">accessToken</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'token_type'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'Bearer'</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'expires_at'</span> <span class="token operator">=</span> <span class="token operator">></span> Carbon <span class="token punctuation">:</span> <span class="token punctuation">:</span> <span class="token function">parse</span> <span class="token punctuation">(</span> <span class="token variable">$tokenResult</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">token</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">expires_at</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">toDateTimeString</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/** * Logout user (Revoke the token) * * @return [string] message */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">logout</span> <span class="token punctuation">(</span> Request <span class="token variable">$request</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$request</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">user</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">token</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">revoke</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">response</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'message'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token single-quoted-string string">'Successfully logged out'</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">/** * Get the authenticated User * * @return [json] user object */</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">user</span> <span class="token punctuation">(</span> Request <span class="token variable">$request</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token function">response</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token variable">$request</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">user</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> </span> |
- Next, create a Unit test to test the API we just created
1 2 | php artisan make <span class="token punctuation">:</span> test UserTest |
In our UserTest
file will look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | <span class="token php language-php"><span class="token delimiter important"><?php</span> <span class="token keyword">namespace</span> <span class="token package">Tests Feature</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Tests TestCase</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Foundation Testing WithFaker</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">Illuminate Foundation Testing RefreshDatabase</span> <span class="token punctuation">;</span> <span class="token keyword">use</span> <span class="token package">App User</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">UserTest</span> <span class="token keyword">extends</span> <span class="token class-name">TestCase</span> <span class="token punctuation">{</span> <span class="token keyword">use</span> <span class="token package">WithFaker</span> <span class="token punctuation">;</span> <span class="token keyword">private</span> <span class="token variable">$password</span> <span class="token operator">=</span> <span class="token double-quoted-string string">"mypassword"</span> <span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">testUserCreation</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$name</span> <span class="token operator">=</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">faker</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">name</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$email</span> <span class="token operator">=</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">faker</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">email</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$response</span> <span class="token operator">=</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">postJson</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'/api/auth/signup'</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'name'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token variable">$name</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'email'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token variable">$email</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'password'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">password</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'password_confirmation'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">password</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$response</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">assertStatus</span> <span class="token punctuation">(</span> <span class="token number">201</span> <span class="token punctuation">)</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">assertExactJson</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'message'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token double-quoted-string string">"Successfully created user!"</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">//testUserCreation</span> <span class="token punctuation">}</span> </span> |
Then we run the test
1 2 3 | <span class="token punctuation">.</span> <span class="token operator">/</span> vendor <span class="token operator">/</span> bin <span class="token operator">/</span> phpunit |
2. Automate the test with CircleCI
It’s time to introduce the power of CI / CD into our Laravel API. I will create a pipeline to ensure that when we push new code, our tests will automatically run and we get the CI / CD successful or failed pipeline status. (go)
1.CircleCI
About CircleCI a bit:
CircleCI is a tool to help us realize CI. There are many other well-known CI tools (Travis CI, Jenkins …), the reason I chose Circle CI is just because it is quite simple and fully functional that I need.
CircleCI uses docker, in Circle CI configuration we will specify the docker image
to use and job
, in job
there are step
, in step
are specific command
. There is also a filter
configuration that allows us to flexibly adjust so that only jobs are run when there is a merge / push into certain branches and so on.
Description of the process of running 1 job on Circle CI:
Developers just need to push or merge into a branch, Circle CI automatically knows that event and boots up to the corresponding installed job. Initially the Circle CI pulls the docker image back and shakes it up in its cloud environment.
Next, it runs the installed steps in the docker container, usually the first step is always checkout i.e. git checkout gets the source (default saved in the ~ / project directory).
The next steps are run depending on your creativity, for example a job to build is usually npm install and then npm run abcxyz or a job to deploy, it may be aws s3 sync or serverless deploy …
After all the steps have been run, the job is finished. If the job’s exit code is error, by default we will receive a failed message again.
In short, after installing and configuring, you just need to build, run tests, deploy, and so on are completely automated and run instantly in the powerful free cloud environment of Circle CI.
1. Sign up for the plan
CircleCI provides users with 4 packages, here I will subscribe to the free package (because I have no skewers) you can see in the free package we have:
1500 minutes build
Unlimited repository and user
4x project build at the same time with public repository and 1x with private repository
After the installation is complete, it will move to the dashboard as follows:
2. Integration into the project
I will select the project created above demo-ci and then click setup project
Circleci supports us many languages like PHP, Java, .NET, Go, IOS, Android, Python …. here I will use PHP
1. Integrate into my laravel project
Create a .circleci
directory in the project In the .circleci
directory Create a file called config.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | <span class="token shell-comment comment"># PHP CircleCI 2.0 configuration file</span> <span class="token shell-comment comment">#</span> <span class="token shell-comment comment"># Check https:</span> <span class="token comment">//circleci.com/docs/2.0/language-php/ for more details</span> <span class="token shell-comment comment">#</span> version <span class="token punctuation">:</span> <span class="token number">2</span> jobs <span class="token punctuation">:</span> build <span class="token punctuation">:</span> docker <span class="token punctuation">:</span> <span class="token shell-comment comment"># Specify the version you desire here</span> <span class="token operator">-</span> image <span class="token punctuation">:</span> circleci <span class="token operator">/</span> php <span class="token punctuation">:</span> <span class="token number">7.1</span> <span class="token operator">-</span> node <span class="token operator">-</span> browsers <span class="token shell-comment comment"># Specify service dependencies here if necessary</span> <span class="token shell-comment comment"># CircleCI maintains a library of pre-built images</span> <span class="token shell-comment comment"># documented at https:</span> <span class="token comment">//circleci.com/docs/2.0/circleci-images/</span> <span class="token shell-comment comment"># Using the RAM variation mitigates I/O contention</span> <span class="token shell-comment comment"># for database intensive operations.</span> <span class="token shell-comment comment"># - image: circleci/mysql:5.7-ram</span> <span class="token shell-comment comment">#</span> <span class="token shell-comment comment"># - image: redis:2.8.19</span> steps <span class="token punctuation">:</span> <span class="token operator">-</span> checkout <span class="token operator">-</span> run <span class="token punctuation">:</span> sudo apt update <span class="token shell-comment comment"># PHP CircleCI 2.0 Configuration File# PHP CircleCI 2.0 Configuration File sudo apt install zlib1g-dev libsqlite3-dev</span> <span class="token operator">-</span> run <span class="token punctuation">:</span> sudo docker <span class="token operator">-</span> php <span class="token operator">-</span> ext <span class="token operator">-</span> install zip <span class="token shell-comment comment"># Download and cache dependencies</span> <span class="token operator">-</span> restore_cache <span class="token punctuation">:</span> keys <span class="token punctuation">:</span> <span class="token shell-comment comment"># "composer.lock" can be used if it is committed to the repo</span> <span class="token operator">-</span> v1 <span class="token operator">-</span> dependencies <span class="token operator">-</span> <span class="token punctuation">{</span> <span class="token punctuation">{</span> checksum <span class="token double-quoted-string string">"composer.json"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token shell-comment comment"># fallback to using the latest cache if no exact match is found</span> <span class="token operator">-</span> v1 <span class="token operator">-</span> dependencies <span class="token operator">-</span> <span class="token operator">-</span> run <span class="token punctuation">:</span> name <span class="token punctuation">:</span> <span class="token double-quoted-string string">"Install Dependencies"</span> command <span class="token punctuation">:</span> composer install <span class="token operator">-</span> n <span class="token operator">--</span> prefer <span class="token operator">-</span> dist <span class="token operator">-</span> save_cache <span class="token punctuation">:</span> key <span class="token punctuation">:</span> v1 <span class="token operator">-</span> dependencies <span class="token operator">-</span> <span class="token punctuation">{</span> <span class="token punctuation">{</span> checksum <span class="token double-quoted-string string">"composer.json"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> paths <span class="token punctuation">:</span> <span class="token operator">-</span> <span class="token punctuation">.</span> <span class="token operator">/</span> vendor <span class="token operator">-</span> restore_cache <span class="token punctuation">:</span> keys <span class="token punctuation">:</span> <span class="token operator">-</span> node <span class="token operator">-</span> v1 <span class="token operator">-</span> <span class="token punctuation">{</span> <span class="token punctuation">{</span> checksum <span class="token double-quoted-string string">"package.json"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator">-</span> node <span class="token operator">-</span> v1 <span class="token operator">-</span> <span class="token operator">-</span> run <span class="token punctuation">:</span> yarn install <span class="token operator">-</span> save_cache <span class="token punctuation">:</span> key <span class="token punctuation">:</span> node <span class="token operator">-</span> v1 <span class="token operator">-</span> <span class="token punctuation">{</span> <span class="token punctuation">{</span> checksum <span class="token double-quoted-string string">"package.json"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> paths <span class="token punctuation">:</span> <span class="token operator">-</span> node_modules <span class="token operator">-</span> run <span class="token punctuation">:</span> name <span class="token punctuation">:</span> <span class="token double-quoted-string string">"Create Environment file and generate app key"</span> command <span class="token punctuation">:</span> <span class="token operator">|</span> mv <span class="token punctuation">.</span> env <span class="token punctuation">.</span> testing <span class="token punctuation">.</span> env php artisan key <span class="token punctuation">:</span> generate <span class="token shell-comment comment"># prepare the database</span> <span class="token operator">-</span> run <span class="token punctuation">:</span> touch storage <span class="token operator">/</span> testing <span class="token punctuation">.</span> sqlite <span class="token operator">-</span> run <span class="token punctuation">:</span> php artisan migrate <span class="token operator">--</span> env <span class="token operator">=</span> testing <span class="token operator">--</span> database <span class="token operator">=</span> sqlite_testing <span class="token operator">--</span> force <span class="token operator">-</span> run <span class="token punctuation">:</span> name <span class="token punctuation">:</span> <span class="token double-quoted-string string">"Generate Passport encryption keys"</span> command <span class="token punctuation">:</span> php artisan passport <span class="token punctuation">:</span> install <span class="token shell-comment comment"># run tests with phpunit</span> <span class="token operator">-</span> run <span class="token punctuation">:</span> name <span class="token punctuation">:</span> <span class="token double-quoted-string string">"Run Tests"</span> command <span class="token punctuation">:</span> <span class="token punctuation">.</span> <span class="token operator">/</span> vendor <span class="token operator">/</span> bin <span class="token operator">/</span> phpunit |
After measuring we go to github click Start building to start building project. CircleCI will start running pipeline configuration. If you have followed the instructions correctly, you should have a successful build indicated by the screen below.
Perfect. We have been able to successfully power our Laravel API with a CI / CD pipeline that automatically runs tests using CircleCI.
We will add a test method fucntion login to the UserTest.php
file and push the code to see how CircleCI automatically runs our newly added test.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function">testUserLogin</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token variable">$name</span> <span class="token operator">=</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">faker</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">name</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$email</span> <span class="token operator">=</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">faker</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">email</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$user</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">User</span> <span class="token punctuation">(</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'name'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token variable">$name</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'email'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token variable">$email</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'password'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token function">bcrypt</span> <span class="token punctuation">(</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">password</span> <span class="token punctuation">)</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$user</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">save</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$response</span> <span class="token operator">=</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">postJson</span> <span class="token punctuation">(</span> <span class="token single-quoted-string string">'/api/auth/login'</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> <span class="token single-quoted-string string">'email'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token variable">$email</span> <span class="token punctuation">,</span> <span class="token single-quoted-string string">'password'</span> <span class="token operator">=</span> <span class="token operator">></span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token property">password</span> <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$response</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">assertStatus</span> <span class="token punctuation">(</span> <span class="token number">200</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token variable">$this</span> <span class="token operator">-</span> <span class="token operator">></span> <span class="token function">assertAuthenticated</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Now save the file, commit and push to GitHub. CircleCI will once again run the pipeline with the tests, including the test cases we just added.
Conclude
Reference source
https://circleci.com/blog/build-a-ci-powered-restful-api-with-laravel/