├── .editorconfig ├── .env.ci ├── .env.example ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── dependabot.yml └── workflows │ └── test.yml ├── .gitignore ├── .php_cs.dist ├── .styleci.yml ├── LICENSE ├── README.md ├── app ├── Console │ ├── Commands │ │ └── .gitkeep │ └── Kernel.php ├── Enums │ └── ResponseCode.php ├── Events │ ├── Event.php │ └── ExampleEvent.php ├── Exceptions │ └── Handler.php ├── Http │ ├── Controllers │ │ ├── AuthController.php │ │ ├── Controller.php │ │ └── UsersController.php │ ├── Middleware │ │ └── Authenticate.php │ └── Resources │ │ └── UserResource.php ├── Jobs │ ├── ExampleJob.php │ └── Job.php ├── Listeners │ └── ExampleListener.php ├── Models │ └── User.php ├── Providers │ ├── AppServiceProvider.php │ ├── AuthServiceProvider.php │ └── EventServiceProvider.php ├── Services │ └── UserService.php └── Support │ ├── Traits │ ├── Helpers.php │ └── SerializeDate.php │ └── helpers.php ├── artisan ├── bootstrap └── app.php ├── composer.json ├── composer.lock ├── config ├── app.php ├── auth.php └── response.php ├── database ├── database.sqlite ├── factories │ ├── PostFactory.php │ └── UserFactory.php ├── migrations │ ├── .gitkeep │ ├── 2020_05_30_115810_create_users_table.php │ └── 2020_10_16_105234_create_posts_table.php └── seeders │ ├── DatabaseSeeder.php │ └── UsersSeeder.php ├── phpunit.xml ├── public ├── .htaccess └── index.php ├── resources ├── lang │ └── zh_CN │ │ └── enums.php └── views │ └── .gitkeep ├── routes └── web.php ├── storage ├── app │ └── .gitignore ├── framework │ ├── cache │ │ ├── .gitignore │ │ └── data │ │ │ └── .gitignore │ └── views │ │ └── .gitignore └── logs │ └── .gitignore └── tests ├── ExampleTest.php ├── Feature └── ExampleTest.php ├── TestCase.php ├── Traits └── CreatesApplication.php └── Unit └── ExampleTest.php /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.{yml,yaml}] 15 | indent_size = 2 16 | -------------------------------------------------------------------------------- /.env.ci: -------------------------------------------------------------------------------- 1 | APP_NAME=lumen-api-starter 2 | APP_ENV=testing 3 | APP_KEY=kcTV8pvNMZUenldwhxRglPII85Xbkbwa 4 | APP_DEBUG=true 5 | APP_URL=http://lumen-api-starter.test 6 | APP_TIMEZONE=Asia/Shanghai 7 | APP_LOCALE=zh-CN 8 | 9 | DB_CONNECTION=sqlite 10 | DB_DATABASE=database/database.sqlite 11 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | APP_NAME=Lumen 2 | APP_ENV=local 3 | APP_KEY= 4 | APP_DEBUG=true 5 | APP_URL=http://localhost 6 | APP_TIMEZONE=UTC 7 | 8 | LOG_CHANNEL=stack 9 | LOG_SLACK_WEBHOOK_URL= 10 | 11 | DB_CONNECTION=mysql 12 | DB_HOST=127.0.0.1 13 | DB_PORT=3306 14 | DB_DATABASE=homestead 15 | DB_USERNAME=homestead 16 | DB_PASSWORD=secret 17 | 18 | CACHE_DRIVER=file 19 | QUEUE_CONNECTION=sync 20 | 21 | JWT_SECRET= -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "composer" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | push: 4 | branches: 5 | - main 6 | jobs: 7 | tests: 8 | name: Tests 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v2 14 | - name: Setup PHP 15 | uses: shivammathur/setup-php@v2 16 | with: 17 | php-version: 8.1 18 | tools: pecl 19 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite,json,redis,mongodb 20 | coverage: none 21 | - name: Validate composer.json and composer.lock 22 | run: composer validate 23 | - name: Cache Composer packages 24 | id: composer-cache 25 | uses: actions/cache@v2 26 | with: 27 | path: vendor 28 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} 29 | restore-keys: | 30 | ${{ runner.os }}-php- 31 | - name: Install dependencies 32 | if: steps.composer-cache.outputs.cache-hit != 'true' 33 | run: composer install --prefer-dist --no-progress --no-suggest --ignore-platform-reqs 34 | - name: Copy ENV Configuration for CI 35 | run: php -r "file_exists('.env') || copy('.env.ci', '.env');" 36 | - name: Create DB and schemas 37 | run: | 38 | mkdir -p database 39 | touch database/database.sqlite 40 | php artisan migrate 41 | - name: Execute tests (Unit and Feature tests) via PHPUnit 42 | run: vendor/bin/phpunit 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /.idea 3 | Homestead.json 4 | Homestead.yaml 5 | .env 6 | .phpunit.result.cache 7 | .php_cs.cache 8 | -------------------------------------------------------------------------------- /.php_cs.dist: -------------------------------------------------------------------------------- 1 | 12 | 13 | This source file is subject to the MIT license that is bundled 14 | with this source code in the file LICENSE. 15 | EOF; 16 | 17 | $finder = PhpCsFixer\Finder::create() 18 | ->exclude('vendor') 19 | ->exclude('tests/Fixtures') 20 | ->in(__DIR__) 21 | ->append([__DIR__.'/php-cs-fixer']); 22 | 23 | $rules = [ 24 | '@PSR2' => true, 25 | // PHPDoc should contain `@param` for all params. 26 | 'phpdoc_add_missing_param_annotation' => ['only_untyped'=>false], 27 | // Annotations in PHPDoc should be ordered so that `@param` annotations come first, then `@throws` annotations, then `@return` annotations. 28 | 'phpdoc_order' => false, 29 | // Annotations in PHPDoc should be grouped together so that annotations of the same type immediately follow each other, and annotations of a different type are separated by a single blank line. 30 | 'phpdoc_separation' => false, 31 | // There should not be a binary flag before strings. 32 | 'no_binary_string' => true, 33 | // Replace control structure alternative syntax to use braces. 34 | 'no_alternative_syntax' => true, 35 | // There should be no empty lines after class opening brace. 36 | 'no_blank_lines_after_class_opening' => true, 37 | // There should not be blank lines between docblock and the documented element. 38 | 'no_blank_lines_after_phpdoc' => true, 39 | // There must be a comment when fall-through is intentional in a non-empty case body. 40 | 'no_break_comment' => true, 41 | // The closing `? >` tag MUST be omitted from files containing only PHP. 42 | 'no_closing_tag' => true, 43 | // There should not be any empty comments. 44 | 'no_empty_comment' => true, 45 | // There should not be empty PHPDoc blocks. 46 | 'no_empty_phpdoc' => true, 47 | // Remove useless semicolon statements. 48 | 'no_empty_statement' => true, 49 | // Removes extra blank lines and/or blank lines following configuration. 50 | 'no_extra_blank_lines' => true, 51 | // Remove leading slashes in `use` clauses. 52 | 'no_leading_import_slash' => true, 53 | // The namespace declaration line shouldn't contain leading whitespace. 54 | 'no_leading_namespace_whitespace' => true, 55 | // Either language construct `print` or `echo` should be used. 56 | 'no_mixed_echo_print' => true, 57 | // Operator `=>` should not be surrounded by multi-line whitespaces. 58 | 'no_multiline_whitespace_around_double_arrow' => true, 59 | // Short cast `bool` using double exclamation mark should not be used. 60 | 'no_short_bool_cast' => true, 61 | // Replace short-echo ` true, 63 | // Single-line whitespace before closing semicolon are prohibited. 64 | 'no_singleline_whitespace_before_semicolons' => true, 65 | // When making a method or function call, there MUST NOT be a space between the method or function name and the opening parenthesis. 66 | 'no_spaces_after_function_name' => true, 67 | // There MUST NOT be spaces around offset braces. 68 | 'no_spaces_around_offset' => true, 69 | // There MUST NOT be a space after the opening parenthesis. There MUST NOT be a space before the closing parenthesis. 70 | 'no_spaces_inside_parenthesis' => true, 71 | // Replaces superfluous `elseif` with `if`. 72 | 'no_superfluous_elseif' => true, 73 | // PHP arrays should be declared using the configured syntax.ƒ 74 | 'array_syntax' => ['syntax'=>'short'], 75 | // Binary operators should be surrounded by space as configured. 76 | 'binary_operator_spaces' => true, 77 | // There MUST be one blank line after the namespace declaration. 78 | 'blank_line_after_namespace' => true, 79 | // Ensure there is no code on the same line as the PHP open tag and it is followed by a blank line. 80 | 'blank_line_after_opening_tag' => true, 81 | // An empty line feed must precede any configured statement. 82 | 'blank_line_before_statement' => true, 83 | // The body of each structure MUST be enclosed by braces. Braces should be properly placed. Body of braces should be properly indented. 84 | 'braces' => true, 85 | // A single space or none should be between cast and variable. 86 | 'cast_spaces' => true, 87 | // Class, trait and interface elements must be separated with one blank line. 88 | 'class_attributes_separation' => true, 89 | // Whitespace around the keywords of a class, trait or interfaces definition should be one space. 90 | 'class_definition' => true, 91 | // Concatenation should be spaced according configuration. 92 | 'concat_space' => true, 93 | // The PHP constants `true`, `false`, and `null` MUST be written using the correct casing. 94 | 'constant_case' => true, 95 | // Equal sign in declare statement should be surrounded by spaces or not following configuration. 96 | 'declare_equal_normalize' => ['space'=>'single'], 97 | // The keyword `elseif` should be used instead of `else if` so that all control keywords look like single words. 98 | 'elseif' => true, 99 | // PHP code MUST use only UTF-8 without BOM (remove BOM). 100 | 'encoding' => true, 101 | // Each line of multi-line DocComments must have an asterisk [PSR-5] and must be aligned with the first one. 102 | 'align_multiline_comment' => true, 103 | // Each element of an array must be indented exactly once. 104 | 'array_indentation' => true, 105 | // Using `isset($var) &&` multiple times should be done in one call. 106 | 'combine_consecutive_issets' => true, 107 | // Calling `unset` on multiple items should be done in one call. 108 | 'combine_consecutive_unsets' => true, 109 | // Remove extra spaces in a nullable typehint. 110 | 'compact_nullable_typehint' => true, 111 | // Escape implicit backslashes in strings and heredocs to ease the understanding of which are special chars interpreted by PHP and which not. 112 | 'escape_implicit_backslashes' => true, 113 | // Converts backtick operators to `shell_exec` calls. 114 | 'backtick_to_shell_exec' => true, 115 | // Orders the elements of classes/interfaces/traits. 116 | 'ordered_class_elements' => ['sortAlgorithm'=>'alpha'], 117 | 'header_comment' => ['header' => $header], 118 | ]; 119 | 120 | $config = PhpCsFixer\Config::create() 121 | ->setRiskyAllowed(true) 122 | ->setRules($rules) 123 | ->setFinder($finder); 124 | 125 | return $config; 126 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | php: 2 | preset: laravel 3 | disabled: 4 | - unused_use 5 | js: true 6 | css: true 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Jiannei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lumen Api Starter Designed With ❤️ 2 | 3 | 基于最新版本的 Lumen 基础构建的一个**基础功能**完备,**规范统一**,能够**快速**应用于实际的 API 项目开发启动模板。同时,也希望通过**合理的**架构设计使其适用于中大型项目。 4 | 5 | 少许的依赖安装,遵循 Laravel 的思维进行扩展,不额外增加「负担」。 6 | 7 | 开箱即用,加速 Api 开发。 8 | 9 | ![StyleCI build status](https://github.styleci.io/repos/267924989/shield) 10 | ![Test](https://github.com/Jiannei/lumen-api-starter/workflows/Test/badge.svg?branch=main) 11 | 12 | ### 社区讨论传送 13 | 14 | - [是时候使用 Lumen 8 + API Resource 开发项目了!](https://learnku.com/articles/45311) 15 | - [一篇 RESTful API 路由设计的最佳实践](https://learnku.com/articles/45526) 16 | - [教你更优雅地写 API 之「规范响应数据」](https://learnku.com/articles/52784) 17 | - [教你更优雅地写 API 之「枚举使用」](https://learnku.com/articles/53015) 18 | - [教你更优雅地写 API 之「记录日志」](https://learnku.com/articles/53669) 19 | 20 | ## 概览 21 | 22 | ### 说明 23 | 24 | 开始了解本项目前,引用一段[官方说明](https://lumen.laravel.com/docs/10.x/installation#installation) 25 | 26 | > 在发布Lumen后的几年里,PHP进行了各种出色的性能改进。因此,随着Laravel Octane的推出,我们不再建议您使用Lumen开始新项目。相反,我们建议始终使用Laravel开始新项目。 27 | 28 | 项目会继续更新维护,当中使用到 package 也会继续更新同时支持 laravel/lumen 新版本。API 规范没有严格意义上的标准,能适用于团队,让项目更好维护的规范就是好的规范,欢迎一起讨论。 29 | 30 | 项目laravel版本[传送地址](https://github.com/jiannei/laravel-api-starter) 31 | 32 | ### 支持情况 33 | 34 | - RESTful 规范的HTTP 响应结构:成功、失败、异常场景统一结构响应;多语言提示返回 35 | - 更为便捷地使用枚举/常量 36 | - Jwt-auth 方式授权 37 | - Repository & Service」架构设计参考 38 | 39 | ### 目录结构 40 | 41 | ``` 42 | ├── app 43 | │ ├── Console 44 | │ │ ├── Commands // cli command:通常用于实现轮询任务 45 | │ │ └── Kernel.php // Schedule 调度 46 | │ ├── Contracts // 定义 interface 47 | │ ├── Enums // 定义枚举:要求php8.1以上版本,且laravel9.x以上版本 https://laravel.com/docs/9.x/releases#enum-casting 48 | │ │ └── ResponseCode.php 49 | │ ├── Events // 事件处理 50 | │ │ ├── Event.php 51 | │ │ └── ExampleEvent.php 52 | │ ├── Exceptions // 异常处理:结合 jiannei/laravel-response,可以更方便处理异常信息响应 53 | │ │ └── Handler.php 54 | │ ├── Http 55 | │ │ ├── Controllers // Controller 层根据 Request 将任务分发给不同 Service 处理,返回响应给客户端 56 | │ │ │ ├── AuthController.php // 包含 jwt 授权示例 57 | │ │ │ ├── Controller.php 58 | │ │ │ └── UsersController.php // 包含 laravel-response 使用示例 59 | │ │ ├── Middleware 60 | │ │ │ └── Authenticate.php // 统一401响应 61 | │ │ └── Resources 62 | │ │ └── UserResource.php // 使用 API 转换资源数据 63 | │ ├── Jobs // 异步任务 64 | │ │ ├── ExampleJob.php 65 | │ │ └── Job.php 66 | │ ├── Listeners // 监听事件处理 67 | │ │ └── ExampleListener.php 68 | │ ├── Models // Laravel 原始的 Eloquent\Model:定义数据表特性、数据表之间的关联关系等;不处理业务 69 | │ │ └── User.php 70 | │ ├── Providers // 各种服务容器 71 | │ │ ├── AppServiceProvider.php 72 | │ │ ├── AuthServiceProvider.php 73 | │ │ └── EventServiceProvider.php 74 | │ ├── Services // Service 层:处理实际业务;调用 Model 取资源数据,分发 Job、Eevent 等 75 | │ │ └── UserService.php 76 | │ └── Support // 对框架的扩展,或者实际项目中需要封装一些与业务无关的通用功能集 77 | │ ├── Traits 78 | │ │ ├── Helpers.php // Class 中常用的辅助功能集 79 | │ │ └── SerializeDate.php 80 | │ └── helpers.php // 全局会用到的辅助函数 81 | ``` 82 | 83 | ## Repository & Service 模式架构 84 | 85 | ``` 86 | Controller => 校验请求后调用不同 service 进行业务处理,调用 API Resource 转换资源数据返回 87 | Service => 具体的业务实现,调用 Model 取资源数据,处理业务,分发 event、job, 88 | Model => 维护资源数据的定义,以及数据之间的关联关系 89 | ``` 90 | 91 | ### 实际案例 92 | 93 | 为了更好地理解 Repository & Service 模式,对 Laravel 中文社区的教程 2 中的 Larabbs 项目使用该模式进行了重构,实际开发过程可以参考其中的分层设计。 94 | 95 | [larabbs](https://github.com/Jiannei/larabbs) 96 | 97 | ### 职责说明 98 | 99 | **Controller 岗位职责**: 100 | 101 | 1. 校验是否有必要处理请求,是否有权限和是否请求参数合法等。无权限或不合法请求直接 response 返回格式统一的数据 102 | 2. 将校验后的参数或 Request 传入 Service 中具体的方法,安排 Service 实现具体的功能业务逻辑 103 | 3. Controller 中可以通过`__construct()`依赖注入多个 Service。比如 `UserController` 中可能会注入 `UserService`(用户相关的功能业务)和 `EmailService`(邮件相关的功能业务) 104 | 4. 使用统一的 `$this->response`调用`sucess`或`fail`方法来返回统一的数据格式 105 | 5. 使用 Laravel Api Resource 的同学可能在 Controller 中还会有转换数据的逻辑。比如,`return Response::success(new UserCollection($resource));`或`return Response::success(new UserResource($user));` 106 | 107 | **Service 岗位职责**: 108 | 109 | 1. 实现项目中的具体**功能**业务。所以 Service 中定义的方法名,应该是用来**描述功能或业务**的(动词+业务描述)。比如`handleListPageDisplay`和`handleProfilePageDisplay`,分别对应用户列表展示和用户详情页展示的需求。 110 | 2. 处理 Controller 中传入的参数,进行**业务判断** 111 | 3.(可选)根据业务需求配置相应的 Criteria 和 Presenter 后(不需要的可以不用配置,或者将通用的配置到 Repository 中) 112 | 4. 调用 Repository 处理**数据的逻辑** 113 | 5. Service 可以不注入 Repository,或者只注入与处理当前业务**存在数据关联**的 Repository。比如,`EmailService`中或许就只有调用第三方 API 的逻辑,不需要更新维护系统中的数据,就不需要注入 Repository;`OrderService`中实现了订单出库逻辑后,还需要生成相应的财务结算单据,就需要注入 `OrderReposoitory`和`FinancialDocumentRepository`,财务单据中的原单号关联着订单号,存在着数据关联。 114 | 6. Service 中不允许调用其他 Service,保持职责单一,如有需要,应该考虑 Controller 中调用 115 | 116 | **Model 岗位职责**: 117 | 118 | Model 层只需要相对简单地数据定义就可以了。比如,对数据表的定义,字段的映射,以及数据表之间关联关系等。 119 | 120 | ### 规范 121 | 122 | * 命名规范: 123 | 124 | - controller: 125 | - 类名:名词,复数形式,描述是对整个资源集合进行操作;当没有集合概念的时候。换句话说,当资源只有一个的情况下,使用单数资源名称也是可以的——即一个单一的资源。例如,如果有一个单一的总体配置资源,你可以使用一个单数名称来表示 126 | - 方法名:动词+名词,体现资源操作。如,store\destroy 127 | 128 | - service: 129 | - 类名:名词,单数。比如`UserService`、`EmailService`和`OrderService` 130 | - 方法名:`动词+名词`,描述能够实现的业务需求。比如:`handleRegistration`表示实现用户注册功能。 131 | 132 | * 使用规范:待补充 133 | 134 | ## Packages 135 | 136 | - [jiannei/laravel-response](https://github.com/jiannei/laravel-response):规范统一的响应数据格式 137 | - [jiannei/laravel-response](https://github.com/jiannei/laravel-enum):多语言的枚举支持 138 | - [tymon/jwt-auth](https://github.com/tymondesigns/jwt-auth):默认支持 JWT 授权 139 | 140 | ## 参考 141 | 142 | * [RESTful API 最佳实践](https://learnku.com/articles/13797/restful-api-best-practice) 143 | * [RESTful 服务最佳实践](https://www.cnblogs.com/jaxu/p/7908111.html) 144 | 145 | ## License 146 | 147 | The Lumen Api Starter is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). 148 | -------------------------------------------------------------------------------- /app/Console/Commands/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiannei/lumen-api-starter/75deefb2e256fb334674f0e1717b27084f32bd49/app/Console/Commands/.gitkeep -------------------------------------------------------------------------------- /app/Console/Kernel.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Console; 13 | 14 | use Illuminate\Console\Scheduling\Schedule; 15 | use Laravel\Lumen\Console\Kernel as ConsoleKernel; 16 | 17 | class Kernel extends ConsoleKernel 18 | { 19 | /** 20 | * The Artisan commands provided by your application. 21 | * 22 | * @var array 23 | */ 24 | protected $commands = [ 25 | ]; 26 | 27 | /** 28 | * Define the application's command schedule. 29 | * 30 | * @return void 31 | */ 32 | protected function schedule(Schedule $schedule) 33 | { 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/Enums/ResponseCode.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Enums; 13 | 14 | use Jiannei\Enum\Laravel\Support\Traits\EnumEnhance; 15 | 16 | enum ResponseCode: int 17 | { 18 | use EnumEnhance; 19 | 20 | case SERVICE_REGISTER_SUCCESS = 200101; 21 | case SERVICE_LOGIN_SUCCESS = 200102; 22 | 23 | // 业务操作错误码(外部服务或内部服务调用...) 24 | case SERVICE_REGISTER_ERROR = 500101; 25 | case SERVICE_LOGIN_ERROR = 500102; 26 | 27 | // 客户端错误码:400 ~ 499 开头,后拼接 3 位 28 | case CLIENT_PARAMETER_ERROR = 400001; 29 | case CLIENT_CREATED_ERROR = 400002; 30 | case CLIENT_DELETED_ERROR = 400003; 31 | 32 | // 服务端操作错误码:500 ~ 599 开头,后拼接 3 位 33 | case SYSTEM_ERROR = 500001; 34 | case SYSTEM_UNAVAILABLE = 500002; 35 | case SYSTEM_CACHE_CONFIG_ERROR = 500003; 36 | case SYSTEM_CACHE_MISSED_ERROR = 500004; 37 | case SYSTEM_CONFIG_ERROR = 500005; 38 | } 39 | -------------------------------------------------------------------------------- /app/Events/Event.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Events; 13 | 14 | use Illuminate\Queue\SerializesModels; 15 | 16 | abstract class Event 17 | { 18 | use SerializesModels; 19 | } 20 | -------------------------------------------------------------------------------- /app/Events/ExampleEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Events; 13 | 14 | class ExampleEvent extends Event 15 | { 16 | /** 17 | * Create a new event instance. 18 | * 19 | * @return void 20 | */ 21 | public function __construct() 22 | { 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/Exceptions/Handler.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Exceptions; 13 | 14 | use Illuminate\Auth\Access\AuthorizationException; 15 | use Illuminate\Database\Eloquent\ModelNotFoundException; 16 | use Illuminate\Validation\ValidationException; 17 | use Jiannei\Response\Laravel\Support\Traits\ExceptionTrait; 18 | use Laravel\Lumen\Exceptions\Handler as ExceptionHandler; 19 | use Symfony\Component\HttpKernel\Exception\HttpException; 20 | use Throwable; 21 | 22 | class Handler extends ExceptionHandler 23 | { 24 | use ExceptionTrait; 25 | 26 | /** 27 | * A list of the exception types that should not be reported. 28 | * 29 | * @var array 30 | */ 31 | protected $dontReport = [ 32 | AuthorizationException::class, 33 | HttpException::class, 34 | ModelNotFoundException::class, 35 | ValidationException::class, 36 | ]; 37 | 38 | /** 39 | * Report or log an exception. 40 | * 41 | * This is a great spot to send exceptions to Sentry, Bugsnag, etc. 42 | * 43 | * @return void 44 | * 45 | * @throws \Exception 46 | */ 47 | public function report(Throwable $exception) 48 | { 49 | parent::report($exception); 50 | } 51 | 52 | /** 53 | * Render an exception into an HTTP response. 54 | * 55 | * @param \Illuminate\Http\Request $request 56 | * 57 | * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse 58 | * 59 | * @throws \Throwable 60 | */ 61 | public function render($request, Throwable $exception) 62 | { 63 | return parent::render($request, $exception); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/Http/Controllers/AuthController.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Http\Controllers; 13 | 14 | use Jiannei\Response\Laravel\Support\Facades\Response; 15 | 16 | class AuthController extends Controller 17 | { 18 | /** 19 | * Create a new AuthController instance. 20 | * 21 | * @return void 22 | */ 23 | public function __construct() 24 | { 25 | $this->middleware('auth:api', ['except' => ['login']]); 26 | } 27 | 28 | /** 29 | * Get a JWT via given credentials. 30 | * 31 | * @return \Illuminate\Http\JsonResponse 32 | */ 33 | public function login() 34 | { 35 | $credentials = request(['email', 'password']); 36 | 37 | if (!$token = auth()->attempt($credentials)) { 38 | return Response::errorUnauthorized(); 39 | } 40 | 41 | return $this->respondWithToken($token); 42 | } 43 | 44 | /** 45 | * Get the authenticated User. 46 | * 47 | * @return \Illuminate\Http\JsonResponse 48 | */ 49 | public function me() 50 | { 51 | return Response::success(auth()->user()); 52 | } 53 | 54 | /** 55 | * Log the user out (Invalidate the token). 56 | * 57 | * @return \Illuminate\Http\JsonResponse 58 | */ 59 | public function logout() 60 | { 61 | auth()->logout(); 62 | 63 | return Response::ok('Successfully logged out'); 64 | } 65 | 66 | /** 67 | * Refresh a token. 68 | * 69 | * @return \Illuminate\Http\JsonResponse 70 | */ 71 | public function refresh() 72 | { 73 | return $this->respondWithToken(auth()->refresh()); 74 | } 75 | 76 | /** 77 | * Get the token array structure. 78 | * 79 | * @param string $token 80 | * 81 | * @return \Illuminate\Http\JsonResponse 82 | */ 83 | protected function respondWithToken($token) 84 | { 85 | return Response::success([ 86 | 'access_token' => $token, 87 | 'token_type' => 'bearer', 88 | 'expires_in' => auth()->factory()->getTTL() * 60, 89 | ]); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Http\Controllers; 13 | 14 | use Laravel\Lumen\Routing\Controller as BaseController; 15 | 16 | abstract class Controller extends BaseController 17 | { 18 | } 19 | -------------------------------------------------------------------------------- /app/Http/Controllers/UsersController.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Http\Controllers; 13 | 14 | use App\Http\Resources\UserResource; 15 | use App\Services\UserService; 16 | use Illuminate\Http\Request; 17 | use Jiannei\Response\Laravel\Support\Facades\Response; 18 | 19 | class UsersController extends Controller 20 | { 21 | public function __construct(private UserService $service) 22 | { 23 | $this->middleware('auth:api', ['except' => ['store', 'show']]); 24 | } 25 | 26 | public function index(string $paginate = 'paginate') 27 | { 28 | $users = match ($paginate) { 29 | 'simple' => $this->service->handleSearchSimpleList(), 30 | 'cursor' => $this->service->handleSearchCursorList(), 31 | default => $this->service->handleSearchList(), 32 | }; 33 | 34 | return Response::success(UserResource::collection($users)); 35 | } 36 | 37 | public function show($id) 38 | { 39 | $user = $this->service->handleSearchItem($id); 40 | 41 | return Response::success($user); 42 | } 43 | 44 | public function store(Request $request) 45 | { 46 | $this->validate($request, [ 47 | 'name' => 'required|string|max:100', 48 | 'email' => 'required|email|unique:users,email', 49 | 'password' => 'required|min:8', 50 | ]); 51 | 52 | $user = $this->service->handleCreateItem($request->all()); 53 | 54 | return Response::created(new UserResource($user)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/Http/Middleware/Authenticate.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Http\Middleware; 13 | 14 | use Closure; 15 | use Illuminate\Contracts\Auth\Factory as Auth; 16 | use Jiannei\Response\Laravel\Support\Facades\Response; 17 | 18 | class Authenticate 19 | { 20 | /** 21 | * The authentication guard factory instance. 22 | * 23 | * @var \Illuminate\Contracts\Auth\Factory 24 | */ 25 | protected $auth; 26 | 27 | /** 28 | * Create a new middleware instance. 29 | * 30 | * @return void 31 | */ 32 | public function __construct(Auth $auth) 33 | { 34 | $this->auth = $auth; 35 | } 36 | 37 | /** 38 | * Handle an incoming request. 39 | * 40 | * @param \Illuminate\Http\Request $request 41 | * @param string|null $guard 42 | * 43 | * @return mixed 44 | */ 45 | public function handle($request, Closure $next, $guard = null) 46 | { 47 | if ($this->auth->guard($guard)->guest()) { 48 | return Response::errorUnauthorized(); 49 | } 50 | 51 | return $next($request); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/Http/Resources/UserResource.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Http\Resources; 13 | 14 | use Illuminate\Http\Resources\Json\JsonResource; 15 | 16 | class UserResource extends JsonResource 17 | { 18 | public function toArray($request) 19 | { 20 | return [ 21 | 'nickname' => $this->name, 22 | 'email' => $this->email, 23 | ]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/Jobs/ExampleJob.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Jobs; 13 | 14 | class ExampleJob extends Job 15 | { 16 | /** 17 | * Create a new job instance. 18 | * 19 | * @return void 20 | */ 21 | public function __construct() 22 | { 23 | } 24 | 25 | /** 26 | * Execute the job. 27 | * 28 | * @return void 29 | */ 30 | public function handle() 31 | { 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/Jobs/Job.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Jobs; 13 | 14 | use Illuminate\Bus\Queueable; 15 | use Illuminate\Contracts\Queue\ShouldQueue; 16 | use Illuminate\Queue\InteractsWithQueue; 17 | use Illuminate\Queue\SerializesModels; 18 | 19 | abstract class Job implements ShouldQueue 20 | { 21 | /* 22 | |-------------------------------------------------------------------------- 23 | | Queueable Jobs 24 | |-------------------------------------------------------------------------- 25 | | 26 | | This job base class provides a central location to place any logic that 27 | | is shared across all of your jobs. The trait included with the class 28 | | provides access to the "queueOn" and "delay" queue helper methods. 29 | | 30 | */ 31 | 32 | use InteractsWithQueue; 33 | use Queueable; 34 | use SerializesModels; 35 | } 36 | -------------------------------------------------------------------------------- /app/Listeners/ExampleListener.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Listeners; 13 | 14 | use App\Events\ExampleEvent; 15 | 16 | class ExampleListener 17 | { 18 | /** 19 | * Create the event listener. 20 | * 21 | * @return void 22 | */ 23 | public function __construct() 24 | { 25 | } 26 | 27 | /** 28 | * Handle the event. 29 | * 30 | * @return void 31 | */ 32 | public function handle(ExampleEvent $event) 33 | { 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/Models/User.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Models; 13 | 14 | use Illuminate\Auth\Authenticatable; 15 | use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract; 16 | use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; 17 | use Illuminate\Database\Eloquent\Factories\HasFactory; 18 | use Illuminate\Database\Eloquent\Model; 19 | use Laravel\Lumen\Auth\Authorizable; 20 | use Tymon\JWTAuth\Contracts\JWTSubject; 21 | 22 | class User extends Model implements AuthenticatableContract, AuthorizableContract, JWTSubject 23 | { 24 | use Authenticatable; 25 | use Authorizable; 26 | use HasFactory; 27 | 28 | /** 29 | * The attributes that are mass assignable. 30 | * 31 | * @var string[] 32 | */ 33 | protected $fillable = [ 34 | 'name', 'email', 35 | ]; 36 | 37 | /** 38 | * The attributes excluded from the model's JSON form. 39 | * 40 | * @var string[] 41 | */ 42 | protected $hidden = [ 43 | 'password', 44 | ]; 45 | 46 | /** 47 | * Get the identifier that will be stored in the subject claim of the JWT. 48 | * 49 | * @return mixed 50 | */ 51 | public function getJWTIdentifier() 52 | { 53 | return $this->getKey(); 54 | } 55 | 56 | /** 57 | * Return a key value array, containing any custom claims to be added to the JWT. 58 | * 59 | * @return array 60 | */ 61 | public function getJWTCustomClaims() 62 | { 63 | return []; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Providers; 13 | 14 | use Illuminate\Support\ServiceProvider; 15 | 16 | class AppServiceProvider extends ServiceProvider 17 | { 18 | /** 19 | * Register any application services. 20 | * 21 | * @return void 22 | */ 23 | public function register() 24 | { 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/Providers/AuthServiceProvider.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Providers; 13 | 14 | use App\Models\User; 15 | use Illuminate\Support\ServiceProvider; 16 | 17 | class AuthServiceProvider extends ServiceProvider 18 | { 19 | /** 20 | * Register any application services. 21 | * 22 | * @return void 23 | */ 24 | public function register() 25 | { 26 | } 27 | 28 | /** 29 | * Boot the authentication services for the application. 30 | * 31 | * @return void 32 | */ 33 | public function boot() 34 | { 35 | // Here you may define how you wish users to be authenticated for your Lumen 36 | // application. The callback which receives the incoming request instance 37 | // should return either a User instance or null. You're free to obtain 38 | // the User instance via an API token or any other method necessary. 39 | 40 | $this->app['auth']->viaRequest('api', function ($request) { 41 | if ($request->input('api_token')) { 42 | return User::where('api_token', $request->input('api_token'))->first(); 43 | } 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/Providers/EventServiceProvider.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Providers; 13 | 14 | use Laravel\Lumen\Providers\EventServiceProvider as ServiceProvider; 15 | 16 | class EventServiceProvider extends ServiceProvider 17 | { 18 | /** 19 | * The event listener mappings for the application. 20 | * 21 | * @var array 22 | */ 23 | protected $listen = [ 24 | \App\Events\ExampleEvent::class => [ 25 | \App\Listeners\ExampleListener::class, 26 | ], 27 | ]; 28 | 29 | /** 30 | * Determine if events and listeners should be automatically discovered. 31 | * 32 | * @return bool 33 | */ 34 | public function shouldDiscoverEvents() 35 | { 36 | return false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/Services/UserService.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Services; 13 | 14 | use App\Models\User; 15 | 16 | class UserService 17 | { 18 | public function handleSearchList() 19 | { 20 | return User::query()->paginate(); 21 | } 22 | 23 | public function handleSearchSimpleList() 24 | { 25 | return User::query()->simplePaginate(); 26 | } 27 | 28 | public function handleSearchCursorList() 29 | { 30 | return User::query()->cursorPaginate(); 31 | } 32 | 33 | public function handleSearchItem($id) 34 | { 35 | return User::query()->findOrFail($id); 36 | } 37 | 38 | public function handleCreateItem(array $data) 39 | { 40 | return User::query()->create($data); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/Support/Traits/Helpers.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Support\Traits; 13 | 14 | trait Helpers 15 | { 16 | } 17 | -------------------------------------------------------------------------------- /app/Support/Traits/SerializeDate.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace App\Support\Traits; 13 | 14 | use Carbon\Carbon; 15 | use DateTimeInterface; 16 | 17 | trait SerializeDate 18 | { 19 | /** 20 | * 为数组 / JSON 序列化准备日期。(Laravel 7). 21 | * 22 | * @return string 23 | */ 24 | protected function serializeDate(DateTimeInterface $date) 25 | { 26 | return $date->format($this->dateFormat ?: Carbon::DEFAULT_TO_STRING_FORMAT); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/Support/helpers.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | -------------------------------------------------------------------------------- /artisan: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | make( 32 | 'Illuminate\Contracts\Console\Kernel' 33 | ); 34 | 35 | exit($kernel->handle(new ArgvInput, new ConsoleOutput)); 36 | -------------------------------------------------------------------------------- /bootstrap/app.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | require_once __DIR__.'/../vendor/autoload.php'; 13 | 14 | (new Laravel\Lumen\Bootstrap\LoadEnvironmentVariables( 15 | dirname(__DIR__) 16 | ))->bootstrap(); 17 | 18 | date_default_timezone_set(env('APP_TIMEZONE', 'UTC')); 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Create The Application 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here we will load the environment and create the application instance 26 | | that serves as the central piece of this framework. We'll use this 27 | | application as an "IoC" container and router for this framework. 28 | | 29 | */ 30 | 31 | $app = new Laravel\Lumen\Application( 32 | dirname(__DIR__) 33 | ); 34 | 35 | $app->withFacades(); 36 | 37 | $app->withEloquent(); 38 | 39 | /* 40 | |-------------------------------------------------------------------------- 41 | | Register Container Bindings 42 | |-------------------------------------------------------------------------- 43 | | 44 | | Now we will register a few bindings in the service container. We will 45 | | register the exception handler and the console kernel. You may add 46 | | your own bindings here if you like or you can make another file. 47 | | 48 | */ 49 | 50 | $app->singleton( 51 | Illuminate\Contracts\Debug\ExceptionHandler::class, 52 | App\Exceptions\Handler::class 53 | ); 54 | 55 | $app->singleton( 56 | Illuminate\Contracts\Console\Kernel::class, 57 | App\Console\Kernel::class 58 | ); 59 | 60 | /* 61 | |-------------------------------------------------------------------------- 62 | | Register Config Files 63 | |-------------------------------------------------------------------------- 64 | | 65 | | Now we will register the "app" configuration file. If the file exists in 66 | | your configuration directory it will be loaded; otherwise, we'll load 67 | | the default version. You may register other files below as needed. 68 | | 69 | */ 70 | 71 | $app->configure('app'); 72 | $app->configure('response'); 73 | $app->configure('jwt'); 74 | 75 | /* 76 | |-------------------------------------------------------------------------- 77 | | Register Middleware 78 | |-------------------------------------------------------------------------- 79 | | 80 | | Next, we will register the middleware with the application. These can 81 | | be global middleware that run before and after each request into a 82 | | route or middleware that'll be assigned to some specific routes. 83 | | 84 | */ 85 | 86 | // $app->middleware([ 87 | // App\Http\Middleware\ExampleMiddleware::class 88 | // ]); 89 | 90 | $app->routeMiddleware([ 91 | 'auth' => App\Http\Middleware\Authenticate::class, 92 | ]); 93 | 94 | /* 95 | |-------------------------------------------------------------------------- 96 | | Register Service Providers 97 | |-------------------------------------------------------------------------- 98 | | 99 | | Here we will register all of the application's service providers which 100 | | are used to bind services into the container. Service providers are 101 | | totally optional, so you are not required to uncomment this line. 102 | | 103 | */ 104 | 105 | // $app->register(App\Providers\AppServiceProvider::class); 106 | $app->register(App\Providers\AuthServiceProvider::class); 107 | // $app->register(App\Providers\EventServiceProvider::class); 108 | $app->register(\Jiannei\Response\Laravel\Providers\LumenServiceProvider::class); 109 | $app->register(Tymon\JWTAuth\Providers\LumenServiceProvider::class); 110 | 111 | /* 112 | |-------------------------------------------------------------------------- 113 | | Load The Application Routes 114 | |-------------------------------------------------------------------------- 115 | | 116 | | Next we will include the routes file so that they can all be added to 117 | | the application. This will provide all of the URLs the application 118 | | can respond to, as well as the controllers that may handle them. 119 | | 120 | */ 121 | 122 | $app->router->group([ 123 | 'namespace' => 'App\Http\Controllers', 124 | ], function ($router) { 125 | require __DIR__.'/../routes/web.php'; 126 | }); 127 | 128 | return $app; 129 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laravel/lumen", 3 | "description": "The Laravel Lumen Framework.", 4 | "keywords": ["framework", "laravel", "lumen"], 5 | "license": "MIT", 6 | "type": "project", 7 | "require": { 8 | "php": "^8.1", 9 | "jiannei/laravel-enum": "dev-main", 10 | "jiannei/laravel-response": "dev-main", 11 | "laravel/lumen-framework": "^10.0", 12 | "tymon/jwt-auth": "^2.0" 13 | }, 14 | "require-dev": { 15 | "fakerphp/faker": "^1.9.1", 16 | "mockery/mockery": "^1.4.4", 17 | "phpunit/phpunit": "^10.0" 18 | }, 19 | "autoload": { 20 | "files": [ 21 | "app/Support/helpers.php" 22 | ], 23 | "psr-4": { 24 | "App\\": "app/", 25 | "Database\\Factories\\": "database/factories/", 26 | "Database\\Seeders\\": "database/seeders/" 27 | } 28 | }, 29 | "autoload-dev": { 30 | "psr-4": { 31 | "Tests\\": "tests/" 32 | } 33 | }, 34 | "scripts": { 35 | "post-root-package-install": [ 36 | "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" 37 | ] 38 | }, 39 | "config": { 40 | "optimize-autoloader": true, 41 | "preferred-install": "dist", 42 | "sort-packages": true 43 | }, 44 | "minimum-stability": "stable", 45 | "prefer-stable": true 46 | } 47 | -------------------------------------------------------------------------------- /config/app.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | return [ 13 | /* 14 | |-------------------------------------------------------------------------- 15 | | Application Name 16 | |-------------------------------------------------------------------------- 17 | | 18 | | This value is the name of your application. This value is used when the 19 | | framework needs to place the application's name in a notification or 20 | | any other location as required by the application or its packages. 21 | | 22 | */ 23 | 24 | 'name' => env('APP_NAME', 'Lumen'), 25 | 26 | /* 27 | |-------------------------------------------------------------------------- 28 | | Application Environment 29 | |-------------------------------------------------------------------------- 30 | | 31 | | This value determines the "environment" your application is currently 32 | | running in. This may determine how you prefer to configure various 33 | | services the application utilizes. Set this in your ".env" file. 34 | | 35 | */ 36 | 37 | 'env' => env('APP_ENV', 'production'), 38 | 39 | /* 40 | |-------------------------------------------------------------------------- 41 | | Application Debug Mode 42 | |-------------------------------------------------------------------------- 43 | | 44 | | When your application is in debug mode, detailed error messages with 45 | | stack traces will be shown on every error that occurs within your 46 | | application. If disabled, a simple generic error page is shown. 47 | | 48 | */ 49 | 50 | 'debug' => (bool) env('APP_DEBUG', false), 51 | 52 | /* 53 | |-------------------------------------------------------------------------- 54 | | Application URL 55 | |-------------------------------------------------------------------------- 56 | | 57 | | This URL is used by the console to properly generate URLs when using 58 | | the Artisan command line tool. You should set this to the root of 59 | | your application so that it is used when running Artisan tasks. 60 | | 61 | */ 62 | 63 | 'url' => env('APP_URL', 'http://localhost'), 64 | 65 | /* 66 | |-------------------------------------------------------------------------- 67 | | Application Timezone 68 | |-------------------------------------------------------------------------- 69 | | 70 | | Here you may specify the default timezone for your application, which 71 | | will be used by the PHP date and date-time functions. We have gone 72 | | ahead and set this to a sensible default for you out of the box. 73 | | 74 | */ 75 | 76 | 'timezone' => 'UTC', 77 | 78 | /* 79 | |-------------------------------------------------------------------------- 80 | | Application Locale Configuration 81 | |-------------------------------------------------------------------------- 82 | | 83 | | The application locale determines the default locale that will be used 84 | | by the translation service provider. You are free to set this value 85 | | to any of the locales which will be supported by the application. 86 | | 87 | */ 88 | 89 | 'locale' => env('APP_LOCALE', 'en'), 90 | 91 | /* 92 | |-------------------------------------------------------------------------- 93 | | Application Fallback Locale 94 | |-------------------------------------------------------------------------- 95 | | 96 | | The fallback locale determines the locale to use when the current one 97 | | is not available. You may change the value to correspond to any of 98 | | the language folders that are provided through your application. 99 | | 100 | */ 101 | 102 | 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'), 103 | 104 | /* 105 | |-------------------------------------------------------------------------- 106 | | Encryption Key 107 | |-------------------------------------------------------------------------- 108 | | 109 | | This key is used by the Illuminate encrypter service and should be set 110 | | to a random, 32 character string, otherwise these encrypted strings 111 | | will not be safe. Please do this before deploying an application! 112 | | 113 | */ 114 | 115 | 'key' => env('APP_KEY'), 116 | 117 | 'cipher' => 'AES-256-CBC', 118 | ]; 119 | -------------------------------------------------------------------------------- /config/auth.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | return [ 13 | /* 14 | |-------------------------------------------------------------------------- 15 | | Authentication Defaults 16 | |-------------------------------------------------------------------------- 17 | | 18 | | This option controls the default authentication "guard" and password 19 | | reset options for your application. You may change these defaults 20 | | as required, but they're a perfect start for most applications. 21 | | 22 | */ 23 | 24 | 'defaults' => [ 25 | 'guard' => env('AUTH_GUARD', 'api'), 26 | ], 27 | 28 | /* 29 | |-------------------------------------------------------------------------- 30 | | Authentication Guards 31 | |-------------------------------------------------------------------------- 32 | | 33 | | Next, you may define every authentication guard for your application. 34 | | Of course, a great default configuration has been defined for you 35 | | here which uses session storage and the Eloquent user provider. 36 | | 37 | | All authentication drivers have a user provider. This defines how the 38 | | users are actually retrieved out of your database or other storage 39 | | mechanisms used by this application to persist your user's data. 40 | | 41 | | Supported: "token" 42 | | 43 | */ 44 | 45 | 'guards' => [ 46 | 'api' => [ 47 | 'driver' => 'jwt', 48 | 'provider' => 'users', 49 | ], 50 | ], 51 | 52 | /* 53 | |-------------------------------------------------------------------------- 54 | | User Providers 55 | |-------------------------------------------------------------------------- 56 | | 57 | | All authentication drivers have a user provider. This defines how the 58 | | users are actually retrieved out of your database or other storage 59 | | mechanisms used by this application to persist your user's data. 60 | | 61 | | If you have multiple user tables or models you may configure multiple 62 | | sources which represent each model / table. These sources may then 63 | | be assigned to any extra authentication guards you have defined. 64 | | 65 | | Supported: "database", "eloquent" 66 | | 67 | */ 68 | 69 | 'providers' => [ 70 | 'users' => [ 71 | 'driver' => 'eloquent', 72 | 'model' => \App\Models\User::class, 73 | ], 74 | ], 75 | 76 | /* 77 | |-------------------------------------------------------------------------- 78 | | Resetting Passwords 79 | |-------------------------------------------------------------------------- 80 | | 81 | | Here you may set the options for resetting passwords including the view 82 | | that is your password reset e-mail. You may also set the name of the 83 | | table that maintains all of the reset tokens for your application. 84 | | 85 | | You may specify multiple password reset configurations if you have more 86 | | than one user table or model in the application and you want to have 87 | | separate password reset settings based on the specific user types. 88 | | 89 | | The expire time is the number of minutes that the reset token should be 90 | | considered valid. This security feature keeps tokens short-lived so 91 | | they have less time to be guessed. You may change this as needed. 92 | | 93 | */ 94 | 95 | 'passwords' => [ 96 | ], 97 | ]; 98 | -------------------------------------------------------------------------------- /config/response.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | return [ 13 | /* 14 | |-------------------------------------------------------------------------- 15 | | Set the http status code when the response fails 16 | |-------------------------------------------------------------------------- 17 | | 18 | | the reference options are false, 200, 500 19 | | 20 | | false, stricter http status codes such as 404, 401, 403, 500, etc. will be returned 21 | | 200, All failed responses will also return a 200 status code 22 | | 500, All failed responses return a 500 status code 23 | */ 24 | 25 | 'error_code' => false, 26 | 27 | // lang/zh_CN/enums.php 28 | 'locale' => 'enums.'.\App\Enums\ResponseCode::class, // enums.\Jiannei\Enum\Laravel\Support\Enums\HttpStatusCode::class 29 | 30 | // You can set some attributes (eg:code/message/header/options) for the exception, and it will override the default attributes of the exception 31 | 'exception' => [ 32 | \Illuminate\Validation\ValidationException::class => [ 33 | 'code' => 422, 34 | ], 35 | \Illuminate\Auth\AuthenticationException::class => [ 36 | ], 37 | \Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class => [ 38 | 'message' => '', 39 | ], 40 | \Illuminate\Database\Eloquent\ModelNotFoundException::class => [ 41 | 'message' => '', 42 | ], 43 | ], 44 | 45 | // Any key that returns data exists supports custom aliases and display. 46 | 'format' => [ 47 | 'class' => \Jiannei\Response\Laravel\Support\Format::class, 48 | 'config' => [ 49 | // key => config 50 | 'status' => ['alias' => 'status', 'show' => true], 51 | 'code' => ['alias' => 'code', 'show' => true], 52 | 'message' => ['alias' => 'message', 'show' => true], 53 | 'error' => ['alias' => 'error', 'show' => true], 54 | 'data' => ['alias' => 'data', 'show' => true], 55 | 'data.data' => ['alias' => 'data.data', 'show' => true], // rows/items/list 56 | ], 57 | ], 58 | ]; 59 | -------------------------------------------------------------------------------- /database/database.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiannei/lumen-api-starter/75deefb2e256fb334674f0e1717b27084f32bd49/database/database.sqlite -------------------------------------------------------------------------------- /database/factories/PostFactory.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Database\Factories; 13 | 14 | use App\Repositories\Models\Post; 15 | use Illuminate\Database\Eloquent\Factories\Factory; 16 | 17 | class PostFactory extends Factory 18 | { 19 | protected $model = Post::class; 20 | 21 | public function definition() 22 | { 23 | return [ 24 | 'title' => $this->faker->sentence, 25 | 'body' => $this->faker->paragraph(3), 26 | 'published' => $this->faker->numberBetween(0, 1), 27 | 'user_id' => $this->faker->randomElement([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), 28 | ]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /database/factories/UserFactory.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Database\Factories; 13 | 14 | use App\Models\User; 15 | use Illuminate\Database\Eloquent\Factories\Factory; 16 | use Illuminate\Support\Facades\Hash; 17 | 18 | class UserFactory extends Factory 19 | { 20 | /** 21 | * The name of the factory's corresponding model. 22 | * 23 | * @var string 24 | */ 25 | protected $model = User::class; 26 | 27 | /** 28 | * Define the model's default state. 29 | * 30 | * @return array 31 | */ 32 | public function definition() 33 | { 34 | return [ 35 | 'name' => $this->faker->name, 36 | 'email' => $this->faker->unique()->safeEmail, 37 | 'password' => Hash::make('password'), 38 | ]; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /database/migrations/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiannei/lumen-api-starter/75deefb2e256fb334674f0e1717b27084f32bd49/database/migrations/.gitkeep -------------------------------------------------------------------------------- /database/migrations/2020_05_30_115810_create_users_table.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | use Illuminate\Database\Migrations\Migration; 13 | use Illuminate\Database\Schema\Blueprint; 14 | use Illuminate\Support\Facades\Schema; 15 | 16 | class CreateUsersTable extends Migration 17 | { 18 | /** 19 | * Run the migrations. 20 | */ 21 | public function up() 22 | { 23 | Schema::create('users', function (Blueprint $table) { 24 | $table->id(); 25 | $table->string('name'); 26 | $table->string('email')->unique(); 27 | $table->string('password'); 28 | $table->timestamps(); 29 | }); 30 | } 31 | 32 | /** 33 | * Reverse the migrations. 34 | */ 35 | public function down() 36 | { 37 | Schema::dropIfExists('users'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /database/migrations/2020_10_16_105234_create_posts_table.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | use Illuminate\Database\Migrations\Migration; 13 | use Illuminate\Database\Schema\Blueprint; 14 | use Illuminate\Support\Facades\Schema; 15 | 16 | /** 17 | * Class CreatePostsTable. 18 | */ 19 | class CreatePostsTable extends Migration 20 | { 21 | /** 22 | * Run the migrations. 23 | * 24 | * @return void 25 | */ 26 | public function up() 27 | { 28 | Schema::create('posts', function (Blueprint $table) { 29 | $table->bigIncrements('id'); 30 | $table->unsignedBigInteger('user_id'); 31 | $table->text('title'); 32 | $table->text('body'); 33 | $table->boolean('published'); 34 | $table->timestamps(); 35 | }); 36 | } 37 | 38 | /** 39 | * Reverse the migrations. 40 | * 41 | * @return void 42 | */ 43 | public function down() 44 | { 45 | Schema::drop('posts'); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /database/seeders/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Database\Seeders; 13 | 14 | use Illuminate\Database\Seeder; 15 | 16 | class DatabaseSeeder extends Seeder 17 | { 18 | /** 19 | * Run the database seeds. 20 | * 21 | * @return void 22 | */ 23 | public function run() 24 | { 25 | $this->call([ 26 | UsersSeeder::class, 27 | ]); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /database/seeders/UsersSeeder.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Database\Seeders; 13 | 14 | use Database\Factories\UserFactory; 15 | use Illuminate\Database\Seeder; 16 | 17 | class UsersSeeder extends Seeder 18 | { 19 | public function run() 20 | { 21 | UserFactory::new()->count(30)->create(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | ./tests 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews -Indexes 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Handle Authorization Header 9 | RewriteCond %{HTTP:Authorization} . 10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 11 | 12 | # Redirect Trailing Slashes If Not A Folder... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_URI} (.+)/$ 15 | RewriteRule ^ %1 [L,R=301] 16 | 17 | # Handle Front Controller... 18 | RewriteCond %{REQUEST_FILENAME} !-d 19 | RewriteCond %{REQUEST_FILENAME} !-f 20 | RewriteRule ^ index.php [L] 21 | 22 | -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | $app = require __DIR__.'/../bootstrap/app.php'; 13 | 14 | /* 15 | |-------------------------------------------------------------------------- 16 | | Run The Application 17 | |-------------------------------------------------------------------------- 18 | | 19 | | Once we have the application, we can handle the incoming request 20 | | through the kernel, and send the associated response back to 21 | | the client's browser allowing them to enjoy the creative 22 | | and wonderful application we have prepared for them. 23 | | 24 | */ 25 | 26 | $app->run(); 27 | -------------------------------------------------------------------------------- /resources/lang/zh_CN/enums.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | use App\Enums\ResponseCode; 13 | use Jiannei\Enum\Laravel\Support\Enums\HttpStatusCode; 14 | 15 | return [ 16 | ResponseCode::class => [ 17 | // 标准 HTTP 状态码 18 | HttpStatusCode::HTTP_OK->value => '操作成功', 19 | HttpStatusCode::HTTP_UNAUTHORIZED->value => '授权失败', 20 | 21 | // 业务操作成功 22 | ResponseCode::SERVICE_REGISTER_SUCCESS->value => '注册成功', 23 | ResponseCode::SERVICE_LOGIN_SUCCESS->value => '登录成功', 24 | 25 | // 业务操作失败:授权业务 26 | ResponseCode::SERVICE_REGISTER_ERROR->value => '注册失败', 27 | ResponseCode::SERVICE_LOGIN_ERROR->value => '登录失败', 28 | 29 | // 客户端错误 30 | ResponseCode::CLIENT_PARAMETER_ERROR->value => '参数错误', 31 | ResponseCode::CLIENT_CREATED_ERROR->value => '数据已存在', 32 | ResponseCode::CLIENT_DELETED_ERROR->value => '数据不存在', 33 | 34 | // 服务端错误 35 | ResponseCode::SYSTEM_ERROR->value => '服务器错误', 36 | ResponseCode::SYSTEM_UNAVAILABLE->value => '服务器正在维护,暂不可用', 37 | ResponseCode::SYSTEM_CACHE_CONFIG_ERROR->value => '缓存配置错误', 38 | ResponseCode::SYSTEM_CACHE_MISSED_ERROR->value => '缓存未命中', 39 | ResponseCode::SYSTEM_CONFIG_ERROR->value => '系统配置错误', 40 | ], 41 | ]; 42 | -------------------------------------------------------------------------------- /resources/views/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jiannei/lumen-api-starter/75deefb2e256fb334674f0e1717b27084f32bd49/resources/views/.gitkeep -------------------------------------------------------------------------------- /routes/web.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | /* 13 | |-------------------------------------------------------------------------- 14 | | Application Routes 15 | |-------------------------------------------------------------------------- 16 | | 17 | | Here is where you can register all of the routes for an application. 18 | | It is a breeze. Simply tell Lumen the URIs it should respond to 19 | | and give it the Closure to call when that URI is requested. 20 | | 21 | */ 22 | 23 | /* @var \Laravel\Lumen\Routing\Router $router */ 24 | 25 | $router->get('/', function () use ($router) { 26 | return $router->app->version(); 27 | }); 28 | 29 | $router->get('users[/{paginate}]', 'UsersController@index'); 30 | 31 | $router->group(['prefix' => 'auth'], function () use ($router) { 32 | $router->post('login', 'AuthController@login'); 33 | $router->delete('logout', 'AuthController@logout'); 34 | $router->put('refresh', 'AuthController@refresh'); 35 | $router->get('me', 'AuthController@me'); 36 | }); 37 | -------------------------------------------------------------------------------- /storage/app/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !data/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /storage/framework/cache/data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/views/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /tests/ExampleTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Tests; 13 | 14 | class ExampleTest extends TestCase 15 | { 16 | /** 17 | * A basic test example. 18 | * 19 | * @return void 20 | */ 21 | public function test_that_base_endpoint_returns_a_successful_response() 22 | { 23 | $this->get('/'); 24 | 25 | $this->assertEquals( 26 | $this->app->version(), $this->response->getContent() 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/Feature/ExampleTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Tests\Feature; 13 | 14 | use Laravel\Lumen\Testing\DatabaseMigrations; 15 | use Tests\TestCase; 16 | 17 | class ExampleTest extends TestCase 18 | { 19 | // use DatabaseMigrations; 20 | 21 | /** 22 | * A basic test example. 23 | */ 24 | public function testExample() 25 | { 26 | $this->get('/'); 27 | 28 | $this->assertEquals( 29 | $this->app->version(), 30 | $this->response->getContent() 31 | ); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Tests; 13 | 14 | use Laravel\Lumen\Testing\TestCase as BaseTestCase; 15 | 16 | abstract class TestCase extends BaseTestCase 17 | { 18 | /** 19 | * Creates the application. 20 | * 21 | * @return \Laravel\Lumen\Application 22 | */ 23 | public function createApplication() 24 | { 25 | return require __DIR__.'/../bootstrap/app.php'; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/Traits/CreatesApplication.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Tests\Traits; 13 | 14 | trait CreatesApplication 15 | { 16 | /** 17 | * Creates the application. 18 | * 19 | * @return \Laravel\Lumen\Application 20 | */ 21 | public function createApplication() 22 | { 23 | return require __DIR__.'/../../bootstrap/app.php'; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tests/Unit/ExampleTest.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * This source file is subject to the MIT license that is bundled 9 | * with this source code in the file LICENSE. 10 | */ 11 | 12 | namespace Tests\Unit; 13 | 14 | use Tests\TestCase; 15 | 16 | class ExampleTest extends TestCase 17 | { 18 | /** 19 | * A basic test example. 20 | * 21 | * @return void 22 | */ 23 | public function testBasicTest() 24 | { 25 | $this->assertTrue(true); 26 | } 27 | } 28 | --------------------------------------------------------------------------------