{"id":15323096,"url":"https://github.com/darkweak/usainboltapi","last_synced_at":"2026-02-04T12:06:44.506Z","repository":{"id":41613200,"uuid":"275790479","full_name":"darkweak/UsainBoltAPI","owner":"darkweak","description":null,"archived":false,"fork":false,"pushed_at":"2023-01-06T10:16:06.000Z","size":4732,"stargazers_count":0,"open_issues_count":21,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-08T13:09:24.371Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/darkweak.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-06-29T11:14:44.000Z","updated_at":"2020-11-26T16:39:55.000Z","dependencies_parsed_at":"2023-02-05T20:46:56.465Z","dependency_job_id":null,"html_url":"https://github.com/darkweak/UsainBoltAPI","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/darkweak/UsainBoltAPI","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darkweak%2FUsainBoltAPI","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darkweak%2FUsainBoltAPI/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darkweak%2FUsainBoltAPI/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darkweak%2FUsainBoltAPI/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/darkweak","download_url":"https://codeload.github.com/darkweak/UsainBoltAPI/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darkweak%2FUsainBoltAPI/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29084088,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-04T03:31:03.593Z","status":"ssl_error","status_checked_at":"2026-02-04T03:29:50.742Z","response_time":62,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-01T09:18:58.657Z","updated_at":"2026-02-04T12:06:44.492Z","avatar_url":"https://github.com/darkweak.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# API de recettes basé sur des outils puissants et populaires\n\n## Technologies utilisées\n* [API Platform](https://api-platform.com)\n* [Lexik JWT](https://github.com/lexik/LexikJWTAuthenticationBundle)\n* [Mercure](https://mercure.rocks)\n* [Souin](https://github.com/darkweak/souin)\n* [Symfony](https://symfony.com)\n* [Vulcain](https://vulcain.rocks)\n\n## Étapes\n\n### Mise en place de l'authentification par jwt\nNous allons pouvoir créer notre authentification par token très facilement en nous basant sur le bundle `LexikJWTAuthenticationBundle`. Pour l'installer, rien de plus simple:\n```bash\ndocker-compose exec php composer req jwt-auth\n```\n\nPuis il suffit de lancer cette commande suivante pour générer les clés si vous utilisez docker:\n```bash\ndocker-compose exec php sh -c '\n    set -e\n    apk add openssl\n    mkdir -p config/jwt\n    jwt_passphrase=${JWT_PASSPHRASE:-$(grep ''^JWT_PASSPHRASE='' .env | cut -f 2 -d ''='')}\n    echo \"$jwt_passphrase\" | openssl genpkey -out config/jwt/private.pem -pass stdin -aes256 -algorithm rsa -pkeyopt rsa_keygen_bits:4096\n    echo \"$jwt_passphrase\" | openssl pkey -in config/jwt/private.pem -passin stdin -out config/jwt/public.pem -pubout\n    setfacl -R -m u:www-data:rX -m u:\"$(whoami)\":rwX config/jwt\n    setfacl -dR -m u:www-data:rX -m u:\"$(whoami)\":rwX config/jwt\n'\n```\n\nSinon il suffit de lancer cette commande directement sur votre poste:\n```bash\njwt_passphrase=${JWT_PASSPHRASE:-$(grep ''^JWT_PASSPHRASE='' .env | cut -f 2 -d ''='')}\n    echo \"$jwt_passphrase\" | openssl genpkey -out config/jwt/private.pem -pass stdin -aes256 -algorithm rsa -pkeyopt rsa_keygen_bits:4096\n    echo \"$jwt_passphrase\" | openssl pkey -in config/jwt/private.pem -passin stdin -out config/jwt/public.pem -pubout\n    setfacl -R -m u:www-data:rX -m u:\"$(whoami)\":rwX config/jwt\n    setfacl -dR -m u:www-data:rX -m u:\"$(whoami)\":rwX config/jwt\n```\n\nEnsuite vous n'avez qu'à modifier le security.yaml avec l'exemple prêt à l'emploi qui suit:\n```yaml\n# ...\n    firewalls:\n        # ...\n        main:\n            anonymous: true\n            lazy: true\n            provider: app_user_provider\n            json_login:\n                check_path: /authentication_token\n                username_path: email\n                password_path: password\n                success_handler: lexik_jwt_authentication.handler.authentication_success\n                failure_handler: lexik_jwt_authentication.handler.authentication_failure\n\n    access_control:\n        # ...\n        - { path: ^/docs, roles: IS_AUTHENTICATED_ANONYMOUSLY }\n        - { path: ^/authentication_token, roles: IS_AUTHENTICATED_ANONYMOUSLY }\n        - { path: ^/, roles: IS_AUTHENTICATED_FULLY }\n```\n\nIl nous faut aussi définir la route `/authentication_token` dans le `routes.yaml` comme suit:\n```yaml\nauthentication_token:\n    path: /authentication_token\n    methods: ['POST']\n```\n\n### Mise en place de l'API\n\nTout d'abord, nous devons installer le système d'API officiel qui est API Platform. Pour se faire il faut exécuter la commande :\n````bash\ndocker-compose exec php composer req api\n````\n\nAPI Platform est supporté par `maker-bundle` lors de la création d'une entité grâce au drapeau `--api-resource` ou `-a`. Cependant dans notre cas, les entités étant déjà générées nous devons ajouter manuellement l'annotation `APIResource` dans nos entités devant être exposées sans oublier le `use`.\n```php\n// ...\n\nuse ApiPlatform\\Core\\Annotation\\ApiResource;\n// ...\n\n/**\n * @ApiResource()\n * ...\n */\nclass MyClass\n```\n\nEt voilà, c'est aussi simple que ça, nous avons maintenant toutes nos routes exposées pour interagir avec l'API. Et comme API Platform gère `OpenAPI`, nous pouvons les consulter facilement via le swagger sur la route `/api/docs` ou `/api` dans notre cas car API Platform est préfixé par `/api`. Cette valeur peut-être changé dans le fichier `config/routes/api_platform.yaml` grâce à la clé `prefix`.  \n\u003cimg src=\"docs/images/swagger.png\" alt=\"swagger render\" /\u003e\n\nEnfin si vous ne souhaitez pas procéder à l'installation manuellement d'API Platform dans Symfony vous pouvez utiliser le dépôt officiel API Platform qui est prêt à l'emploi [ici](https://github.com/api-platform/core)\n\n### Définition des points d'API\nPour définir nos points d'API, nous profiterons de l'annotation `APIResource`. Nous pourrons restreindre des méthodes HTTP et donc des actions sur l'API à certaines catégories utilisateurs.  \nPar exemple, nous voulons qu'un utilisateur authentifié puisse créer une recette mais qu'il soit le seul à pouvoir la modifier, nous allons mettre en place cette annotation.  \n\nL'annotation `APIResource` peut contenir les attributs `collectionOperations` et `itemOperations` ce qui va nous permettre de définir les règles de sécurités par operation (`DELETE`, `GET`, `PATCH`, `POST`, `PUT`).\nDe ce fait, nous pouvons définir dans l'annotation `APIResource` de notre entité `Recipe` les méthodes `post` et `put` avec une sécurité propre à chaque méthode de cette façon :\n\n```php\n/**\n * @ApiResource(\n *      collectionOperations={\n *          \"post\"={\"security\"=\"is_granted('IS_AUTHENTICATED_FULLY')\"}\n *      },\n *      itemOperations={\n *          \"put\"={\"security\"=\"is_granted('ROLE_ADMIN') or user == object.author\"}\n *      }\n * )\n * ...\n */\n```\n\nPar exemple notre classe `Recipe` devra exposer\n\n| Nom                      | Méthode | Operation  | Sécurité                                                 |\n|:------------------------:|:-------:|:----------:|:--------------------------------------------------------:|\n| La liste                 | GET     | collection | `-`                                                      |\n| La création              | POST    | collection | L'utilisateur doit être authentifié                      |\n| L'objet simple           | GET     | item       | `-`                                                      |\n| La mise à jour           | PUT     | item       | L'utilisateur est admin ou est le créateur de la recette |\n| La mise à jour partielle | PATCH   | item       | L'utilisateur est admin ou est le créateur de la recette |\n| La suppression           | DELETE  | item       | L'utilisateur est admin ou est le créateur de la recette |\n\nOn aura donc cette déclaration :\n```php\n/**\n * @ApiResource(\n *      collectionOperations={\n *          \"get\",\n *          \"post\"={\"security\"=\"is_granted('IS_AUTHENTICATED_FULLY')\"}\n *      },\n *      itemOperations={\n *          \"get\",\n *          \"patch\"={\"security\"=\"is_granted('ROLE_ADMIN') or user == object.author\"},\n *          \"put\"={\"security\"=\"is_granted('ROLE_ADMIN') or user == object.author\"},\n *          \"delete\"={\"security\"=\"is_granted('ROLE_ADMIN') or user == object.author\"}\n *      }\n * )\n * ...\n */\n```\n\nMaintenant on souhaite pouvoir uniquement lister les `Step`, mais que seuls les admin puissent les créer, les éditer mais sans pouvoir les supprimer. On aura donc ceci :\n```php\n/**\n * @ApiResource(\n *      security=\"is_granted('IS_AUTHENTICATED_FULLY')\",\n *      collectionOperations={\n *          \"get\"={\"security\"=\"is_granted('IS_AUTHENTICATED_ANONYMOUSLY')\"},\n *          \"post\",\n *      },\n *      itemOperations={\n *          \"get\"={\n *              \"controller\"=NotFoundAction::class,\n *              \"read\"=false,\n *              \"output\"=false,\n *          },\n *          \"patch\",\n *          \"put\"\n *      }\n * )\n * ...\n */\n```\n\nOn remarque qu'on peut définir un security global puis redéfinir un sécurity par opération. Cela permet d'éviter la redondance. Nous voyons aussi que lorsque nous voulons retirer le `get` dans les `itemOperations` nous sommes obligés de définir la méthode comme renvoyant forcément un `NotFound` du fait qu'API Platform se base sur cette méthode pour générer les IRIs des objets. Cela ce défini donc de cette manière :\n```php\n * ...\n *      itemOperations={\n *          \"get\"={\n *              \"controller\"=NotFoundAction::class,\n *              \"read\"=false,\n *              \"output\"=false,\n *          },\n *          ...\n *      }\n * ...\n```\nDe plus il faudra forcément être authentifié dans notre cas pour requêter un item de `Step`\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdarkweak%2Fusainboltapi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdarkweak%2Fusainboltapi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdarkweak%2Fusainboltapi/lists"}