Added 'version' field (might not work on older versions), improved Postman schema, initial OpenAPI implementation

This commit is contained in:
Sys 2021-07-31 17:01:46 +02:00
parent 3eef215858
commit 137960dea2
No known key found for this signature in database
GPG Key ID: 3CD2C29F8AB39BFD
4 changed files with 226 additions and 23 deletions

View File

@ -33,13 +33,33 @@ class SchemaExtractor
'answerPreCheckoutQuery'
];
private Dom $dom;
private string $version;
/**
* SchemaExtractor constructor.
* @param LoggerInterface $logger
* @param string $url
* @throws ChildNotFoundException
* @throws CircularException
* @throws ClientExceptionInterface
* @throws ContentLengthException
* @throws LogicalException
* @throws StrictException
* @throws Throwable
*/
public function __construct(private LoggerInterface $logger, private string $url = Versions::LATEST)
{
$this->dom = new Dom();
try {
$this->dom->loadFromURL($this->url);
} catch (Throwable $e) {
$this->logger->critical(sprintf('Unable to load data from URL "%s": %s', $this->url, $e->getMessage()));
throw $e;
}
$this->version = $this->parseVersion();
$this->logger->info('Bot API version: ' . $this->version);
}
/**
@ -76,6 +96,28 @@ class SchemaExtractor
return ['description' => $description, 'table' => $table, 'extended_by' => $extendedBy];
}
private function parseVersion(): string
{
/** @var Dom\Node\AbstractNode $element */
$element = $this->dom->find('h3')[0];
$tag = '';
while ($tag != 'p') {
try {
$element = $element->nextSibling();
} catch (ChildNotFoundException | ParentNotFoundException) {
continue;
}
$tag = $element->tag->name();
}
$versionNumbers = explode('.', str_replace('Bot API ', '', $element->innerText));
return sprintf(
'%s.%s.%s',
$versionNumbers[0] ?? '1',
$versionNumbers[1] ?? '0',
$versionNumbers[2] ?? '0'
);
}
/**
* @return array
* @throws ChildNotFoundException
@ -88,28 +130,24 @@ class SchemaExtractor
* @throws ClientExceptionInterface
* @throws Throwable
*/
#[ArrayShape(['version' => "string", 'methods' => "array", 'types' => "array"])]
public function extract(): array
{
$dom = new Dom;
try {
$dom->loadFromURL($this->url);
$elements = $this->dom->find('h4');
} catch (Throwable $e) {
$this->logger->critical(sprintf('Unable to load data from URL "%s": %s', $this->url, $e->getMessage()));
throw $e;
}
try {
$elements = $dom->find('h4');
} catch (Throwable $e) {
$this->logger->critical(sprintf('Unable to load data from URL "%s": %s', $this->url, $e->getMessage()));
throw $e;
}
$data = [];
$data = ['version' => $this->version];
/* @var Dom\Node\AbstractNode $element */
foreach ($elements as $element) {
if (!str_contains($name = $element->text, ' ')) {
$isMethod = lcfirst($name) == $name;
$path = $isMethod ? 'methods' : 'types';
['description' => $description, 'table' => $table, 'extended_by' => $extendedBy] = self::parseNode($element);
['description' => $description, 'table' => $table, 'extended_by' => $extendedBy] = self::parseNode(
$element
);
$data[$path][] = self::generateElement(
$name,
trim($description),

View File

@ -2,6 +2,7 @@
namespace TgScraper;
use BadMethodCallException;
use Exception;
use InvalidArgumentException;
use JetBrains\PhpStorm\ArrayShape;
@ -27,6 +28,11 @@ use Throwable;
class Generator
{
/**
* Path to templates directory.
*/
public const TEMPLATES_DIRECTORY = __DIR__ . '/../templates';
/**
* @var array
*/
@ -53,8 +59,8 @@ class Generator
?array $schema = null
) {
if (empty($schema)) {
$extractor = new SchemaExtractor($this->logger, $this->url);
try {
$extractor = new SchemaExtractor($this->logger, $this->url);
$this->logger->info('Schema not provided, extracting from URL.');
$schema = $extractor->extract();
} catch (Throwable $e) {
@ -179,6 +185,14 @@ class Generator
return Yaml::dump($this->schema, $inline, $indent, $flags);
}
/**
* @return string
*/
public function toOpenApi(): string
{
throw new BadMethodCallException('Not implemented');
}
/**
* Thanks to davtur19 (https://github.com/davtur19/TuriBotGen/blob/master/postman.php)
@ -189,24 +203,16 @@ class Generator
public function toPostman(
int $options = 0
): string {
$result = [
'info' => [
'name' => 'Telegram Bot API',
'schema' => 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json'
],
'variable' => [
'key' => 'token',
'value' => '1234:AAbbcc',
'type' => 'string'
]
];
$template = file_get_contents(self::TEMPLATES_DIRECTORY . '/postman.json');
$result = json_decode($template, true);
$result['info']['version'] = $this->schema['version'];
foreach ($this->schema['methods'] as $method) {
$formData = [];
if (!empty($method['fields'])) {
foreach ($method['fields'] as $field) {
$formData[] = [
'key' => $field['name'],
'value' => '',
'disabled' => !$field['required'],
'description' => sprintf(
'%s. %s',
$field['required'] ? 'Required' : 'Optional',

144
templates/openapi.json Normal file
View File

@ -0,0 +1,144 @@
{
"openapi": "3.0.0",
"info": {
"title": "Telegram Bot API",
"description": "Auto-generated OpenAPI schema by TGScraper.",
"version": "1.0.0"
},
"servers": [
{
"url": "https://api.telegram.org/bot{token}",
"variables": {
"token": {
"default": "1234:AAbbcc",
"description": "Bot's unique authentication token, given by @BotFather."
}
}
}
],
"externalDocs": {
"description": "Official Telegram Bot API documentation",
"url": "https://core.telegram.org/bots/api"
},
"components": {
"responses": {
"BadRequest": {
"description": "Bad request, you have provided malformed data.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"Unauthorized": {
"description": "The authorization token is invalid or it has been revoked.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"Forbidden": {
"description": "This action is forbidden.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"NotFound": {
"description": "The specified resource was not found.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"Conflict": {
"description": "There is a conflict with another instance using webhook or polling.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"TooManyRequests": {
"description": "You're doing too many requests, retry after a while.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
}
},
"schemas": {
"Response": {
"type": "object",
"required": [
"ok"
],
"properties": {
"ok": {
"type": "boolean"
}
}
},
"Success": {
"allOf": [
{
"$ref": "#/components/schemas/Response"
},
{
"type": "object",
"required": [
"result"
],
"properties": {
"result": {
"type": "object"
}
}
}
]
},
"Error": {
"allOf": [
{
"$ref": "#/components/schemas/Response"
},
{
"type": "object",
"required": [
"error_code",
"description"
],
"properties": {
"error_code": {
"type": "integer"
},
"description": {
"type": "string"
},
"parameters": {
"$ref": "#/components/schemas/ResponseParameters"
}
}
}
]
}
}
},
"paths": {}
}

15
templates/postman.json Normal file
View File

@ -0,0 +1,15 @@
{
"info": {
"name": "Telegram Bot API",
"description": "Auto-generated Postman collection by TGScraper.",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
"version": "1.0.0"
},
"variable": {
"key": "token",
"description": "Bot's unique authentication token, given by @BotFather.",
"type": "string",
"value": "1234:AAbbcc"
},
"item": []
}