<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: pcreem</title>
    <description>The latest articles on DEV Community by pcreem (@pcreem).</description>
    <link>https://dev.to/pcreem</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F463582%2Fda5cca56-f430-484f-bc57-19924d880f05.png</url>
      <title>DEV Community: pcreem</title>
      <link>https://dev.to/pcreem</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pcreem"/>
    <language>en</language>
    <item>
      <title>Create the first phpunit test</title>
      <dc:creator>pcreem</dc:creator>
      <pubDate>Thu, 15 Apr 2021 05:27:46 +0000</pubDate>
      <link>https://dev.to/pcreem/create-the-first-phpunit-test-1aj9</link>
      <guid>https://dev.to/pcreem/create-the-first-phpunit-test-1aj9</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Note: phpunit9 doesn't support php8^, it compatible with php7.4&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;clone the repo: &lt;a href="https://github.com/pcreem/psr-4Autoload"&gt;https://github.com/pcreem/psr-4Autoload&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;install phpunit 
&lt;code&gt;$composer require --dev phpunit/phpunit ^9&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$./vendor/bin/phpunit --version
PHPUnit 9.0.0 by Sebastian Bergmann and contributors. 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$code composer.json&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "autoload": {
        "psr-4": {
            "App\\":"App/"
        }
    },
    "require-dev": {
        "phpunit/phpunit": "^9"
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$code App/Data/Database.php&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
namespace App\Data;

class Database {
    public function sayHi()
    {
        return 'create database\n';
    }
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$code tests/DatabaseTest.php&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use App\Data\Database;

final class DatabaseTest extends TestCase
{
    public function testCanCreateDatabase(): void
    {
        $database = new Database();
        $this-&amp;gt;assertSame('create database\n', $database-&amp;gt;sayHi());
    }
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;code&gt;$./vendor/bin/phpunit --testdox tests&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;output&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PHPUnit 9.5.4 by Sebastian Bergmann and contributors.

Database
 ✔ Can create database
the init

Time: 00:00.006, Memory: 4.00 MB

OK (1 test, 1 assertion)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;repo: &lt;a href="https://github.com/pcreem/theFirstPhpUnitTest"&gt;https://github.com/pcreem/theFirstPhpUnitTest&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Write a simple PSR-4 autoload</title>
      <dc:creator>pcreem</dc:creator>
      <pubDate>Mon, 22 Mar 2021 08:07:45 +0000</pubDate>
      <link>https://dev.to/pcreem/write-a-simple-psr-4-autoload-1nl3</link>
      <guid>https://dev.to/pcreem/write-a-simple-psr-4-autoload-1nl3</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$mkdir App
$mkdir App/Data
$code App/Data/Database.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;App/Data/Database.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
namespace App\Data;

class Database {
    public function __construct()
    {
        echo "the init\n";
    }

    public function sayHi()
    {
        echo "create database\n";
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;$code composer.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "autoload": {
        "psr-4": {
            "App\\":"App/"
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;$code index.php&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php
require __DIR__ . '/vendor/autoload.php';
use App\Data\Database;

$obj  = new Database();

echo $obj-&amp;gt;sayHi();
?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;$composer dump&lt;/code&gt;&lt;br&gt;
&lt;code&gt;$php index.php&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;the init
create database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;repo: &lt;a href="https://github.com/pcreem/psr-4Autoload"&gt;https://github.com/pcreem/psr-4Autoload&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Create mysql user and database </title>
      <dc:creator>pcreem</dc:creator>
      <pubDate>Tue, 02 Mar 2021 01:29:05 +0000</pubDate>
      <link>https://dev.to/pcreem/create-mysql-user-and-database-4119</link>
      <guid>https://dev.to/pcreem/create-mysql-user-and-database-4119</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$sudo mysql
mysql&amp;gt; CREATE USER 'newuser'@'localhost' IDENTIFIED BY 'password';
mysql&amp;gt; GRANT ALL PRIVILEGES ON * . * TO 'newuser'@'localhost';
mysql&amp;gt; \q

//login as newuser
$mysql -u newuser -p
mysql&amp;gt; CREATE DATABASE databasename; 

//option create table
mysql&amp;gt; CREATE TABLE Persons (
    PersonID int,
    LastName varchar(255),
    FirstName varchar(255),
    Address varchar(255),
    City varchar(255)
);

//insert multiple data
INSERT INTO table_name (column_list)
VALUES
    (value_list_1),
    (value_list_2),
    ...
    (value_list_n);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>PHP8 constructor type test experiment</title>
      <dc:creator>pcreem</dc:creator>
      <pubDate>Sat, 20 Feb 2021 07:57:09 +0000</pubDate>
      <link>https://dev.to/pcreem/php8-constructor-type-test-experiment-1b5l</link>
      <guid>https://dev.to/pcreem/php8-constructor-type-test-experiment-1b5l</guid>
      <description>&lt;p&gt;PHP8 simplify constructor method from&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//php7 version
class Point {
  public float $x;
  public float $y;
  public float $z;

  public function __construct(
    float $x = 0.0,
    float $y = 0.0,
    float $z = 0.0
  ) {
    $this-&amp;gt;x = $x;
    $this-&amp;gt;y = $y;
    $this-&amp;gt;z = $z;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class Point {
  public function __construct(
    public float $x = 0.0,
    public float $y = 0.0,
    public float $z = 0.0,
  ) {}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;write a simple case&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php    
    class Point {
        public function __construct(
          public string $name
        ) {}

        public function returnVal(){
            return $this-&amp;gt;name;
        }
    }

    $testClass = new Point('the string case');
    print $testClass-&amp;gt;returnVal();
?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;the string case
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;check array in string test&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;turn &lt;code&gt;'the string case'&lt;/code&gt; to &lt;code&gt;['the string case']&lt;/code&gt; &lt;br&gt;
The output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PHP Fatal error:  Uncaught TypeError: Point::__construct(): Argument #1 ($name) must be of type string, array given
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;works well&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;check number in string test&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;turn &lt;code&gt;'the string case'&lt;/code&gt; to &lt;code&gt;123&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;The output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;123
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's no type error warning. &lt;br&gt;
add &lt;code&gt;declare(strict_types=1);&lt;/code&gt; to the top of code&lt;br&gt;
The output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PHP Fatal error:  Uncaught TypeError: Point::__construct(): Argument #1 ($name) must be of type string, int given
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Build a simple Laravel API</title>
      <dc:creator>pcreem</dc:creator>
      <pubDate>Tue, 09 Feb 2021 10:38:46 +0000</pubDate>
      <link>https://dev.to/pcreem/build-a-simple-laravel-api-1lfb</link>
      <guid>https://dev.to/pcreem/build-a-simple-laravel-api-1lfb</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A Controller with an API&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$laravel new simpleAPI
$cd simpleAPI
$php artisan make:controller dummyAPI
$code app/Http/Controllers/dummyAPI.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;app/Http/Controllers/dummyAPI.php&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class dummyAPI extends Controller
{
    function getData(){
        return ["name"=&amp;gt;"alice"];
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;routes/api.php&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\dummyAPI;

Route::middleware('auth:api')-&amp;gt;get('/user', function (Request $request) {
    return $request-&amp;gt;user();
});

Route::get("data",[dummyAPI::class,'getData']);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;$php artisan serve&lt;/code&gt;&lt;br&gt;
Get &lt;a href="http://127.0.0.1:8000/api/data"&gt;http://127.0.0.1:8000/api/data&lt;/a&gt; on Postman or Browser&lt;br&gt;
&lt;em&gt;the output&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "name": "alice"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Controller plus Model and API&lt;br&gt;
create database and table, use mysql as example&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql&amp;gt; create database dummy;
$php artisan make:model Dummy -rmc
Model created successfully.
Created Migration: 2021_02_09_094710_create_dummies_table
Controller created successfully.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;modify database/migrations/2021_02_09_094710_create_dummies_table.php&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  public function up()
    {
        Schema::create('dummies', function (Blueprint $table) 
        {
            $table-&amp;gt;id();
            $table-&amp;gt;string('name');
            $table-&amp;gt;timestamps();
        });
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;migrate and insert data&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$php artisan migrate
mysql&amp;gt; use dummy;
mysql&amp;gt; insert into dummies(name) values ('dummy1');
mysql&amp;gt; insert into dummies(name) values ('dummy2');
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;modify routes/api.php&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\DummyController;

Route::middleware('auth:api')-&amp;gt;get('/user', function (Request $request) {
    return $request-&amp;gt;user();
});

Route::get("data",[DummyController::class,'show']);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;run &lt;code&gt;php artisan serve&lt;/code&gt;&lt;br&gt;
Get &lt;a href="http://127.0.0.1:8000/api/data"&gt;http://127.0.0.1:8000/api/data&lt;/a&gt; on Postman or Browser&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
    {
        "id": 1,
        "name": "dummy1",
        "created_at": null,
        "updated_at": null
    },
    {
        "id": 2,
        "name": "dummy2",
        "created_at": null,
        "updated_at": null
    }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;CRUD API&lt;/p&gt;

&lt;p&gt;&lt;em&gt;CREATE&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;edit &lt;br&gt;
app/Http/Controllers/DummyController.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//add this to top of the code
use Symfony\Component\HttpFoundation\Response as Res;

...

    public function store(Request $request)
    {
        $dummy = Dummy::create($request-&amp;gt;all());
        $dummy = $dummy-&amp;gt;refresh();
        return response($dummy,Res::HTTP_CREATED);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;edit app/Models/Dummy.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class dummy extends Model
{
    use HasFactory;

    protected $fillable = [
        'name'
    ];
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;add&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Route::apiResource('dummy',DummyController::class);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(optional) Install REST client on VS code&lt;br&gt;
create dummy.http&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST http://127.0.0.1:8000/api/dummy HTTP/1.1
content-type:application/json

{
    "name":"henry"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;click send request&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//result
{
  "id": 3,
  "name": "henry",
  "created_at": "2021-02-10T04:15:28.000000Z",
  "updated_at": "2021-02-10T04:15:28.000000Z"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;DELETE&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;edit app/Http/Controllers/DummyController.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public function destroy(dummy $dummy)
    {
        $dummy-&amp;gt;delete();
        return response(null, RES::HTTP_NO_CONTENT);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;send request in dummy.http&lt;br&gt;
&lt;code&gt;DELETE http://127.0.0.1:8000/api/dummy/1&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;UPDATE&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;edit app/Http/Controllers/DummyController.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  public function update(Request $request, dummy $dummy)
    {
        $dummy-&amp;gt;update($request-&amp;gt;all());
        return response($dummy,RES::HTTP_OK);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;send request in dummy.http&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PATCH http://127.0.0.1:8000/api/dummy/2 HTTP/1.1
content-type:application/json

{
    "name":"the modify one"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;READ&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;read single data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;edit app/Http/Controllers/DummyController.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  public function show(dummy $dummy)
    {
        return response($dummy,RES::HTTP_OK);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;send request in dummy.http&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET http://127.0.0.1:8000/api/dummy/2 
content-type:application/json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;read all data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;edit app/Http/Controllers/DummyController.php&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   public function index()
    {
        $dummy = Dummy::get();
        return response(['data' =&amp;gt; $dummy], Res::HTTP_OK);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;send request in dummy.http&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET http://127.0.0.1:8000/api/dummy
content-type:application/json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;repo: &lt;a href="https://github.com/pcreem/basicLaravelApi"&gt;https://github.com/pcreem/basicLaravelApi&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>how to load data from txt file into mysql</title>
      <dc:creator>pcreem</dc:creator>
      <pubDate>Mon, 01 Feb 2021 03:53:12 +0000</pubDate>
      <link>https://dev.to/pcreem/how-to-load-data-from-txt-file-into-mysql-3i58</link>
      <guid>https://dev.to/pcreem/how-to-load-data-from-txt-file-into-mysql-3i58</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;create database, table&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql&amp;gt;CREATE DATABASE pet;
mysql&amp;gt;USE pet;
mysql&amp;gt;CREATE TABLE pet (name VARCHAR(20), owner VARCHAR(20), species VARCHAR(20), sex CHAR(1), birth DATE, death DATE);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;create data in pet.txt (use \N to represent null data)&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Whistler        Gwen    bird    \N      1997-12-09      \N
Bowser  Diane   dog     m       1979-08-31      1995-07-29

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;logout mysql and login with --local-infile=1 parameter&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql --local-infile=1 -u user -p
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;load data and check result&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql&amp;gt;USE pet;
mysql&amp;gt;LOAD DATA LOCAL INFILE '/path/pet.txt' INTO TABLE pet;
mysql&amp;gt;select * from pet;

+----------+-------+---------+------+------------+------------+
| name     | owner | species | sex  | birth      | death      |
+----------+-------+---------+------+------------+------------+
| Whistler | Gwen  | bird    | NULL | 1997-12-09 | NULL       |
| Bowser   | Diane | dog     | m    | 1979-08-31 | 1995-07-29 |
+----------+-------+---------+------+------------+------------+
2 rows in set (0.04 sec)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;reference:&lt;br&gt;
&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/loading-tables.html"&gt;https://dev.mysql.com/doc/refman/8.0/en/loading-tables.html&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Install Laravel on Ubuntu</title>
      <dc:creator>pcreem</dc:creator>
      <pubDate>Thu, 28 Jan 2021 10:27:49 +0000</pubDate>
      <link>https://dev.to/pcreem/how-to-install-laravel-on-ubuntu-19l7</link>
      <guid>https://dev.to/pcreem/how-to-install-laravel-on-ubuntu-19l7</guid>
      <description>&lt;p&gt;&lt;strong&gt;install php&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$sudo apt install zip unzip software-properties-common
$sudo add-apt-repository ppa:ondrej/php
$sudo apt install -y php8.0 php8.0-gd php8.0-mbstring php8.0-xml php-zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Apache2&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$sudo apt install apache2 libapache2-mod-php8.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;MySQL&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$sudo apt install mysql-server php8.0-mysql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;(optional) Upgrade composer 2.0&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$sudo apt install curl
$curl -sS https://getcomposer.org/installer -o composer-setup.php
$sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Laravel installer&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$composer global require laravel/installer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Edit Laravel path&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$cd~
$nano .bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;add &lt;code&gt;export PATH=$PATH:$HOME/.config/composer/vendor/bin&lt;/code&gt; to last line&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$source ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;create &amp;amp; run project&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$laravel new {project name}
$php artisan serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;open &lt;a href="http://127.0.0.1:8000"&gt;http://127.0.0.1:8000&lt;/a&gt; on browser&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(optional) VScode&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$sudo snap install --classic code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
    </item>
    <item>
      <title>Cypress next-auth mail authentication  </title>
      <dc:creator>pcreem</dc:creator>
      <pubDate>Sun, 11 Oct 2020 12:04:01 +0000</pubDate>
      <link>https://dev.to/pcreem/cypress-next-auth-mail-authentication-57f0</link>
      <guid>https://dev.to/pcreem/cypress-next-auth-mail-authentication-57f0</guid>
      <description>&lt;p&gt;Authentication with email could simplify the signup process and prevent password mistakes. In the topic, we will use &lt;a href="https://next-auth.js.org/getting-started/example" rel="noopener noreferrer"&gt;next-auth&lt;/a&gt; default email authentication method and test the workflow via cypress.&lt;/p&gt;

&lt;p&gt;For quick start: &lt;a href="https://github.com/pcreem/cypressAuth" rel="noopener noreferrer"&gt;repo&lt;/a&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;point check before cypress testing, make sure you can get the following results&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;after signup with an email, a notification on the webpage
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fa1cfuqzhu9lfh29457i6.png" alt="homepage"&gt;
&lt;/li&gt;
&lt;li&gt;an email notification in Mailtrap inbox
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F001gq79lvzqnfjgvlppw.png" alt="Mailtrap inbox"&gt;
&lt;/li&gt;
&lt;li&gt;webpage turn to login state with httpOnly cookie
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbelpwqjeu2rq19g9mwhx.png" alt="login"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  cypress authentication work flow
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Aim to solve the following test:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;send an email after a user signup&lt;/li&gt;
&lt;li&gt;check the email has been received&lt;/li&gt;
&lt;li&gt;make sure the email contains the link to the homepage&lt;/li&gt;
&lt;li&gt;click the link in email redirect to the homepage &lt;/li&gt;
&lt;li&gt;make sure the page turn to login state&lt;/li&gt;
&lt;li&gt;keep user login after page refresh &lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Setting up
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npx yarn add cypress&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;optional&lt;/em&gt; &lt;code&gt;npx yarn add faker&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A user signup with an email &lt;code&gt;code .\cypress\integration\sample_spec.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const faker = require('faker');
const randomEmail = faker.internet.email().toLowerCase();

describe('Login Test', () =&amp;gt; {

    it('Visits the test page', () =&amp;gt; {
      cy.visit('http://localhost:3000')
      cy.contains('Sign in').click()
      cy.url().should('include', '/api/auth/signin')

      cy.get('#input-email-for-email-provider')
        .type(randomEmail)
        .should('have.value', randomEmail)

        cy.contains('Sign in with Email').click()
        cy.contains('Check your email')

    });

    it('should send an email containing a verification link', () =&amp;gt; {
        const inboxUrl = Cypress.env('inboxUrl')
        const token  = Cypress.env('Api-Token')

        cy.getLastEmail().then(html =&amp;gt; {

          const link = html.match(/href="([^"]*)/)[1]
          cy.expect(link).to.contains('/api/auth/callback/email')
          cy.visit(link);
          cy.contains(`Signed in as ${randomEmail}`)
          cy.reload()
          cy.contains(`Signed in as ${randomEmail}`)
          //delete all mail
          cy.request({
            method: 'PATCH',
            url: `${inboxUrl}/clean`,
            headers: {
                'Api-Token': token,
                }
            });
        });
      });
  })


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;API interacts with Mailtrap to get last mail 
&lt;code&gt;code .\cypress\support\commands.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const inboxUrl = Cypress.env('inboxUrl')
const token  = Cypress.env('Api-Token')

Cypress.Commands.add('getLastEmail', () =&amp;gt; {
    function requestEmail() {
      return cy
        .request({
          method: 'GET',
          url: `${inboxUrl}/messages`,
          headers: {
            'Api-Token': token,
          },
          json: true,
        })
        .then(({ body }) =&amp;gt; {

          if (body) {

            let msgId = body[0].id
            cy.request({
            method: 'GET',
            url: `${inboxUrl}/messages/${msgId}/body.html`,
            headers: {
                'Api-Token': token,
            },
            json: true,
            }).then(({ body }) =&amp;gt; { 
                if (body) { return body }

                cy.wait(1000);  
                return requestEmail();
            })
          }
        });
    }

    return requestEmail();
  });

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  configuration
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;code cypress.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;there could have network problems during the test, use "retries" to retry the test will save your time, visit cypress page for &lt;a href="https://docs.cypress.io/guides/guides/test-retries.html#Introduction" rel="noopener noreferrer"&gt;more info&lt;/a&gt;&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "retries": 3 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;code cypress.env.json&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "inboxUrl":"Your Mailtrap Inbox url with inboxId",
    "Api-Token":"Your Mailtrap API token"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npx cypress open&lt;/code&gt;&lt;/li&gt;
&lt;li&gt; run sample_spec.js test&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;the result should like this&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F11y8jjbwgwhs8kcnj5yv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F11y8jjbwgwhs8kcnj5yv.png" alt="cypress open"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;make a automatical process&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;npx yarn add start-server-and-test&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npx start-server-and-test 'next dev' 3000 'cypress run'&lt;/code&gt;
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fes2y7570m8qbfxt7mteg.png" alt="cypress run"&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>node</category>
      <category>cypress</category>
    </item>
    <item>
      <title>Use cache to catch data without page refresh</title>
      <dc:creator>pcreem</dc:creator>
      <pubDate>Sun, 13 Sep 2020 06:43:49 +0000</pubDate>
      <link>https://dev.to/pcreem/use-cache-to-catch-data-without-page-refresh-1c5e</link>
      <guid>https://dev.to/pcreem/use-cache-to-catch-data-without-page-refresh-1c5e</guid>
      <description>&lt;h1&gt;
  
  
  &lt;a href="https://react-todo-orcin.vercel.app/"&gt;demo&lt;/a&gt;
&lt;/h1&gt;

&lt;h1&gt;
  
  
  problem aim to solve
&lt;/h1&gt;

&lt;p&gt;In a React todo-list development page, data can't update synchronously with CRUD in the database. Users need to refresh the browser to get the latest information, which made a stuck browser experience. Here gonna use cache, which is a temporary data storage location, and todo-list create/delete to make the problem solve example. &lt;/p&gt;

&lt;h1&gt;
  
  
  prerequisite
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;GraphQL client &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://formidable.com/open-source/urql/"&gt;urql&lt;/a&gt;: a GraphQL client &lt;/li&gt;
&lt;li&gt;@urql/exchange-graphcache: for cache setting&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/graphql-tag"&gt;graphql-tag&lt;/a&gt;: a utility for parsing GraphQL queries&lt;/li&gt;
&lt;li&gt;React / react-bootstrap (optional)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://dev.to/pcreem/build-a-graphql-todolist-server-on-prisma-postgresql-2j63"&gt;GraphQL server&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  conceptual code
&lt;/h1&gt;

&lt;h3&gt;
  
  
  a. set component, todo create/delete GraphQL queries
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;code .\src\components\todo.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from 'react'
import gql from 'graphql-tag';
import { useQuery, useMutation } from 'urql';
import { InputGroup, FormControl, Button, Col, Row, Alert, Spinner } from 'react-bootstrap'; //optional

export const FEED_QUERY = gql` //show latest info
  query{
    info{
        id
        title
      }
  }
`;

const UPSERT_POST = gql` //exexute todo create 
  mutation upsertPost( $postId:ID!, $title: String!) {
    upsertPost( postId: $postId, title: $title) {
      id
      title
    }
  }
`

const DELETE_POST = gql`
  mutation deletePost($postId:ID!) {
    deletePost(postId: $postId) {
      id
    }
  }
`

const PostForm = (props) =&amp;gt; {
  //Upsert Section
  let postId = 0
  const [title, setTitle] = React.useState('')

  const [upsertState, executeUpsert] = useMutation(UPSERT_POST)
  const upsert = React.useCallback(() =&amp;gt; {
    if (title.length !== 0 &amp;amp;&amp;amp; title.length &amp;lt;= 30) { executeUpsert({ postId, title }); }
  }, [executeUpsert, postId, title])

  return (
    &amp;lt;Col sm={8}&amp;gt;
      &amp;lt;InputGroup className="mb-3"&amp;gt;
        &amp;lt;FormControl
          placeholder='Add Todo...'
          aria-label="Recipient's username"
          aria-describedby="basic-addon2"
          maxLength="30"
          value={title}
          onChange={e =&amp;gt; setTitle(e.target.value)}
        /&amp;gt;
        &amp;lt;InputGroup.Append&amp;gt;
          &amp;lt;Button
            variant="outline-secondary"
            disabled={upsertState.fetching}
            type="submit"
            onClick={() =&amp;gt; { upsert(); setTitle('') }}
          &amp;gt;Add&amp;lt;/Button&amp;gt;
        &amp;lt;/InputGroup.Append&amp;gt;{'  '}
      &amp;lt;/InputGroup&amp;gt;
    &amp;lt;/Col&amp;gt;
  )
}

function Post({ post }) {
  //Delete Section
  const postId = post.id
  const [deleteState, executeDelete] = useMutation(DELETE_POST)
  const del = React.useCallback(() =&amp;gt; {
    executeDelete({ postId })
  }, [executeDelete, postId])

  return (
    &amp;lt;Col &amp;gt;
      &amp;lt;Alert variant="light" disabled={deleteState.fetching} onClose={() =&amp;gt; { del(); }} dismissible&amp;gt;
        &amp;lt;p&amp;gt;{post.title}&amp;lt;/p&amp;gt;
      &amp;lt;/Alert&amp;gt;
    &amp;lt;/Col&amp;gt;
  )
}



const PostList = () =&amp;gt; {
  const [result] = useQuery({ query: FEED_QUERY })
  const { data, fetching, error } = result

  if (fetching) return &amp;lt;&amp;gt;&amp;lt;Spinner animation="border" role="status"&amp;gt;&amp;lt;span className="sr-only"&amp;gt;Loading...&amp;lt;/span&amp;gt;&amp;lt;/Spinner&amp;gt;&amp;lt;/&amp;gt;

  if (error) return &amp;lt;div&amp;gt;Error&amp;lt;/div&amp;gt;

  const postsToRender = data.info
  return (
    &amp;lt;&amp;gt;
      {postsToRender.map(post =&amp;gt; &amp;lt;Post key={post.id} post={post} /&amp;gt;)}
    &amp;lt;/&amp;gt;
  );
};

const Todo = (props) =&amp;gt; {
  return (
    &amp;lt;&amp;gt;
      &amp;lt;br&amp;gt;&amp;lt;/br&amp;gt;
      &amp;lt;Row className="justify-content-md-center"&amp;gt;
        &amp;lt;PostForm /&amp;gt;
      &amp;lt;/Row&amp;gt;
      &amp;lt;hr&amp;gt;&amp;lt;/hr&amp;gt;
      &amp;lt;Row className="justify-content-md-center"&amp;gt;
        &amp;lt;PostList /&amp;gt;
      &amp;lt;/Row&amp;gt;
    &amp;lt;/&amp;gt;
  )

}

export default Todo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  b. cache setting
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;code .\src\index.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//...React setting
import { Provider, Client, dedupExchange, fetchExchange } from 'urql'
import { cacheExchange } from '@urql/exchange-graphcache'
import { FEED_QUERY } from './components/todo.js'

const cache = cacheExchange({
  updates: {
    Mutation: { 
      upsertPost: (result, args, cache, info) =&amp;gt; {  //execute create todo 
        cache.updateQuery({ query: FEED_QUERY }, data =&amp;gt; { //update the latest information in cache 
          if (data !== null) {
            data.info.unshift(result.upsertPost);
            return data;
          } else {
            return null
          }
        });
      },
      deletePost: (result, args, cache, info) =&amp;gt; { // execute delete todo
        cache.invalidate({ __typename: 'Post', id:  result.deletePost.id }); //delete todo in cache
      },
    },
  },
});

const client = new Client({
  url: '/',
  fetchOptions: () =&amp;gt; {
    //...your fetch setting
  },
  exchanges: [dedupExchange, cache, fetchExchange],
}) 

ReactDOM.render(
  &amp;lt;Provider value={client}&amp;gt;
    &amp;lt;App /&amp;gt;
  &amp;lt;/Provider&amp;gt;,
  document.getElementById('root')
)

serviceWorker.unregister();

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  note
&lt;/h1&gt;

&lt;p&gt;The todo-list will get user-related data in the &lt;a href="https://react-todo-orcin.vercel.app/"&gt;demo&lt;/a&gt;, code is not shown here. You could write a todo-only code to experience the cache effect.   &lt;/p&gt;

</description>
      <category>react</category>
      <category>graphql</category>
    </item>
    <item>
      <title>use httpOnly/sameSite cookie to make JWT authentication safer (local experiment)</title>
      <dc:creator>pcreem</dc:creator>
      <pubDate>Sat, 12 Sep 2020 11:10:19 +0000</pubDate>
      <link>https://dev.to/pcreem/use-httponly-samesite-secure-cookie-token-on-graphql-server-local-experiment-9od</link>
      <guid>https://dev.to/pcreem/use-httponly-samesite-secure-cookie-token-on-graphql-server-local-experiment-9od</guid>
      <description>&lt;h1&gt;
  
  
  the pros and cons of storing token in local storage
&lt;/h1&gt;

&lt;p&gt;One of the common ways to store a token on the front end is local-storage with the benefit of larger store sizes than a cookie and operate without a server. But the method also bring &lt;a href="https://owasp.org/www-community/attacks/xss/" rel="noopener noreferrer"&gt;XSS&lt;/a&gt; an &lt;a href="https://owasp.org/www-community/attacks/csrf" rel="noopener noreferrer"&gt;CSRF&lt;/a&gt; attack concern, such as &lt;br&gt;
&lt;code&gt;&amp;lt;img src="http://domain.not.exist" onerror=alert(localStorage.getItem.token);&amp;gt;&lt;br&gt;
&lt;/code&gt; &lt;/p&gt;

&lt;h1&gt;
  
  
  another token storage possibility
&lt;/h1&gt;

&lt;p&gt;XSS execute by script, CSRF works when the original cookie sent to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy" rel="noopener noreferrer"&gt;origin URL&lt;/a&gt; from different domains. To add more difficulty to XSS and CSRF is &lt;a href="https://owasp.org/www-community/HttpOnly" rel="noopener noreferrer"&gt;httpOnly&lt;/a&gt; and &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite" rel="noopener noreferrer"&gt;sameSite&lt;/a&gt; setting in the cookie. The cookie secure parameter makes data only transfer over the HTTPS protocol, which makes &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/MitM" rel="noopener noreferrer"&gt;MitM&lt;/a&gt; attack not easily execute. &lt;/p&gt;

&lt;h1&gt;
  
  
  prerequisite
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;A React login page with GraphQL client &lt;/li&gt;
&lt;li&gt;
&lt;a href="]https://ngrok.com/"&gt;ngrok&lt;/a&gt; in React root folder&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/pcreem/build-a-graphql-todolist-server-on-prisma-postgresql-2j63"&gt;GraphQL server &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  conceptual code and setting
&lt;/h1&gt;

&lt;h3&gt;
  
  
  A. server side
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;code ./resolvers/mutation.js&lt;/code&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

async function login(parent, args, context, info) {
  //...user email/password verification
  const token = jwt.sign({ userId: user.id }, APP_SECRET)
  const options = {
    maxAge: 1000 * 60 * 15 , //expires in 15 minutes
    httpOnly: true, // client can't get cookie by script
    secure: true, // only transfer over https
    sameSite: true, // only sent for requests to the same FQDN as the domain in the cookie
  }
  context.request.res.cookie('token', token, options)

//Can't get token at the first client login request
  const returnToken = () =&amp;gt; context.request.headers.cookie

  let { userId } = jwt.verify(returnToken().replace('token=', ''), APP_SECRET)
  if (userId === user.id) {
    console.log('ok') //checking result on server console
    return {
      user, //send user information to client
    }
  }
  throw new Error('Invalid request')

}

module.exports = { login }



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;please note the code can't get a cookie token at the first client request&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  B. Client-side
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;add to the end of &lt;code&gt;code package.json&lt;/code&gt;
```
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;...&lt;br&gt;
  },&lt;br&gt;
  "proxy": "&lt;a href="http://localhost:4000" rel="noopener noreferrer"&gt;http://localhost:4000&lt;/a&gt;"&lt;br&gt;
}&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;_After adding proxy and run on local, there will be a hosting error, which needs a configuration in .env. Remember to change your server API URL setting accordingly._

* `code .env`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DANGEROUSLY_DISABLE_HOST_CHECK=true&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**The setting is dangerous as it named, please don't use it in production**  

### C. Start project 
* on server
`node index.js`

* on client
`npm start`
`.\ngrok.exe http 3000`

### D. Check result 
1. copy the ngrok **https** URL to the browser, then run your login on the client, if setting success, you will see 
  * the result on the Application field. The httpOnly, secure field should be marked and sameSite field named with strict
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/w5w5xwjhnhnuu25ratjq.png)
  * an error on your server
`TypeError: Cannot read property 'replace' of undefined`
The reason is the login function can't send and get a cookie in the first client request.

2. send a login request again, there will be an `ok` on the server console, which means the server get token in the cookie. 

3. The client will get user information after token verify. In the case is a todo page. 
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/jiqcwk298gzbs6actmkl.png)

### E. test httpOnly/https effect
* httpOnly: you can write a javascript to get the cookie 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;import Cookies from 'js-cookie'&lt;br&gt;
export const getToken = () =&amp;gt; Cookies.get(AUTH_TOKEN);&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* https: use localhost:3000 or ngrok Http URL to test

# Issues and [Reference](https://medium.com/@ryanchenkie_40935/react-authentication-how-to-store-jwt-in-a-cookie-346519310e81)
1. Solve cookie token res/req in a more efficient way
2. Set refresh cookie for a smooth user experience
3. how/where to store and transfer user data 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>httponly</category>
      <category>graphql</category>
      <category>token</category>
    </item>
    <item>
      <title>Build a GraphQL Todolist server on Prisma/PostgreSQL</title>
      <dc:creator>pcreem</dc:creator>
      <pubDate>Wed, 09 Sep 2020 12:09:06 +0000</pubDate>
      <link>https://dev.to/pcreem/build-a-graphql-todolist-server-on-prisma-postgresql-2j63</link>
      <guid>https://dev.to/pcreem/build-a-graphql-todolist-server-on-prisma-postgresql-2j63</guid>
      <description>&lt;h2&gt;
  
  
  &lt;a href="https://github.com/pcreem/graphqlTodoServer"&gt;Github&lt;/a&gt; and &lt;a href="https://prisma--deploy.herokuapp.com/"&gt;Demo&lt;/a&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Brief intro about GraphQL and Prisma
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://graphql.org/"&gt;GraphQL&lt;/a&gt; is developed by Facebook in 2015. On the Client side, It makes nest data fetching easier by JSON like interface (as the image above),  rather than multiple URLs or ORM/database request. On the Server side, you can update the data model by add or delete row at the aging field.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.prisma.io/"&gt;Prisma&lt;/a&gt; is an alternative ORM and SQL query builder.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The following will show how to build a GraphQL backend from scratch.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  prerequisites: 
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nodejs.org/en/"&gt;Node.js&lt;/a&gt; installed on your machine&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt; database server running&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A. setup database: 
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;mkdir todo &lt;br&gt;
mkdir todo/backend &lt;br&gt;
cd todo/backend&lt;br&gt;
npm init -y &lt;br&gt;
npm install @prisma/cli - save-dev&lt;br&gt;
npx prisma init&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  database model:
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;code ./prisma/schema.prisma&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model Post {
  id        Int      @default(autoincrement()) @id
  createdAt DateTime @default(now())
  title     String
  content   String? //question mark means opational
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
}

model User {
  id       Int     @default(autoincrement()) @id
  email    String  @unique
  name     String?
  password String
  posts    Post[]
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;code ./prisma/.env&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DATABASE_URL=postgresql://USER:PASSWORD@HOST:PORT/DATABASE
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h4&gt;
  
  
  Prisma Migrate:
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;npx prisma migrate save --name init --experimental &lt;br&gt;
npx prisma migrate up --experimental&lt;br&gt;
npx prisma generate&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  B. Build server
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;npm i graphql-yoga @prisma/client &lt;br&gt;
code index.js&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { PrismaClient } = require('@prisma/client')
const prisma = new PrismaClient()
const { GraphQLServer } = require('graphql-yoga')

const Query = require('./resolvers/query.js')
const Mutation = require('./resolvers/mutation.js')
const User = require('./resolvers/user.js')
const Post = require('./resolvers/post.js')

const resolvers = {
  Query,
  Mutation,
  User,
  Post
}

const server = new GraphQLServer({
  typeDefs: './schema.graphql',
  resolvers,
  context: request =&amp;gt; {
    return {
      ...request,
      prisma,
    }
  },
})

const PORT = process.env.PORT || 4000
server.start(PORT, () =&amp;gt; console.log(`Server is running on http://localhost:4000`))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;typeDefs&lt;/code&gt; connect to the schema wrote at the t section. It defined the database path, data type,  and the relation between them.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;resolvers&lt;/code&gt; defined how to deal with data in each relevant script. For example, Query responsible for fetching data, Mutation for CRUD/ Signup/Login function, we will deal with it later. The rest two (User and Post in resolvers field) define data relations. &lt;/li&gt;
&lt;li&gt;The &lt;code&gt;context&lt;/code&gt; contains custom data being passed through your resolver chain.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  C. Build typeDefs, resolvers, and user identification
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;define typeDefs
&lt;code&gt;code schema.graphql&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type Query {
  info: [Post!]!
}

type Mutation {
  upsertPost (postId:ID!, title: String!, content: String): Post!
  deletePost (postId:ID!): Post

  signup(email: String!, password: String!, name: String!): AuthPayload
  login(email: String!, password: String!): AuthPayload
}

type Post {
  id: ID!
  title: String!
  content: String
  author:    User
  createdAt: String!
}

type AuthPayload {
  token: String
  user: User
}

type User {
  id: ID!
  name: String
  email: String!
  posts: [Post]
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;define resolvers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;npm i jsonwebtoken bcryptjs dotenv&lt;/code&gt;&lt;br&gt;
&lt;code&gt;mkdir resolvers&lt;/code&gt;&lt;br&gt;
&lt;code&gt;code ./resolvers/query.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { getUserId } = require('../utils')

function info(parent, args, context, info) {
  const userId = getUserId(context)
  const Posts = context.prisma.post.findMany({
    where: {
      authorId: parseInt(userId)
    }
  })

  return Posts
}


module.exports = {
  info
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;code ./resolvers/mutation.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { getUserId } = require('../utils')
const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')
require('dotenv').config()
const APP_SECRET = process.env.APP_SECRET

function upsertPost(parent, args, context, info) {
  const userId = getUserId(context)
  const upsertPost = context.prisma.post.upsert({
    where: {
      id: parseInt(args.postId)
    },
    update: {
      title: args.title,
      content: args.content,
    },
    create: {
      title: args.title,
      content: args.content,
      author: {
        connect: { id: parseInt(userId) },
      },
    },
  })

  return upsertPost
}


function deletePost(parent, args, context, info) {
  const deletePost = context.prisma.post.delete({

    where: {
      id: parseInt(args.postId),
    },
  })

  return deletePost
}

async function signup(parent, args, context, info) {
  const password = await bcrypt.hash(args.password, 10)
  const user = await context.prisma.user.create({ data: { ...args, password } })
  const token = jwt.sign({ userId: user.id }, APP_SECRET)

  return {
    token,
    user,
  }
}

async function login(parent, args, context, info) {
  const user = await context.prisma.user.findOne({ where: { email: args.email } })
  if (!user) {
    throw new Error('No such user found')
  }
  const valid = await bcrypt.compare(args.password, user.password)
  if (!valid) {
    throw new Error('Invalid password')
  }
  const token = jwt.sign({ userId: user.id }, APP_SECRET)

  return {
    token,
    user,
  }
}

module.exports = {
  upsertPost,
  deletePost,

  signup,
  login,
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;code ./resolvers/user.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function posts(parent, args, context) {
  return context.prisma.user.findOne({ where: { id: parent.id } }).posts()
}

module.exports = {
  posts,
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;code ./resolvers/post.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function author(parent, args, context) {
  return context.prisma.post.findOne({ where: { id: parent.id } }).author()
}

module.exports = {
  author,
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The four scrips function have short explained on the above second item (The resolvers).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build a helper to handle user identification
&lt;code&gt;code utils.js&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const jwt = require('jsonwebtoken')
require('dotenv').config()
const APP_SECRET = process.env.APP_SECRET

function getUserId(context) {
  const Authorization = context.request.get('Authorization')
  if (Authorization) {
    const token = Authorization.replace('Bearer ', '')
    const { userId } = jwt.verify(token, APP_SECRET)
    return userId
  }

  throw new Error('Not authenticated')
}

module.exports = {
  getUserId,
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;code .env&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;APP_SECRET = Your_APP_SECRET
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  D. Start GraphQL server
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;node index.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;you could try the following command on GraphQL left column&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;signup&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mutation {
  signup(
    name: "__yourname__"
    email: "__your@email.com__"
    password: "__yourpassword__"
  ) {
    token
    user {
      id
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;login&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mutation {
  login(
    email: "__your@email.com__"
    password: "__yourpassword__"
  ) {
    token
    user {
      id
      name
      posts{
        id
        title
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;em&gt;add todo&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;a. copy token to Header(bottom left)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ "Authorization": "Bearer __Token__" }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;b. command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mutation {
  upsertPost(
    postId:"0"
    title: "www.graphqlconf.org"
  ) {
    id
    titile
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;delete todo&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mutation {
  deletePost(
    postId:"__Id__" //enter todo id
  ) {
    id
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>graphql</category>
      <category>node</category>
    </item>
  </channel>
</rss>
