Browse Source

API documentation en cours

master
art.dambrine 5 years ago
parent
commit
709c51762f
  1. 10
      app.js
  2. 2
      controllers/etudiantController.js
  3. 305
      docs/swagger.json
  4. 0
      models/etudiantModel.js
  5. 22
      node_modules/swagger-ui-dist/README.md
  6. 14
      node_modules/swagger-ui-dist/absolute-path.js
  7. BIN
      node_modules/swagger-ui-dist/favicon-16x16.png
  8. BIN
      node_modules/swagger-ui-dist/favicon-32x32.png
  9. 60
      node_modules/swagger-ui-dist/index.html
  10. 17
      node_modules/swagger-ui-dist/index.js
  11. 68
      node_modules/swagger-ui-dist/oauth2-redirect.html
  12. 110
      node_modules/swagger-ui-dist/package.json
  13. 134
      node_modules/swagger-ui-dist/swagger-ui-bundle.js
  14. 1
      node_modules/swagger-ui-dist/swagger-ui-bundle.js.map
  15. 22
      node_modules/swagger-ui-dist/swagger-ui-standalone-preset.js
  16. 1
      node_modules/swagger-ui-dist/swagger-ui-standalone-preset.js.map
  17. 4
      node_modules/swagger-ui-dist/swagger-ui.css
  18. 1
      node_modules/swagger-ui-dist/swagger-ui.css.map
  19. 9
      node_modules/swagger-ui-dist/swagger-ui.js
  20. 1
      node_modules/swagger-ui-dist/swagger-ui.js.map
  21. 22
      node_modules/swagger-ui-express/LICENSE
  22. 239
      node_modules/swagger-ui-express/README.md
  23. 260
      node_modules/swagger-ui-express/index.js
  24. 103
      node_modules/swagger-ui-express/package.json
  25. 2
      package.json
  26. 2
      routes.js
  27. BIN
      welcome_page/images/main.jpg
  28. 320
      welcome_page/index.html

10
index.js → app.js

@ -3,9 +3,15 @@ const express = require("express")
const mongoose = require("mongoose") const mongoose = require("mongoose")
const bodyParser = require('body-parser'); const bodyParser = require('body-parser');
// Documentation de notre API
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./docs/swagger.json');
// Initialisation de l'app // Initialisation de l'app
const app = express() const app = express()
var path = require('path');
// Import des routes // Import des routes
const routes = require("./routes") const routes = require("./routes")
@ -16,8 +22,10 @@ app.use(bodyParser.urlencoded({
app.use(bodyParser.json()); app.use(bodyParser.json());
// Route pour notre documentation
app.use('/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); // documentation à la racine
app.get('/', (req, res) => res.send('Hello, allez à <a href="/api/etudiants">API-Etudiants</a>')); // route racine app.get('/', (req, res) => res.sendFile(path.join(__dirname + '/welcome_page/index.html'))); // route racine
app.use("/api",routes) // route /api par défaut app.use("/api",routes) // route /api par défaut

2
etudiantController.js → controllers/etudiantController.js

@ -1,4 +1,4 @@
Etudiant = require('./etudiantModel'); Etudiant = require('../models/etudiantModel');
// Handle index actions (method: GET) // Handle index actions (method: GET)
exports.index = function (req, res) { exports.index = function (req, res) {

305
docs/swagger.json

@ -0,0 +1,305 @@
{
"swagger": "2.0",
"info": {
"description": "Bienvenue pour tester ma nouvelle api de sauvegarde des etudiants. http://localhost:3000",
"version": "1.0.0",
"title": "Documentation API - Etudiants",
"contact": {
"email": "art-dambrine@live.fr"
}
},
"host": "localhost",
"basePath": "/api",
"tags": [
{
"name": "pet",
"description": "Everything about your Pets"
}
],
"schemes": [
"http"
],
"paths": {
"/pet": {
"post": {
"tags": [
"pet"
],
"summary": "Add a new pet to the store",
"description": "",
"operationId": "addPet",
"consumes": [
"application/json",
"application/xml"
],
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "Pet object that needs to be added to the store",
"required": true,
"schema": {
"$ref": "#/definitions/Pet"
}
}
],
"responses": {
"405": {
"description": "Invalid input"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
},
"put": {
"tags": [
"pet"
],
"summary": "Update an existing pet",
"description": "",
"operationId": "updatePet",
"consumes": [
"application/json",
"application/xml"
],
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"in": "body",
"name": "body",
"description": "Pet object that needs to be added to the store",
"required": true,
"schema": {
"$ref": "#/definitions/Pet"
}
}
],
"responses": {
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Pet not found"
},
"405": {
"description": "Validation exception"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
}
},
"/pet/{petId}": {
"get": {
"tags": [
"pet"
],
"summary": "Find pet by ID",
"description": "Returns a single pet",
"operationId": "getPetById",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "petId",
"in": "path",
"description": "ID of pet to return",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"200": {
"description": "successful operation",
"schema": {
"$ref": "#/definitions/Pet"
}
},
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Pet not found"
}
},
"security": [
{
"api_key": []
}
]
},
"post": {
"tags": [
"pet"
],
"summary": "Updates a pet in the store with form data",
"description": "",
"operationId": "updatePetWithForm",
"consumes": [
"application/x-www-form-urlencoded"
],
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "petId",
"in": "path",
"description": "ID of pet that needs to be updated",
"required": true,
"type": "integer",
"format": "int64"
},
{
"name": "name",
"in": "formData",
"description": "Updated name of the pet",
"required": false,
"type": "string"
},
{
"name": "status",
"in": "formData",
"description": "Updated status of the pet",
"required": false,
"type": "string"
}
],
"responses": {
"405": {
"description": "Invalid input"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
},
"delete": {
"tags": [
"pet"
],
"summary": "Deletes a pet",
"description": "",
"operationId": "deletePet",
"produces": [
"application/xml",
"application/json"
],
"parameters": [
{
"name": "api_key",
"in": "header",
"required": false,
"type": "string"
},
{
"name": "petId",
"in": "path",
"description": "Pet id to delete",
"required": true,
"type": "integer",
"format": "int64"
}
],
"responses": {
"400": {
"description": "Invalid ID supplied"
},
"404": {
"description": "Pet not found"
}
},
"security": [
{
"petstore_auth": [
"write:pets",
"read:pets"
]
}
]
}
}
},
"definitions": {
"Pet": {
"type": "object",
"required": [
"name",
"photoUrls"
],
"properties": {
"id": {
"type": "integer",
"format": "int64"
},
"category": {
"$ref": "#/definitions/Category"
},
"name": {
"type": "string",
"example": "doggie"
},
"photoUrls": {
"type": "array",
"xml": {
"name": "photoUrl",
"wrapped": true
},
"items": {
"type": "string"
}
},
"tags": {
"type": "array",
"xml": {
"name": "tag",
"wrapped": true
},
"items": {
"$ref": "#/definitions/Tag"
}
},
"status": {
"type": "string",
"description": "pet status in the store",
"enum": [
"available",
"pending",
"sold"
]
}
},
"xml": {
"name": "Pet"
}
}
}
}

0
etudiantModel.js → models/etudiantModel.js

22
node_modules/swagger-ui-dist/README.md

@ -0,0 +1,22 @@
# Swagger UI Dist
[![NPM version](https://badge.fury.io/js/swagger-ui-dist.svg)](http://badge.fury.io/js/swagger-ui-dist)
# API
This module, `swagger-ui-dist`, exposes Swagger-UI's entire dist folder as a dependency-free npm module.
Use `swagger-ui` instead, if you'd like to have npm install dependencies for you.
`SwaggerUIBundle` and `SwaggerUIStandalonePreset` can be imported:
```javascript
import { SwaggerUIBundle, SwaggerUIStandalonePreset } from "swagger-ui-dist"
```
To get an absolute path to this directory for static file serving, use the exported `getAbsoluteFSPath` method:
```javascript
const swaggerUiAssetPath = require("swagger-ui-dist").getAbsoluteFSPath()
// then instantiate server that serves files from the swaggerUiAssetPath
```
For anything else, check the [Swagger-UI](https://github.com/swagger-api/swagger-ui) repository.

14
node_modules/swagger-ui-dist/absolute-path.js

@ -0,0 +1,14 @@
/*
* getAbsoluteFSPath
* @return {string} When run in NodeJS env, returns the absolute path to the current directory
* When run outside of NodeJS, will return an error message
*/
const getAbsoluteFSPath = function () {
// detect whether we are running in a browser or nodejs
if (typeof module !== "undefined" && module.exports) {
return require("path").resolve(__dirname)
}
throw new Error('getAbsoluteFSPath can only be called within a Nodejs environment');
}
module.exports = getAbsoluteFSPath

BIN
node_modules/swagger-ui-dist/favicon-16x16.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

BIN
node_modules/swagger-ui-dist/favicon-32x32.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

60
node_modules/swagger-ui-dist/index.html

@ -0,0 +1,60 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body
{
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js"> </script>
<script src="./swagger-ui-standalone-preset.js"> </script>
<script>
window.onload = function() {
// Begin Swagger UI call region
const ui = SwaggerUIBundle({
url: "https://petstore.swagger.io/v2/swagger.json",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
})
// End Swagger UI call region
window.ui = ui
}
</script>
</body>
</html>

17
node_modules/swagger-ui-dist/index.js

@ -0,0 +1,17 @@
try {
module.exports.SwaggerUIBundle = require("./swagger-ui-bundle.js")
module.exports.SwaggerUIStandalonePreset = require("./swagger-ui-standalone-preset.js")
} catch(e) {
// swallow the error if there's a problem loading the assets.
// allows this module to support providing the assets for browserish contexts,
// without exploding in a Node context.
//
// see https://github.com/swagger-api/swagger-ui/issues/3291#issuecomment-311195388
// for more information.
}
// `absolutePath` and `getAbsoluteFSPath` are both here because at one point,
// we documented having one and actually implemented the other.
// They were both retained so we don't break anyone's code.
module.exports.absolutePath = require("./absolute-path.js")
module.exports.getAbsoluteFSPath = require("./absolute-path.js")

68
node_modules/swagger-ui-dist/oauth2-redirect.html

@ -0,0 +1,68 @@
<!doctype html>
<html lang="en-US">
<title>Swagger UI: OAuth2 Redirect</title>
<body onload="run()">
</body>
</html>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1);
} else {
qp = location.search.substring(1);
}
arr = qp.split("&")
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value)
}
) : {}
isValid = qp.state === sentState
if ((
oauth2.auth.schema.get("flow") === "accessCode"||
oauth2.auth.schema.get("flow") === "authorizationCode"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}
</script>

110
node_modules/swagger-ui-dist/package.json

@ -0,0 +1,110 @@
{
"_args": [
[
"swagger-ui-dist@^3.18.1",
"/home/art/Documents/API-REST-Etudiants/api/node_modules/swagger-ui-express"
]
],
"_from": "swagger-ui-dist@>=3.18.1 <4.0.0",
"_hasShrinkwrap": false,
"_id": "swagger-ui-dist@3.25.0",
"_inCache": true,
"_installable": true,
"_location": "/swagger-ui-dist",
"_nodeVersion": "8.11.4",
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/swagger-ui-dist_3.25.0_1579299487236_0.9443448516912767"
},
"_npmUser": {
"email": "apiteam@swagger.io",
"name": "swagger-api"
},
"_npmVersion": "6.13.4",
"_phantomChildren": {},
"_requested": {
"name": "swagger-ui-dist",
"raw": "swagger-ui-dist@^3.18.1",
"rawSpec": "^3.18.1",
"scope": null,
"spec": ">=3.18.1 <4.0.0",
"type": "range"
},
"_requiredBy": [
"/swagger-ui-express"
],
"_resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.25.0.tgz",
"_shasum": "90279cdcc56e591fcfbe7b5240a9d653b989336d",
"_shrinkwrap": null,
"_spec": "swagger-ui-dist@^3.18.1",
"_where": "/home/art/Documents/API-REST-Etudiants/api/node_modules/swagger-ui-express",
"bugs": {
"url": "https://github.com/swagger-api/swagger-ui/issues"
},
"contributors": [
{
"url": "in alphabetical order"
},
{
"name": "Anna Bodnia",
"email": "anna.bodnia@gmail.com"
},
{
"name": "Buu Nguyen",
"email": "buunguyen@gmail.com"
},
{
"name": "Josh Ponelat",
"email": "jponelat@gmail.com"
},
{
"name": "Kyle Shockey",
"email": "kyleshockey1@gmail.com"
},
{
"name": "Robert Barnwell",
"email": "robert@robertismy.name"
},
{
"name": "Sahar Jafari",
"email": "shr.jafari@gmail.com"
}
],
"dependencies": {},
"description": "[![NPM version](https://badge.fury.io/js/swagger-ui-dist.svg)](http://badge.fury.io/js/swagger-ui-dist)",
"devDependencies": {},
"directories": {},
"dist": {
"fileCount": 16,
"integrity": "sha512-vwvJPPbdooTvDwLGzjIXinOXizDJJ6U1hxnJL3y6U3aL1d2MSXDmKg2139XaLBhsVZdnQJV2bOkX4reB+RXamg==",
"npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJeIjKfCRA9TVsSAnZWagAAFLkP/1oeu6E9uPtTXEF4qU6/\nlicQAiQ9UQ1m6NNaIv3obw30JnXGjQpRlqVYkSCvxJfYJwn8H3ujYn8kk+Qn\n8a2m/74C6v6FSok8tABZdsqHSY6uN1+ivBoBWDG96a9GiYH0qPReZTVZmOxT\nvZJcmf+1TpR1+Obl6/wVaKAPBI8e4vfgnbwW/SKlPgO8h9RpOFhtant1ngWI\n87q0jW9I4JCigU+rCQuhmU4MkQ10Rkzmvmfg22pwTovzluh+LdyYT3NVqe9s\n1WrfhMBdUVzdn2SrH9oU9CEO1M7Xys4wBI/lRDZTZMNSahXp9bRq9wEp18Lh\n68d/AHE3LkNatULGrjertuTbUJQXQ0SXZu4J2vzEpzMI4aD4Qkrgtd5Kmp3E\n1nP0mqEOcOgoWGmfTJZKjdcIrj64aqvRXFyDF3FnbZX8Yw16erKnaKdL/2Ub\nh7cGWodlu7FDGau2Gng2/V9p93Wbfh98wdVaLR8Lq7/6lvwROVMMQsZp9OZC\n3VM8HYAgARoFMpX8yi+k/5OGlWtnbOM3KRqzHt47UrlQo0XU2W92mSsU/FxM\ncNkvzIXl0l9YaZnqGIOHUgid4OHVqvzhtPObj+3W/7V9KjHrprrbtoAYs1cM\nv0CEqlwolkbVRMl80HllGoHQHIDoH8KVfxrap28DjwqkxiHLBkdhWLTP2ZsE\nrY19\r\n=6Tta\r\n-----END PGP SIGNATURE-----\r\n",
"shasum": "90279cdcc56e591fcfbe7b5240a9d653b989336d",
"tarball": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.25.0.tgz",
"unpackedSize": 9136956
},
"homepage": "https://github.com/swagger-api/swagger-ui#readme",
"license": "Apache-2.0",
"main": "index.js",
"maintainers": [
{
"name": "kyleshockey",
"email": "kyle.shockey1@gmail.com"
},
{
"name": "swagger",
"email": "apiteam@swagger.io"
},
{
"name": "swagger-api",
"email": "apiteam@swagger.io"
}
],
"name": "swagger-ui-dist",
"optionalDependencies": {},
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/swagger-api/swagger-ui.git"
},
"version": "3.25.0"
}

134
node_modules/swagger-ui-dist/swagger-ui-bundle.js

File diff suppressed because one or more lines are too long

1
node_modules/swagger-ui-dist/swagger-ui-bundle.js.map

File diff suppressed because one or more lines are too long

22
node_modules/swagger-ui-dist/swagger-ui-standalone-preset.js

File diff suppressed because one or more lines are too long

1
node_modules/swagger-ui-dist/swagger-ui-standalone-preset.js.map

File diff suppressed because one or more lines are too long

4
node_modules/swagger-ui-dist/swagger-ui.css

File diff suppressed because one or more lines are too long

1
node_modules/swagger-ui-dist/swagger-ui.css.map

File diff suppressed because one or more lines are too long

9
node_modules/swagger-ui-dist/swagger-ui.js

File diff suppressed because one or more lines are too long

1
node_modules/swagger-ui-dist/swagger-ui.js.map

File diff suppressed because one or more lines are too long

22
node_modules/swagger-ui-express/LICENSE

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2018 Scott IT London
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

239
node_modules/swagger-ui-express/README.md

@ -0,0 +1,239 @@
# Swagger UI Express
This module allows you to serve auto-generated [swagger-ui](https://swagger.io/tools/swagger-ui/) generated API docs from express, based on a `swagger.json` file. The result is living documentation for your API hosted from your API server via a route.
Swagger version is pulled from npm module swagger-ui-dist. Please use a lock file or specify the version of swagger-ui-dist you want to ensure it is consistent across environments.
You may be also interested in:
* [swagger-jsdoc](https://github.com/Surnet/swagger-jsdoc/blob/master/docs/GETTING-STARTED.md): Allows you to markup routes
with jsdoc comments. It then produces a full swagger yml config dynamically, which you can pass to this module to produce documentation. See below under the usage section for more info.
* [swagger tools](https://github.com/swagger-api): Various tools, including swagger editor, swagger code gen etc.
## Usage
Install using npm:
```bash
$ npm install swagger-ui-express
```
Express setup `app.js`
```javascript
const express = require('express');
const app = express();
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json');
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
```
or if you are using Express router
```javascript
const router = require('express').Router();
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json');
router.use('/api-docs', swaggerUi.serve);
router.get('/api-docs', swaggerUi.setup(swaggerDocument));
```
Open http://`<app_host>`:`<app_port>`/api-docs in your browser to view the documentation.
If you want to set up routing based on the swagger document checkout [swagger-express-router](https://www.npmjs.com/package/swagger-express-router)
### [swagger-jsdoc](https://www.npmjs.com/package/swagger-jsdoc)
If you are using swagger-jsdoc simply pass the swaggerSpec into the setup function:
```javascript
// Initialize swagger-jsdoc -> returns validated swagger spec in json format
const swaggerSpec = swaggerJSDoc(options);
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerSpec));
```
### Swagger Explorer
By default the Swagger Explorer bar is hidden, to display it pass true as the 'explorer' property of the options to the setup function:
```javascript
const express = require('express');
const app = express();
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json');
var options = {
explorer: true
};
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, options));
```
### Custom swagger options
To pass custom options e.g. validatorUrl, to the SwaggerUi client pass an object as the 'swaggerOptions' property of the options to the setup function:
```javascript
const express = require('express');
const app = express();
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json');
var options = {
swaggerOptions: {
validatorUrl: null
}
};
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, options));
```
For all the available options, refer to [Swagger UI Configuration](https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/configuration.md)
### Custom CSS styles
To customize the style of the swagger page, you can pass custom CSS as the 'customCss' property of the options to the setup function.
E.g. to hide the swagger header:
```javascript
const express = require('express');
const app = express();
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json');
var options = {
customCss: '.swagger-ui .topbar { display: none }'
};
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, options));
```
### Custom CSS styles from Url
You can also pass the url to a custom css file, the value must be the public url of the file and can be relative or absolute to the swagger path.
```javascript
const express = require('express');
const app = express();
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json');
var options = {
customCssUrl: '/custom.css'
};
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, options));
```
### Custom JS
If you would like to have full control over your HTML you can provide your own javascript file, value accepts absolute or relative path. Value must be the public url of the js file.
```javascript
const express = require('express');
const app = express();
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json');
var options = {
customJs: '/custom.js'
};
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument, options));
```
### Load swagger from url
To load your swagger from a url instead of injecting the document, pass `null` as the first parameter, and pass the relative or absolute URL as the 'url' property to 'swaggerOptions' in the setup function.
```javascript
const express = require('express');
const app = express();
const swaggerUi = require('swagger-ui-express');
var options = {
swaggerOptions: {
url: 'http://petstore.swagger.io/v2/swagger.json'
}
}
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(null, options));
```
To load multiple swagger documents from urls as a dropdown in the explorer bar, pass an array of object with `name` and `url` to 'urls' property to 'swaggerOptions' in the setup function.
```javascript
const express = require('express');
const app = express();
const swaggerUi = require('swagger-ui-express');
var options = {
explorer: true,
swaggerOptions: {
urls: [
{
url: 'http://petstore.swagger.io/v2/swagger.json',
name: 'Spec1'
},
{
url: 'http://petstore.swagger.io/v2/swagger.json',
name: 'Spec2'
}
]
}
}
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(null, options));
```
Make sure 'explorer' option is set to 'true' in your setup options for the dropdown to be visible.
### Load swagger from yaml file
To load your swagger specification yaml file you need to use a module able to convert yaml to json; for instance `yamljs`.
npm install --save yamljs
```javascript
const express = require('express');
const app = express();
const swaggerUi = require('swagger-ui-express');
const YAML = require('yamljs');
const swaggerDocument = YAML.load('./swagger.yaml');
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
```
### Modify swagger file on the fly before load
To dynamically set the host, or any other content, in the swagger file based on the incoming request object you may pass the json via the req object; to achieve this just do not pass the the swagger json to the setup function and it will look for `swaggerDoc` in the `req` object.
```javascript
const express = require('express');
const app = express();
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('./swagger.json');
app.use('/api-docs', function(req, res, next){
swaggerDocument.host = req.get('host');
req.swaggerDoc = swaggerDocument;
next();
}, swaggerUi.serve, swaggerUi.setup());
```
## Requirements
* Node v0.10.32 or above
* Express 4 or above
## Testing
* Install phantom
* `npm install`
* `npm test`

260
node_modules/swagger-ui-express/index.js

@ -0,0 +1,260 @@
'use strict'
var express = require('express')
var swaggerUi = require('swagger-ui-dist')
var favIconHtml = '<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />' +
'<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />'
var swaggerInit = ''
var htmlTplString = `
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title><% title %></title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
<% favIconString %>
<% customJs %>
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body {
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;width:0;height:0">
<defs>
<symbol viewBox="0 0 20 20" id="unlocked">
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path>
</symbol>
<symbol viewBox="0 0 20 20" id="locked">
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="close">
<path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow">
<path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow-down">
<path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"/>
</symbol>
<symbol viewBox="0 0 24 24" id="jump-to">
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"/>
</symbol>
<symbol viewBox="0 0 24 24" id="expand">
<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>
</symbol>
</defs>
</svg>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js"> </script>
<script src="./swagger-ui-standalone-preset.js"> </script>
<script src="./swagger-ui-init.js"> </script>
<% customCssUrl %>
<style>
<% customCss %>
</style>
</body>
</html>
`
var jsTplString = `
window.onload = function() {
// Build a system
var url = window.location.search.match(/url=([^&]+)/);
if (url && url.length > 1) {
url = decodeURIComponent(url[1]);
} else {
url = window.location.origin;
}
<% swaggerOptions %>
url = options.swaggerUrl || url
var urls = options.swaggerUrls
var customOptions = options.customOptions
var spec1 = options.swaggerDoc
var swaggerOptions = {
spec: spec1,
url: url,
urls: urls,
dom_id: '#swagger-ui',
deepLinking: true,
presets: [
SwaggerUIBundle.presets.apis,
SwaggerUIStandalonePreset
],
plugins: [
SwaggerUIBundle.plugins.DownloadUrl
],
layout: "StandaloneLayout"
}
for (var attrname in customOptions) {
swaggerOptions[attrname] = customOptions[attrname];
}
var ui = SwaggerUIBundle(swaggerOptions)
if (customOptions.oauth) {
ui.initOAuth(customOptions.oauth)
}
if (customOptions.authAction) {
ui.authActions.authorize(customOptions.authAction)
}
window.ui = ui
}
`
var generateHTML = function (swaggerDoc, opts, options, customCss, customfavIcon, swaggerUrl, customSiteTitle, _htmlTplString, _jsTplString) {
var isExplorer
var customJs
var swaggerUrls
var customCssUrl
if (opts && typeof opts === 'object') {
options = opts.swaggerOptions
customCss = opts.customCss
customJs = opts.customJs
customfavIcon = opts.customfavIcon
swaggerUrl = opts.swaggerUrl
swaggerUrls = opts.swaggerUrls
isExplorer = opts.explorer || !!swaggerUrls
customSiteTitle = opts.customSiteTitle
customCssUrl = opts.customCssUrl
} else {
//support legacy params based function
isExplorer = opts
}
options = options || {}
var explorerString = isExplorer ? '' : '.swagger-ui .topbar .download-url-wrapper { display: none }'
customCss = explorerString + ' ' + customCss || explorerString
customfavIcon = customfavIcon || false
customSiteTitle = customSiteTitle || 'Swagger UI'
_htmlTplString = _htmlTplString || htmlTplString
_jsTplString = _jsTplString || jsTplString
var favIconString = customfavIcon ? '<link rel="icon" href="' + customfavIcon + '" />' : favIconHtml
var htmlWithCustomCss = _htmlTplString.toString().replace('<% customCss %>', customCss)
var htmlWithFavIcon = htmlWithCustomCss.replace('<% favIconString %>', favIconString)
var htmlWithCustomJs = htmlWithFavIcon.replace('<% customJs %>', customJs ? `<script src="${customJs}"></script>` : '')
var htmlWithCustomCssUrl = htmlWithCustomJs.replace('<% customCssUrl %>', customCssUrl ? `<link href="${customCssUrl}" rel="stylesheet">` : '')
var initOptions = {
swaggerDoc: swaggerDoc || undefined,
customOptions: options,
swaggerUrl: swaggerUrl || undefined,
swaggerUrls: swaggerUrls || undefined
}
swaggerInit = _jsTplString.toString().replace('<% swaggerOptions %>', stringify(initOptions))
return htmlWithCustomCssUrl.replace('<% title %>', customSiteTitle)
}
var setup = function (swaggerDoc, opts, options, customCss, customfavIcon, swaggerUrl, customSiteTitle) {
return function (req, res) {
if (req.swaggerDoc) {
var reqHtml = generateHTML(req.swaggerDoc, opts, options, customCss, customfavIcon, swaggerUrl, customSiteTitle, htmlTplString, jsTplString)
res.send(reqHtml)
} else {
var html = generateHTML(swaggerDoc, opts, options, customCss, customfavIcon, swaggerUrl, customSiteTitle, htmlTplString, jsTplString)
res.send(html)
}
}
}
function swaggerInitFn(req, res, next) {
if (req.url === '/package.json') {
res.sendStatus(404)
} else if (req.url === '/swagger-ui-init.js') {
res.set('Content-Type', 'application/javascript')
res.send(swaggerInit)
} else {
next()
}
}
var swaggerInitFunction = function (swaggerDoc, opts) {
var swaggerInitFile = jsTplString.toString().replace('<% swaggerOptions %>', stringify(opts))
return function (req, res, next) {
if (req.url === '/package.json') {
res.sendStatus(404)
} else if (req.url === '/swagger-ui-init.js') {
res.set('Content-Type', 'application/javascript')
res.send(swaggerInitFile)
} else {
next()
}
}
}
var swaggerAssetMiddleware = options => {
var opts = options || {}
opts.index = false
return express.static(swaggerUi.getAbsoluteFSPath(), opts)
}
var serveFiles = function (swaggerDoc, opts) {
opts = opts || {}
var initOptions = {
swaggerDoc: swaggerDoc || undefined,
customOptions: opts.swaggerOptions || {},
swaggerUrl: opts.swaggerUrl || {},
swaggerUrls: opts.swaggerUrls || undefined
}
var swaggerInitWithOpts = swaggerInitFunction(swaggerDoc, initOptions)
return [swaggerInitWithOpts, swaggerAssetMiddleware()]
}
var serve = [swaggerInitFn, swaggerAssetMiddleware()]
var serveWithOptions = options => [swaggerInitFn, swaggerAssetMiddleware(options)]
var stringify = function (obj, prop) {
var placeholder = '____FUNCTIONPLACEHOLDER____'
var fns = []
var json = JSON.stringify(obj, function (key, value) {
if (typeof value === 'function') {
fns.push(value)
return placeholder
}
return value
}, 2)
json = json.replace(new RegExp('"' + placeholder + '"', 'g'), function (_) {
return fns.shift()
})
return 'var options = ' + json + ';'
}
module.exports = {
setup: setup,
serve: serve,
serveWithOptions: serveWithOptions,
generateHTML: generateHTML,
serveFiles: serveFiles
}

103
node_modules/swagger-ui-express/package.json

@ -0,0 +1,103 @@
{
"_args": [
[
"swagger-ui-express",
"/home/art/Documents/API-REST-Etudiants/api"
]
],
"_from": "swagger-ui-express@latest",
"_hasShrinkwrap": false,
"_id": "swagger-ui-express@4.1.4",
"_inCache": true,
"_installable": true,
"_location": "/swagger-ui-express",
"_nodeVersion": "8.9.3",
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/swagger-ui-express_4.1.4_1584822083241_0.09336378664252143"
},
"_npmUser": {
"email": "scottie1984@gmail.com",
"name": "scottie1984"
},
"_npmVersion": "5.5.1",
"_phantomChildren": {},
"_requested": {
"name": "swagger-ui-express",
"raw": "swagger-ui-express",
"rawSpec": "",
"scope": null,
"spec": "latest",
"type": "tag"
},
"_requiredBy": [
"#USER"
],
"_resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.1.4.tgz",
"_shasum": "8b814ad998b850a1cf90e71808d6d0a8a8daf742",
"_shrinkwrap": null,
"_spec": "swagger-ui-express",
"_where": "/home/art/Documents/API-REST-Etudiants/api",
"author": {
"email": "scottie1984@gmail.com",
"name": "Stephen Scott"
},
"bugs": {
"url": "https://github.com/scottie1984/swagger-ui-express/issues"
},
"dependencies": {
"swagger-ui-dist": "^3.18.1"
},
"description": "Swagger UI Express",
"devDependencies": {
"es6-shim": "0.35.2",
"express": "4.12.2",
"mocha": "2.2.5",
"phantom": "2.1.21"
},
"directories": {},
"dist": {
"fileCount": 4,
"integrity": "sha512-Ea96ecpC+Iq9GUqkeD/LFR32xSs8gYqmTW1gXCuKg81c26WV6ZC2FsBSPVExQP6WkyUuz5HEiR0sEv/HCC343g==",
"npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJedndDCRA9TVsSAnZWagAAOusP/3O+4gsBAfyF4+eiOXVT\nBKNCOM9xh+QrtMDOrOx9QEGCSyqFtoM890YeWhavV+8bo8FMkj7H/LbsPEVA\ngLUVZc2QBV8g5wDkYr9eVf/ARZkRs3GYAYicgPBD/3Fc5//VGhd5jvN4Fv7N\n7FeGmDrqXevPnT1KtSXQziae9GtAofFSg+ZZdTreRdBlRfcPxQx1dBhxi+Qp\n8ewFSnin3ulbI9cIF1hbuVErGvZJ9O2ObG/rq8ZttwlAHbv+Gf9oHJ07qJak\ntt8/KEJ83I+OXmOw8wMvihzohBEBceNjf/bgp81xhGZjCzelq42x5LNnumQS\nz8hmXE28JwlI8uCrMnfctoAr+9PX5gSMsRiO49KIESZlAidqgwLudPsL6nne\ni48spEWwFRqFHcZumhDW96GohYcwcNPXz5fjM14Hm9Y4UfntvjV2we+8p0Qz\ngNKPkIMeFQ2yHm+OkEK+Lx2Gkcljgecns8Kpf/6of6SvLdzquqPow43/Z93J\nbsbJcxLop04bdwcNZKntOg0QnX5nsgHX65NcJHp5q+S3m2qDrICEZLzcwfrS\ntyby55RYaaD+K5kW38RGMYFxlLYBgK75WdSvnh/k44kHl5BB92j+U4oSECpg\nukdiaUurRz2YRQlEWek2/rQnvCCTcQtocB5/rtgTLWM+Mi0NrY4hECfqQlsM\nmn8N\r\n=a4nH\r\n-----END PGP SIGNATURE-----\r\n",
"shasum": "8b814ad998b850a1cf90e71808d6d0a8a8daf742",
"tarball": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.1.4.tgz",
"unpackedSize": 18367
},
"engines": {
"node": ">= v0.10.32"
},
"gitHead": "da6d0e24a703a6c274385f9523252b56ad6538a4",
"homepage": "https://github.com/scottie1984/swagger-ui-express",
"keywords": [
"documentation",
"express",
"json",
"swagger",
"ui"
],
"license": "MIT",
"main": "./index.js",
"maintainers": [
{
"name": "scottie1984",
"email": "scottie1984@gmail.com"
}
],
"name": "swagger-ui-express",
"optionalDependencies": {},
"peerDependencies": {
"express": ">=4.0.0"
},
"private": false,
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/scottie1984/swagger-ui-express.git"
},
"scripts": {
"test": "mocha test/*",
"test-app": "node ./test/testapp/run.js "
},
"version": "4.1.4"
}

2
package.json

@ -5,7 +5,7 @@
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon index.js" "start": "nodemon app.js"
}, },
"author": "Arthur Dambrine", "author": "Arthur Dambrine",
"license": "ISC", "license": "ISC",

2
routes.js

@ -10,7 +10,7 @@ router.get('/', function (req, res) {
}); });
// Import etudiant controller // Import etudiant controller
var etudiantController = require('./etudiantController'); var etudiantController = require('./controllers/etudiantController');
// GET All etudiants // GET All etudiants
router.route('/etudiants') router.route('/etudiants')

BIN
welcome_page/images/main.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 868 KiB

320
welcome_page/index.html

@ -0,0 +1,320 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link href="styles.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Crete+Round" rel="stylesheet">
<title>Arthur DAMBRINE</title>
<style>
/* GENERAL */
*{
margin: 0;
padding: 0;
}
body{
font-family: Arial, sans-serif;
font-size: 15px;
}
h1, h2, h3, h4{
color: #444;
}
h1{
font-family: 'Crete Round', serif;
font-size: 45px;
}
h2{
font-size: 55px;
}
h3{
font-size: 30px;
}
h4{
font-size: 24px;
}
p{
line-height: 20px;
color: #444;
}
a{
text-decoration: none;
color: #777;
}
ul{
list-style: none;
}
.wrapper{
width: 940px;
margin: 0 auto;
padding: 0 10px;
}
.green{
color:#72a8ec;
}
.clear{
clear:both;
}
small{
font-size: 13px;
font-style: italic;
}
/* HEADER */
header{
height: 120px;
}
header h1{
float:left;
margin-top: 32px;
}
header nav{
float:right;
margin-top: 50px;
}
header nav ul li{
float: left;
display: inline-block;
}
header nav ul li a{
text-transform: uppercase;
font-weight: bold;
margin-right: 20px;
}
/* MAIN-IMAGE */
#main-image{
height: 300px;
background: url('https://image.freepik.com/photos-gratuite/fond-bois-vue-dessus_23-2148234292.jpg') center;
}
#main-image h2{
color : #FFFFFF;
font-size: 3em;
font-weight: normal;
text-transform: uppercase;
text-align: center;
padding: 40px 0 40px 0;
margin-bottom: 20px;
}
.button-1{
display: block;
width: 120px;
height: 50px;
background: #72a8ec;
color: #fff;
font-size: 20px;
margin: 0 auto;
line-height: 50px;
text-align: center;
border-radius: 3px;
}
.button-1:hover{
background: #444;
}
/* STEPS */
#steps ul{
margin: 80px 0;
}
#steps ul li{
width: 300px;
float: left;
padding-top: 140px;
text-align: center;
margin-right: 10px;
}
#steps h4{
text-transform: uppercase;
margin-bottom: 20px;
}
#steps p{
margin-bottom: 20px;
font-size: 0.97em;
}
/* POSSIBILITIES */
#possibilities{
background-color: #efefef;
padding: 60px 0;
}
#possibilities article{
width: 460px;
height: 270px;
float: left;
border-radius: 10px;
}
#possibilities article:first-child{
margin-right: 20px;
}
.overlay{
background: rgba(255,255,255,0.95);
height: 100%;
width: 190px;
padding: 20px;
border-radius: 10px 0 0 10px;
text-align: center;
box-sizing: border-box;
}
article h4{
border-bottom: 1px solid #ddd;
padding-bottom: 20px;
text-transform: uppercase;
margin-bottom: 20px;
text-align: center;
}
#possibilities p{
text-align: center;
margin-bottom: 20px;
}
.button-2{
color: #fff;
background-color: #ff7a00;
padding: 6px 20px;
border-radius: 3px;
}
.button-2:hover{
background-color: #02b8dd;
}
/* CONTACT */
#contact{
padding: 60px 0;
text-align: center;
}
#contact h3{
width: 400px;
text-transform: uppercase;
margin: 0 auto 20px auto;
border-bottom: 1px solid #02b8dd;
padding-bottom: 20px;
}
form{
margin: 100px auto;
}
label{
font-weight: bold;
font-size: 20px;
margin-right: 10px;
color: #777;
}
input[type="text"]{
padding: 10px;
font-size: 20px;
margin-right: 20px;
border: 2px solid #ddd;
border-radius: 3px;
}
.button-3{
color: #fff;
font-size: 20px;
font-weight: bold;
padding: 11px;
background-color: #72a8ec;
border-style: none;
border-radius: 3px;
}
.button-3:hover{
background-color: #444;
}
/* FOOTER */
footer{
height: 160px;
background-color: #444;
margin-top: 70px;
}
footer h1{
color:#fff;
text-align: center;
padding-top: 40px;
}
.copyright{
text-align: center;
font-weight: bold;
color: #777;
}
</style>
</head>
<body>
<header>
<div class="wrapper">
<h1>Arthur DAMBRINE<span class="green">.</span></h1>
<nav>
<ul>
<li><a href="">Accueil</a></li>
<li><a href="/api">API</a></li>
<li><a href="/docs">Documentation</a></li>
</ul>
</nav>
</div>
</header>
<section id="main-image">
<div class="wrapper">
<h2>Venez tester mon <br><strong>API</strong></h2>
</div>
<a href="/api" class="button-1">Let's go !</a>
</section>
<footer>
<div class="wrapper">
<h1>Fais avec amour<span class="green">.</span></h1>
<div class="copyright">Copyright © 2020. Tous droits réservés.</div>
</div>
</footer>
</body>
</html>
Loading…
Cancel
Save