chengwl 2 weken geleden
bovenliggende
commit
e3041eed24

+ 7 - 1
bootstrap/app.php

@@ -48,4 +48,10 @@ return Application::configure(basePath: dirname(__DIR__))
     })
     })
     ->withExceptions(function (Exceptions $exceptions) {
     ->withExceptions(function (Exceptions $exceptions) {
         //
         //
-    })->create();
+    })
+->withProviders([
+     \ApiPlatform\Laravel\ApiPlatformProvider::class,
+     \ApiPlatform\Laravel\ApiPlatformDeferredProvider::class,
+     \ApiPlatform\Laravel\Eloquent\ApiPlatformEventProvider::class,
+])
+->create();

+ 1 - 0
bootstrap/providers.php

@@ -44,4 +44,5 @@ return [
     Webkul\Tax\Providers\TaxServiceProvider::class,
     Webkul\Tax\Providers\TaxServiceProvider::class,
     Webkul\Theme\Providers\ThemeServiceProvider::class,
     Webkul\Theme\Providers\ThemeServiceProvider::class,
     Webkul\User\Providers\UserServiceProvider::class,
     Webkul\User\Providers\UserServiceProvider::class,
+    Webkul\BagistoApi\Providers\BagistoApiServiceProvider::class,
 ];
 ];

+ 15 - 8
composer.json

@@ -17,6 +17,8 @@
         "ext-pdo": "*",
         "ext-pdo": "*",
         "ext-pdo_mysql": "*",
         "ext-pdo_mysql": "*",
         "ext-tokenizer": "*",
         "ext-tokenizer": "*",
+        "api-platform/graphql": "v4.2.3",
+        "api-platform/laravel": "v4.1.25",
         "astrotomic/laravel-translatable": "^11.0.0",
         "astrotomic/laravel-translatable": "^11.0.0",
         "bagisto/image-cache": "dev-master",
         "bagisto/image-cache": "dev-master",
         "barryvdh/laravel-dompdf": "^2.0.0",
         "barryvdh/laravel-dompdf": "^2.0.0",
@@ -96,7 +98,9 @@
             "Webkul\\SocialShare\\": "packages/Webkul/SocialShare/src",
             "Webkul\\SocialShare\\": "packages/Webkul/SocialShare/src",
             "Webkul\\Tax\\": "packages/Webkul/Tax/src",
             "Webkul\\Tax\\": "packages/Webkul/Tax/src",
             "Webkul\\Theme\\": "packages/Webkul/Theme/src",
             "Webkul\\Theme\\": "packages/Webkul/Theme/src",
-            "Webkul\\User\\": "packages/Webkul/User/src"
+            "Webkul\\User\\": "packages/Webkul/User/src",
+            "Webkul\\BagistoApi\\": "packages/Webkul/BagistoApi/src",
+            "Webkul\\GraphQL\\": "packages/Webkul/GraphQL/src"
         }
         }
     },
     },
     "autoload-dev": {
     "autoload-dev": {
@@ -124,17 +128,20 @@
             "dont-discover": [
             "dont-discover": [
                 "intervention/image",
                 "intervention/image",
                 "laravel/socialite",
                 "laravel/socialite",
-                "shetabit/visitor"
+                "shetabit/visitor",
+                "api-platform/laravel"
             ]
             ]
         }
         }
     },
     },
-    "repositories": [{
-        "type": "path",
-        "url": "packages/*/*",
-        "options": {
-            "symlink": true
+    "repositories": [
+        {
+            "type": "path",
+            "url": "packages/*/*",
+            "options": {
+                "symlink": true
+            }
         }
         }
-    }],
+    ],
     "config": {
     "config": {
         "optimize-autoloader": true,
         "optimize-autoloader": true,
         "preferred-install": "dist",
         "preferred-install": "dist",

+ 230 - 0
config/api-platform.php

@@ -0,0 +1,230 @@
+<?php
+
+/*
+ * This file is part of the API Platform project.
+ *
+ * (c) Kévin Dunglas <dunglas@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+declare(strict_types=1);
+
+use ApiPlatform\Metadata\Operation\DashPathSegmentNameGenerator;
+use ApiPlatform\Metadata\UrlGeneratorInterface;
+use Illuminate\Auth\Access\AuthorizationException;
+use Illuminate\Auth\AuthenticationException;
+use Symfony\Component\Serializer\NameConverter\SnakeCaseToCamelCaseNameConverter;
+use Webkul\BagistoApi\Exception\InvalidInputException;
+use Webkul\BagistoApi\Exception\ValidationException;
+
+return [
+    'title'       => '',
+    'description' => '',
+    'version'     => '1.0.0',
+    'show_webby'  => true,
+
+    'routes' => [
+        'domain' => null,
+        // Global middleware applied to every API Platform routes
+        // HandleInvalidInputException: Catches validation errors and returns RFC 7807 format
+        // VerifyStorefrontKey: Validates X-STOREFRONT-KEY header and rate limiting for shop APIs
+        // BagistoApiDocumentationMiddleware: Handles custom /api index and documentation pages
+        // ForceApiJson: Ensures API responses have JSON content-type
+        // CacheResponse: Using custom ApiAwareResponseCache profile that:
+        // - Excludes API routes from caching (APIs need fresh data)
+        // - Caches shop pages for performance
+        // - Only caches HTML, not JSON responses
+        'middleware' => [
+            'Webkul\BagistoApi\Http\Middleware\HandleInvalidInputException',
+            'Webkul\BagistoApi\Http\Middleware\SecurityHeaders',
+            'Webkul\BagistoApi\Http\Middleware\LogApiRequests',
+            'Webkul\BagistoApi\Http\Middleware\SetLocaleChannel',
+            'Webkul\BagistoApi\Http\Middleware\VerifyStorefrontKey',
+            'Webkul\BagistoApi\Http\Middleware\BagistoApiDocumentationMiddleware',
+            'Webkul\BagistoApi\Http\Middleware\ForceApiJson',
+            'Spatie\ResponseCache\Middlewares\CacheResponse',
+        ],
+    ],
+
+    'resources' => [
+        base_path('packages/Webkul/BagistoApi/src/Models/'),
+    ],
+
+    'formats' => [
+        'json'=> ['application/json'],
+    ],
+
+    'patch_formats' => [
+        'json' => ['application/merge-patch+json'],
+    ],
+
+    'docs_formats' => [
+        'jsonopenapi' => ['application/vnd.openapi+json'],
+        'html'        => ['text/html'],
+    ],
+
+    'error_formats' => [
+        'jsonproblem' => ['application/problem+json'],
+    ],
+
+    'defaults' => [
+        'pagination_enabled'                => true,
+        'pagination_partial'                => false,
+        'pagination_client_enabled'         => false,
+        'pagination_client_items_per_page'  => false,
+        'pagination_client_partial'         => false,
+        'pagination_items_per_page'         => 10,
+        'pagination_maximum_items_per_page' => 50,
+        'route_prefix'                      => '/api',
+        'middleware'                        => [],
+    ],
+
+    'pagination' => [
+        'page_parameter_name'           => 'page',
+        'enabled_parameter_name'        => 'pagination',
+        'items_per_page_parameter_name' => 'itemsPerPage',
+        'partial_parameter_name'        => 'partial',
+    ],
+
+    'graphql' => [
+        'enabled'              => true,
+        'nesting_separator'    => '__',
+        'introspection'        => ['enabled' => true],
+        'max_query_complexity' => 400,
+        'max_query_depth'      => 20,
+        'graphiql'             => [
+            'enabled'           => true,
+            'default_query'     => null,
+            'default_variables' => null,
+        ],
+        'graphql_playground' => [
+            'enabled'           => true,
+            'default_query'     => null,
+            'default_variables' => null,
+        ],
+        // GraphQL middleware for authentication and rate limiting
+        'middleware' => [
+            'Webkul\BagistoApi\Http\Middleware\SetLocaleChannel',
+            'Webkul\BagistoApi\Http\Middleware\VerifyGraphQLStorefrontKey',
+        ],
+    ],
+
+    'graphiql' => [
+        'enabled' => true,
+    ],
+
+    'name_converter' => SnakeCaseToCamelCaseNameConverter::class,
+
+    'path_segment_name_generator' => DashPathSegmentNameGenerator::class,
+
+    'exception_to_status' => [
+        AuthenticationException::class => 401,
+        AuthorizationException::class  => 403,
+        ValidationException::class     => 400,
+        InvalidInputException::class   => 400,
+    ],
+
+    'swagger_ui' => [
+        'enabled' => true,
+        'apiKeys' => [
+            'api' => [
+                'name'   => 'Authorization',
+                'type'   => 'header',
+                'scheme' => 'bearer',
+            ],
+        ],
+    ],
+
+    'url_generation_strategy' => UrlGeneratorInterface::ABS_PATH,
+
+    'serializer' => [
+        'hydra_prefix'    => false,
+        'datetime_format' => 'Y-m-d\TH:i:sP',
+    ],
+
+    'cache' => 'redis',
+
+    'schema_cache' => [
+        'enabled' => true,
+        'store'   => 'redis',
+    ],
+
+    'security' => [
+        'sanctum' => true,
+    ],
+
+    'rate_limit' => [
+        'skip_localhost' => env('RATE_LIMIT_SKIP_LOCALHOST', true),
+        'auth'           => env('RATE_LIMIT_AUTH', 5),
+        'admin'          => env('RATE_LIMIT_ADMIN', 60),
+        'shop'           => env('RATE_LIMIT_SHOP', 100),
+        'graphql'        => env('RATE_LIMIT_GRAPHQL', 100),
+        'cache_driver'   => env('RATE_LIMIT_CACHE', 'redis'),
+        'cache_prefix'   => 'api:rate-limit:',
+    ],
+
+    'security_headers' => [
+        'enabled'     => true,
+        'force_https' => env('APP_FORCE_HTTPS', false),
+        'csp_header'  => "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'",
+    ],
+
+    'api_logging' => [
+        'enabled'            => env('API_LOG_ENABLED', true),
+        'log_sensitive_data' => env('API_LOG_SENSITIVE_DATA', false),
+        'exclude_paths'      => ['docs', 'graphiql', 'swagger-ui', 'docs.json'],
+        'channel'            => 'api',
+        'async'              => env('API_LOG_ASYNC', true),
+        'queue'              => env('API_LOG_QUEUE', 'api-logs'),
+    ],
+
+    'graphql_validation' => [
+        'max_depth'      => env('GRAPHQL_MAX_DEPTH', 10),
+        'max_complexity' => env('GRAPHQL_MAX_COMPLEXITY', 300),
+    ],
+
+    'request_limits' => [
+        'max_size_mb'          => env('MAX_REQUEST_SIZE', 10),
+        'max_pagination_limit' => env('MAX_PAGINATION_LIMIT', 100),
+    ],
+
+    'database' => [
+        'log_queries'          => env('DB_QUERY_LOG_ENABLED', false),
+        'slow_query_threshold' => env('DB_SLOW_QUERY_THRESHOLD', 1000),
+    ],
+
+    'caching' => [
+        'enable_security_cache' => env('API_SECURITY_CACHE', true),
+        'security_cache_ttl'    => env('API_SECURITY_CACHE_TTL', 3600),
+        'enable_response_cache' => env('API_RESPONSE_CACHE', true),
+        'response_cache_ttl'    => env('API_RESPONSE_CACHE_TTL', 3600),
+    ],
+
+    'http_cache' => [
+        'etag'                   => true,
+        'max_age'                => 3600,
+        'shared_max_age'         => null,
+        'vary'                   => null,
+        'public'                 => true,
+        'stale_while_revalidate' => 30,
+        'stale_if_error'         => null,
+        'invalidation'           => [
+            'urls'              => [],
+            'scoped_clients'    => [],
+            'max_header_length' => 7500,
+            'request_options'   => [],
+            'purger'            => ApiPlatform\HttpCache\SouinPurger::class,
+        ],
+    ],
+
+    'key_rotation_policy' => [
+        'enabled'               => true,
+        'expiration_months'     => env('API_KEY_EXPIRATION_MONTHS', 12),
+        'transition_days'       => env('API_KEY_TRANSITION_DAYS', 7),
+        'cleanup_days'          => env('API_KEY_CLEANUP_DAYS', 90),
+        'cache_ttl'             => env('API_KEY_CACHE_TTL', 3600),
+        'storefront_key_prefix' => env('STOREFRONT_KEY_PREFIX', 'pk_storefront_'),
+    ],
+];

+ 1 - 0
packages/Webkul/BagistoApi

@@ -0,0 +1 @@
+Subproject commit d9adbe5a0b6a0766887a5165eaeea6c87640a2c8

File diff suppressed because it is too large
+ 9 - 0
public/themes/admin/default/assets/images/admin-api.svg


File diff suppressed because it is too large
+ 3 - 0
public/themes/admin/default/assets/images/document.svg


File diff suppressed because it is too large
+ 9 - 0
public/themes/admin/default/assets/images/graph-QL.svg


BIN
public/themes/admin/default/assets/images/left-gradient.webp


BIN
public/themes/admin/default/assets/images/right-gradient.webp


File diff suppressed because it is too large
+ 9 - 0
public/themes/admin/default/assets/images/shop-api.svg


+ 6 - 0
public/themes/admin/default/assets/images/top-logo.svg

@@ -0,0 +1,6 @@
+<svg width="100" height="100" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
+<rect width="100" height="100" fill="white" style="fill:white;fill-opacity:1;"/>
+<rect x="17.3223" y="28.542" width="65.4582" height="56.2711" fill="#2149F3" style="fill:#2149F3;fill:color(display-p3 0.1294 0.2863 0.9529);fill-opacity:1;"/>
+<rect x="17.3223" y="84.8134" width="65.4582" height="9.18712" fill="black" style="fill:black;fill-opacity:1;"/>
+<path d="M70.7228 27.4745V42.735C70.7228 44.7271 69.1756 46.342 67.267 46.342C65.3584 46.342 63.8112 44.7271 63.8112 42.735V27.4745C63.8112 19.0464 57.2653 12.214 49.1905 12.214C41.1157 12.214 34.5698 19.0464 34.5698 27.4745V42.735C34.5698 44.7271 33.0226 46.342 31.114 46.342C29.2054 46.342 27.6582 44.7271 27.6582 42.735V27.4745C27.6582 15.0622 37.2985 5 49.1905 5C61.0825 5 70.7228 15.0622 70.7228 27.4745Z" fill="black" style="fill:black;fill-opacity:1;"/>
+</svg>