This is Slim 3 API skeleton project for Composer

Overview

Slim 3 API skeleton

Software License Build Status Coverage

This is Slim 3 API skeleton project for Composer. Project uses Zend Table Gateway and Phinx for database operations, Monolog for logging, and Fractal as a serializer. Vagrant virtualmachine config and Paw project files are included for easy development. The skeleton tries to follow DDD principles.

Install

Install the latest version using composer.

$ composer create-project --no-interaction --stability=dev tuupola/slim-api-skeleton app

Usage

If you have Vagrant installed start the virtual machine.

$ cd app
$ vagrant up

Now you can access the api at https://192.168.50.52/todos

Get a token

$ curl "https://192.168.50.52/token" \
    --request POST \
    --include \
    --insecure \
    --header "Content-Type: application/json" \
    --data '["todo.all"]' \
    --user test:test

HTTP/1.1 201 Created
Content-Type: application/json

{
    "token": "XXXXXXXXXX",
    "expires": 1491030210
}
$ export TOKEN=XXXXXXXXXX

Create a new todo

$ curl "https://192.168.50.52/todos" \
    --request POST \
    --include \
    --insecure \
    --header "Authorization: Bearer $TOKEN" \
    --header "Content-Type: application/json" \
    --data '{ "title": "Test the API", "order": 10 }'

HTTP/1.1 201 Created
ETag: "c39de417d4d1f5fe22d19cad68d672d8"
Last-Modified: Sat, 16 Apr 2016 10:21:50 GMT
Location: /todos/12Cf2ZjVvyu3A
Content-Type: application/json

{
    "data": {
        "uid": "12Cf2ZjVvyu3A",
        "order": 10,
        "title": "Test the API",
        "completed": false,
        "links": {
            "self": "/todos/12Cf2ZjVvyu3A"
        }
    }
}

Get an existing todo

$ curl "https://192.168.50.52/todos/12Cf2ZjVvyu3A" \
    --include \
    --insecure \
    --header "Authorization: Bearer $TOKEN"

HTTP/1.1 200 OK
ETag: "c39de417d4d1f5fe22d19cad68d672d8"
Last-Modified: Sat, 16 Apr 2016 10:21:50 GMT
Content-Type: application/json

{
    "data": {
        "uid": "12Cf2ZjVvyu3A",
        "order": 10,
        "title": "Test the API",
        "completed": false,
        "links": {
            "self": "/todos/12Cf2ZjVvyu3A"
        }
    }
}

Update part of an existing todo

$ curl "https://192.168.50.52/todos/12Cf2ZjVvyu3A" \
    --request PATCH \
    --include \
    --insecure \
    --header "Authorization: Bearer $TOKEN" \
    --header "Content-Type: application/json" \
    --header 'If-Match: "c39de417d4d1f5fe22d19cad68d672d8"' \
    --data '{ "order": 27 }'

HTTP/1.1 200 OK
ETag: "ab6070930158fc8323aa4550aff438b7"
Last-Modified: Sat, 16 Apr 2016 10:27:16 GMT
Content-Type: application/json

{
    "data": {
        "uid": "12Cf2ZjVvyu3A",
        "order": 27,
        "title": "Test the API",
        "completed": false,
        "links": {
            "self": "/todos/12Cf2ZjVvyu3A"
        }
    }
}

Fully update an existing todo

$ curl "https://192.168.50.52/todos/12Cf2ZjVvyu3A" \
    --request PUT \
    --include \
    --insecure \
    --header "Authorization: Bearer $TOKEN" \
    --header "Content-Type: application/json" \
    --header 'If-Match: "ab6070930158fc8323aa4550aff438b7"' \
    --data '{ "title": "Full update", "order": 66, "completed": true }'

HTTP/1.1 200 OK
ETag: "451665ea7769851880f411750bbd873c"
Last-Modified: Sat, 16 Apr 2016 10:28:45 GMT
Content-Type: application/json

{
    "data": {
        "uid": "12Cf2ZjVvyu3A",
        "order": 66,
        "title": "Full update",
        "completed": true,
        "links": {
            "self": "/todos/12Cf2ZjVvyu3A"
        }
    }
}

Delete an existing todo

$ curl "https://192.168.50.52/todos/12Cf2ZjVvyu3A" \
    --request DELETE \
    --include \
    --insecure \
    --header "Authorization: Bearer $TOKEN"

HTTP/1.1 204 No Content

License

The MIT License (MIT). Please see License File for more information.

Comments
  • Read Query Handler returns null

    Read Query Handler returns null

    Hi there,

    Great work on the Skeleton API!

    I'm new to Slim API and have been playing around and have duplicated the 'todos' table with an 'entries' table. The GET routing is working fine but I can't POST anything. I get the error 'Call to a member function getTimestamp() on null'.

    Debugging this leads me to $entry ($todo in your case) returning null in the following block of code (note that all handlers have been added to the dependencies file:

    $command = new CreateEntryCommand($data);
    $this->commandBus->handle($command);
    
    $query = new ReadEntryQuery($data);
    $entry = $this->commandBus->handle($query); // $entry returns NULL
    
    /* Add Last-Modified and ETag headers to response. */
    $response = $this->cache->withEtag($response, $entry->etag());
    $response = $this->cache->withLastModified($response, $entry->timestamp());
    

    Here's how the objects look like:

    $query:
    object(Skeleton\Application\Entry\ReadEntryQuery)#316 (1) {
      ["uid":"Skeleton\Application\Entry\ReadEntryQuery":private]=>
      string(13) "1E3HbNm2aHG7A"
    }
    
    $entry:
    object(Skeleton\Domain\Entry)#334 (6) {
      ["uid":"Skeleton\Domain\Entry":private]=>
      NULL
      ["order":"Skeleton\Domain\Entry":private]=>
      NULL
      ["completed":"Skeleton\Domain\Entry":private]=>
      bool(false)
      ["title":"Skeleton\Domain\Entry":private]=>
      NULL
      ["createdAt":"Skeleton\Domain\Entry":private]=>
      NULL
      ["updatedAt":"Skeleton\Domain\Entry":private]=>
      NULL
    }
    
    $data:
    array(3) {
      ["title"]=>
      string(25) "Testtttttttttttty the API"
      ["order"]=>
      int(10)
      ["uid"]=>
      string(13) "1E3HbNm2aHG7A"
    }
    
    

    When I print the $todo object in the todo POST route, I'm successfully getting data instead of NULL.

    Do you have any idea why this could be the case?

    question 
    opened by controlnocontrol 11
  • 500 internal server error due to php_value   always_populate_raw_post_data   -1

    500 internal server error due to php_value always_populate_raw_post_data -1

    I am getting 500 internal server error. my host support is saying it is because of

    php_value always_populate_raw_post_data -1 in .httaccess file.

    what does -1 means? how to fix this issue?

    Thanks

    opened by Fshamri 9
  • Uncaught TypeError: Argument 3 passed to Slim\\Handlers\\ApiError

    Uncaught TypeError: Argument 3 passed to Slim\\Handlers\\ApiError

    When some exceptions are throwed by Slim the ApiError handler can't handle it because the passed parameters are wrong.

    Uncaught TypeError: Argument 3 passed to Slim\Handlers\ApiError::__invoke() must be an instance of Slim\Handlers\Exception, instance of UnexpectedValueException given in /home/ieasrl/intranet/src/Slim/Handlers/ApiError.php:19

    For example if i upload the project to the server, create a virtualHost and i forgot to give 777 cmod permission to log folder this could happend.

    I can't understand what is really wrong or if ApiError must work different. So i have to comment handlers to see the error in apache log.

    Other error when handler.php is not commented is: [Thu Aug 10 10:16:44.159886 2017] [:error] [pid 14888] [client 10.0.2.247:51490] PHP Notice: Array to string conversion in /home/ieasrl/intranet/vendor/tuupola/dbal-psr3-logger/src/Psr3Logger.php on line 40

    bug 
    opened by pdrappo 7
  • Token not found

    Token not found

    I use the postman with auth basic authorization and user in headers test and password test with post method and in body of request like scope[] = todo.all and scope[] = todo.list, I received the answer statos => ok and the token. But in other request like /dump or /todos i received the answer "token not found".

    opened by IgorDePaula 7
  • Return value of Tuupola\\Middleware\\CorsMiddleware::origin() must be an instance of Tuupola\\Middleware\\void, none returned

    Return value of Tuupola\\Middleware\\CorsMiddleware::origin() must be an instance of Tuupola\\Middleware\\void, none returned

    Hi there,

    I'm trying to set up a basic test environment with on my hosting server. Everything was working fine but I'm suddenly getting a 500 error as indicated in the subject. Do you know what this is?

    Thanks!

    EDIT: Also, note that this is the second project I'm installing with the host. The first one had no issues at all.

    opened by controlnocontrol 4
  • vagrant time too long

    vagrant time too long

    hi,when I run vagrant The program stopped at "default: Waiting for machine to boot. This may take a few minutes..." .And this step has been going on for hours

    vagrant

    opened by wubin1836 4
  • array_intersect(): Argument #2 is not an array

    array_intersect(): Argument #2 is not an array

    I'm encountering an issue at line 16 of App\Token.php

    return !!count(array_intersect($scope, $this->decoded->scope));

    saying "array_intersect(): Argument #2 is not an array".

    opened by carlo-arellano 4
  • Cors information is not at the response header's when i throw an exception

    Cors information is not at the response header's when i throw an exception

    Hi, i dont know if this is an issue or not. May be i'm doing something wrong, but for example, when i try to login and get a token if the credentials are wrong i throw an exception like NotFoundException and this is passed to \Slim\Handlers\Error\ApiErrorwho handle the exception and gives response with a json object. The problem is that Cors information is not at the response header's when this path is taked in the code. How can i fix this. Thanks.

    $credentials = $request->getParsedBody();
    $mapper = $this->spot->mapper("App\Entities\Auth\User");
    
          // Selecciono el usuario
           $result = $mapper->where([
               'username' => $credentials['username'],
               'password' => md5($credentials['password'])
               ])->with('perms')->first();
    
           if(!$result){
             $data = array("status" => "error", "msg" => "");
             if($mapper->where(['username' => $credentials['username']])->first()){
                    $alert = ["type" => "danger", "message" => "La contraseña es incorrecta"];
               }else{
                    $alert = ["type" => "danger", "message" => "El usuario ingresado no existe."];
               }
    
    throw new NotFoundException($alert['message'], 401);
    
    opened by pdrappo 4
  • Spot2 Relations?

    Spot2 Relations?

    First, I would like to say how much I am loving this! I have used this to spin up like 3 APIs now in the blink of an eye. The latest one I am using requires me to have relationships built into my entities and I was wondering if that was possible with this setup? I did it just like it is in the Spot docs....here is my entity class:

    namespace App; use Spot\EntityInterface; use Spot\MapperInterface; use Spot\EventEmitter; use Tuupola\Base62; use Ramsey\Uuid\Uuid; use Psr\Log\LogLevel;

    class Chat extends \Spot\Entity { protected static $table = "chats"; public static function fields() { return [ "chat_id" => ["type" => "integer", "unsigned" => true, "primary" => true, "autoincrement" => true], "chat_event_id" => ["type" => "integer", "unsigned" => true], "chat_expires_at" => ["type" => "string", "length" => 100], "chat_created_at" => ["type" => "datetime", "value" => new \DateTime()], "chat_updated_at" => ["type" => "datetime", "value" => new \DateTime()] ]; } public static function events(EventEmitter $emitter) { $emitter->on("beforeUpdate", function (EntityInterface $entity, MapperInterface $mapper) { $entity->chat_updated_at = new \DateTime(); }); } public static function relations(MapperInterface $mapper, EntityInterface $entity) { return [ 'messages' => $mapper->hasMany($entity, 'App\ChatMessage', 'chat_message_chat_id')->order(['chat_message_created_at' => 'ASC']), ]; } public function timestamp() { return $this->chat_updated_at->getTimestamp(); } }

    and here is my Transformer class for Fractal:

    namespace App; use App\Chat; use League\Fractal; class ChatTransformer extends Fractal\TransformerAbstract { public function transform(Chat $chat) { return [ "chat_event_id" => (integer)$chat->chat_event_id ?: 0, "chat_expires_at" => (string)$chat->chat_expires_at ?: null, "chat_messages" => $chat->messages ]; } }

    Everything else is pretty much setup like you do in your examples. When I run this, I only get a blank for the 'chat_messages' return even though I know there should be something in there so I was just wondering if I was missing something.

    help wanted 
    opened by danielwlockhart 4
  • Too few arguments to function Skeleton\\Domain\\Token:

    Too few arguments to function Skeleton\\Domain\\Token:

    If I run any of the examples for example:

    curl "https://192.168.50.52/todos" \
        --request POST \
        --include \
        --insecure \
        --header "Authorization: Bearer INSERT-JWT-TOKEN-HERE" \
        --header "Content-Type: application/json" \
        --data '{ "title": "Test the API", "order": 10 }'
    

    Then I get this response

    {
      "title": "Too few arguments to function Skeleton\\Domain\\Token::__construct(), 0 passed in .../app/config/middleware.php on line 41 and exactly 1 expected",
      "type": "about:blank",
      "status": 500
    }
    
    

    I'm not sure what I'm doing wrong. I've tried everything including creating the database and adding tables and data for the todo's app. Thanks

    opened by timogoosen 3
  • [QUESTION] How to add MySQL ORDER BY

    [QUESTION] How to add MySQL ORDER BY

    I'm looking at the zend-db documentation and they indicate that ORDER BY is achieved with something like:

    $select = new Select;
    $select->order('id DESC'); // produces 'id' DESC
    

    Your ZendTodoRepository all function seems to always expect an array. Was your framework set up with ORDER BY in mind? How can we achieve this?

    opened by controlnocontrol 3
  • JWT support

    JWT support

    can you add JWT support and URL like URL/login URL/register URL/status //will get all the status only if he is authenticated or 403 error will be thrown

    opened by seifkh97 2
  • Question: How to deal with insert queries and table joins?

    Question: How to deal with insert queries and table joins?

    In let's say to Todo class, I need to add a property from another table via JOIN. This works well through the hydrator, transformer classes etc. However how do I deal with the CreateQuery and CreateHandler classes? It's required to pass the joined property which obviously doesn't exist in the table.

    I was able to unset the property in the ZendRepo but this somehow doesn't feel elegant. Is there any way you recommend to approach this?

    opened by controlnocontrol 0
  • Update to Slim 4?

    Update to Slim 4?

    Thank you for this awesome skeleton-project.

    Have you planned to do an update to make it slim 4 compatible and with the (new) best practices ?

    I would be highly interested by it.

    opened by samuelgfeller 2
  • New version not working after installation ?

    New version not working after installation ?

    Hi Tuupola, I was trying out composer create-project --no-interaction --stability=dev tuupola/slim-api-skeleton app. Then when I tried to run I got this output

    <?php
    
    require __DIR__ . "/../app.php";
    

    What else settings can I run to enable it properly? Secondly where should I put the route file now in this new version because in my older version I had everything in src folder both the middleware and routes file?

    opened by learnme2019 1
  • How set dynamic database host names

    How set dynamic database host names

    Current below is my settings.php

    [ 'displayErrorDetails' => true, // set to false in production 'addContentLengthHeader' => false, // Allow the web server to send the content-length header // Renderer settings 'renderer' => [ 'template_path' => __DIR__ . '/../templates/', ], // Monolog settings 'logger' => [ 'name' => 'slim-app', 'path' => isset($_ENV['docker']) ? 'php://stdout' : __DIR__ . '/../logs/app.log', 'level' => \Monolog\Logger::DEBUG, ], "db" => [ "host" => "localhost", "dbname" => "***", "user" => "***1", "pass" => "***" ], ], ]; With this settings it works perfectly in the route when I called this e.g. $selectQueryResult1 = $this->db->prepare($selectQuery1) The issue now I will want to have many different database e.g. db1, db2; when I set new settings in the settings file I always get this error /var/www/html/apiv1/vendor/slim/slim/Slim/Container.php(172): Slim\Container->get('db1') How can I set and call those extra database settings?
    opened by newbie14 0
  • Zend TableGateway can't execute 2 consecutive query

    Zend TableGateway can't execute 2 consecutive query

    Hi Guys,

    Firtsly, I'm sorry if I miss placed the question. After weeks learning the framework with this skeleton, I just desperate facing this issue.

    It seems I can't run 2 consecutive query using TableGateway. It's always produce (not just UPDATE):

    "Statement couldn't be produced with sql: UPDATE `users` SET `last_access` = NOW() WHERE `id` = ?"
    

    Here's the code inside ZendUserRepository:

    ...
        public function footprint(int $id): void {
            $data = ['last_access' => new Predicate\Expression('NOW()')];
            $where = ['id' => $id];
            $this->table->update($data, $where);
        }
        
        public function authenticate(string $username, string $password): bool {
            $where = [
                'username' => $username,
                new Predicate\IsNotNull('roles')
            ];
            $rowset = $this->table->select($where);
            if (null === $row = $rowset->current()) {
                return false;
            }
            $data = (array) $row;
            if(password_verify($password, $data['password'])) {
                $this->footprint($data['id']);
                return true;
            }
            return false;
        }
    ...
    

    Please, kindly help this newbie here.

    Best Regards, Adit

    bug 
    opened by aditbisa 3
Owner
Mika Tuupola
Mika Tuupola
Slim Framework 4 Skeleton Application

Slim Framework 4 Skeleton Application Use this skeleton application to quickly setup and start working on a new Slim Framework 4 application. This app

Cleonildo Soares Guimaraes Junior 5 Nov 21, 2021
Simple skeleton for the PHP Slim framework

Simple skeleton for the PHP Slim framework

Andrew S Erwin 2 Nov 13, 2021
Use this skeleton application to quickly setup and start working on a new Slim Framework 4 application

Slim Framework 4 Skeleton Application Use this skeleton application to quickly setup and start working on a new Slim Framework 4 application. This app

Slim Framework 1.5k Dec 25, 2022
SPA Skeleton with Mithril.js and Slim Framework

A single-page application (SPA) skeleton based on Mithril.js and Slim Framework 4 trying to use good practices

tebe 5 Oct 23, 2022
Project skeleton generator for Laravel & Lumen projects

Skeletor Skeletor is a PHP based CLI tool that has been built to take away the pain of setting up a base project skeleton for Laravel & Lumen projects

Wouter 39 Oct 4, 2022
A skeleton WordPress project to be used as a base for new WordPress projects.

BoxUK WordPress Project Skeleton A base WordPress project from Box UK to get you up and running quickly. Installation Create a new project with compos

Box UK 33 Dec 14, 2022
CodeIgniter 4-based application skeleton

Bonfire 2 Just getting started. More details at Patreon What is Bonfire? Bonfire will be a robust application skeleton for CodeIgniter 4-based applica

Lonnie Ezell 79 Dec 25, 2022
A skeleton for creating applications with CakePHP 4.x.

CakePHP Application Skeleton A skeleton for creating applications with CakePHP 4.x. The framework source code can be found here: cakephp/cakephp. Inst

Fabiano Araujo 1 Oct 13, 2021
A skeleton for build your Kata with Docker

A skeleton for build your Kata with Docker

Raúl Coloma Bonifacio 1 Nov 12, 2021
Reverse proxy skeleton built for docker with traefik, showcasing a Symfony + React application

Decoupled Backend(Symfony) + Frontend(React ts) built with Traefik & Docker Reverse proxy skeleton built for docker with traefik, showcasing a decoupl

Sergiu 1 Dec 13, 2021
⚡️ This package provides a wonderful PHP skeleton to start building your next package idea.

This package provides a wonderful PHP Skeleton to start building your next package idea. Requires PHP 8.0+ ⚡️ Create your package using Composer: comp

Nuno Maduro 383 Dec 20, 2022
This repository is pre-configured, clean and empty skeleton for creating a new projects using Kraken Framework.

Kraken Application Skeleton Note: This repository contains pre-configured application skeleton for fast creation of new projects with Kraken Framework

Kraken 79 Aug 6, 2022
A skeleton application using the Zend Framework MVC

This is a skeleton application using the Zend Framework MVC layer and module systems. This application is meant to be used as a starting place for those looking to get their feet wet with Zend Framework.

Zend Framework 1.5k Dec 15, 2022
Boilerplate for Slim Framework 3

Boilerplate for Slim Framework 3 Boilerplate for getting started with Slim Framework Use this skeleton application to quickly setup and start working

Yudi Purwanto 23 Dec 27, 2022
Symfony React Blank is a blank symfony and react project, use this template to start your app using Symfony as an backend api and React as a frontend library.

Symfony React Blank Symfony React Blank is a blank symfony and react project, use this template to start your app using Symfony as an backend api and

Antoine Kingue 2 Nov 5, 2021
Laravel API starter Kit will provide you with the tools for making API's that everyone will love

Laravel API Starter Kit Laravel API starter Kit will provide you with the tools for making API's that everyone will love, API Authentication is alread

Jose Luis Fonseca 400 Dec 29, 2022
A Laravel 5.8 API Boilerplate to create a ready-to-use REST API in seconds.

Laravel API Boilerplate (JWT Edition) for Laravel 5.8 Laravel API Boilerplate is a "starter kit" you can use to build your first API in seconds. As yo

Francesco Malatesta 1.2k Dec 18, 2022
Hydra is a zero-config API boilerplate with Laravel Sanctum that comes with excellent user and role management API out of the box

Hydra - Zero Config API Boilerplate with Laravel Sanctum Hydra is a zero-config API boilerplate with Laravel Sanctum and comes with excellent user and

Hasin Hayder 858 Dec 24, 2022
The Laravel Boilerplate Project - https://laravel-boilerplate.com

Laravel Boilerplate (Current: Laravel 8.*) (Demo) Demo Credentials Admin: [email protected] Password: secret User: [email protected] Password: secret Offici

Anthony Rappa 5.4k Jan 4, 2023