1
Fork 0
mirror of https://github.com/thegeneralist01/twitter-openapi synced 2026-01-11 23:50:26 +01:00
Signed-off-by: ふぁ <yuki@yuki0311.com>
This commit is contained in:
ふぁ 2023-05-05 21:11:19 +09:00
parent ca1fbb7815
commit cce687ba15
No known key found for this signature in database
GPG key ID: 83A8A5E74872A8AA
9 changed files with 268 additions and 95 deletions

View file

@ -436,7 +436,10 @@
}, },
"features": {} "features": {}
}, },
"create.json": { "=====v1.1====": {
"url": "https://twitter.com/i/api/1.1/"
},
"friendships/create.json": {
"include_profile_interstitial_type": 1, "include_profile_interstitial_type": 1,
"include_blocking": 1, "include_blocking": 1,
"include_blocked_by": 1, "include_blocked_by": 1,
@ -450,11 +453,91 @@
"include_ext_verified_type": 1, "include_ext_verified_type": 1,
"include_ext_profile_image_shape": 1, "include_ext_profile_image_shape": 1,
"skip_status": 1, "skip_status": 1,
"user_id": 1180389371481976833 "user_id": 44196397
}, },
"Template": { "friendships/destroy.json": {
"queryId": "", "include_profile_interstitial_type": 1,
"variables": {}, "include_blocking": 1,
"features": {} "include_blocked_by": 1,
"include_followed_by": 1,
"include_want_retweets": 1,
"include_mute_edge": 1,
"include_can_dm": 1,
"include_can_media_tag": 1,
"include_ext_has_nft_avatar": 1,
"include_ext_is_blue_verified": 1,
"include_ext_verified_type": 1,
"include_ext_profile_image_shape": 1,
"skip_status": 1,
"user_id": 44196397
},
"friends/following/list.json": {
"include_profile_interstitial_type": 1,
"include_blocking": 1,
"include_blocked_by": 1,
"include_followed_by": 1,
"include_want_retweets": 1,
"include_mute_edge": 1,
"include_can_dm": 1,
"include_can_media_tag": 1,
"include_ext_has_nft_avatar": 1,
"include_ext_is_blue_verified": 1,
"include_ext_verified_type": 1,
"include_ext_profile_image_shape": 1,
"skip_status": 1,
"cursor": -1,
"user_id": 17152334,
"count": 3,
"with_total_count": true
},
"search/typeahead.json": {
"include_ext_is_blue_verified": 1,
"include_ext_verified_type": 1,
"include_ext_profile_image_shape": 1,
"q": "aaa",
"src": "search_box",
"result_type": "events,users,topics"
},
"=====v2====": {
"url": "https://twitter.com/i/api/2"
},
"search/adaptive.json": {
"include_profile_interstitial_type": 1,
"include_blocking": 1,
"include_blocked_by": 1,
"include_followed_by": 1,
"include_want_retweets": 1,
"include_mute_edge": 1,
"include_can_dm": 1,
"include_can_media_tag": 1,
"include_ext_has_nft_avatar": 1,
"include_ext_is_blue_verified": 1,
"include_ext_verified_type": 1,
"include_ext_profile_image_shape": 1,
"skip_status": 1,
"cards_platform": "Web-12",
"include_cards": 1,
"include_ext_alt_text": true,
"include_ext_limited_action_results": false,
"include_quote_count": true,
"include_reply_count": 1,
"tweet_mode": "extended",
"include_ext_views": true,
"include_entities": true,
"include_user_entities": true,
"include_ext_media_color": true,
"include_ext_media_availability": true,
"include_ext_sensitive_media_warning": true,
"include_ext_trusted_friends_metadata": true,
"send_error_codes": true,
"simple_quoted_tweet": true,
"q": "elon musk",
"query_source": "trend_click",
"count": 20,
"requestContext": "launch",
"pc": 1,
"spelling_corrections": 1,
"include_ext_edit_control": true,
"ext": "mediaStats,highlightedLabel,hasNftAvatar,voiceInfo,birdwatchPivot,enrichments,superFollowMetadata,unmentionInfo,editControl,vibe"
} }
} }

View file

@ -53,11 +53,17 @@ security:
tags: tags:
- name: user - name: user
description: response User description: response User
- name: userList - name: user-list
description: response User list description: response User list
- name: tweet - name: tweet
description: response tweet description: response tweet
- name: post - name: post
description: post description: post
- name: v1.1 - name: v1.1-get
description: legacy APIs description: legacy APIs get
- name: v1.1-post
description: legacy APIs post
- name: v2-get
description: legacy APIs get
- name: v2-post
description: legacy APIs post

View file

@ -16,7 +16,7 @@ paths:
schema: schema:
$ref: "#/components/schemas/FollowResponse" $ref: "#/components/schemas/FollowResponse"
tags: tags:
- "userList" - "user-list"
/graphql/{{queryId}}/Followers: /graphql/{{queryId}}/Followers:
get: get:
@ -30,7 +30,7 @@ paths:
schema: schema:
$ref: "#/components/schemas/FollowResponse" $ref: "#/components/schemas/FollowResponse"
tags: tags:
- "userList" - "user-list"
components: components:
schemas: schemas:

View file

@ -0,0 +1,25 @@
openapi: 3.0.3
info:
title: Twitter OpenAPI
version: 0.0.1
paths:
/1.1/friends/following/list.json:
get:
operationId: getFriendsFollowingList
description: get friends following list
responses:
"200":
description: Successful operation
tags:
- "v1.1-get"
/1.1/search/typeahead.json:
get:
operationId: getSearchTypeahead
description: get search typeahead
responses:
"200":
description: Successful operation
tags:
- "v1.1-get"

View file

@ -0,0 +1,25 @@
openapi: 3.0.3
info:
title: Twitter OpenAPI
version: 0.0.1
paths:
/1.1/friendships/create.json:
post:
operationId: postCreateFriendships
description: post create friendships
responses:
"200":
description: Successful operation
tags:
- "v1.1-post"
/1.1/friendships/destroy.json:
post:
operationId: postDestroyFriendships
description: post destroy friendships
responses:
"200":
description: Successful operation
tags:
- "v1.1-post"

View file

@ -4,12 +4,12 @@ info:
version: 0.0.1 version: 0.0.1
paths: paths:
/1.1/friendships/create.json: /2/search/adaptive.json:
post: get:
operationId: postCreateFriendships operationId: getSearchAdaptive
description: post create friendships description: get search adaptive
responses: responses:
"200": "200":
description: Successful operation description: Successful operation
tags: tags:
- "v1.1" - "v2.0-get"

View file

@ -11,87 +11,106 @@ class Config:
"openapi": [AddSecuritySchemesOnSecuritySchemes()], "openapi": [AddSecuritySchemesOnSecuritySchemes()],
"request": { "request": {
key: [ key: [
ReplaceQueryIdPlaceholder(), ReplaceQueryIdPlaceholder(split=-1),
SetResponsesHeader(), SetResponsesHeader(suffix=None),
AddParametersOnContent(), AddParametersOnContent(split=-1),
] ]
for key in ["default", "user", "userList", "tweet"] for key in ["default", "user", "user-list", "tweet"]
} }
| { | {
"post": [ key: [
ReplaceQueryIdPlaceholder(), ReplaceQueryIdPlaceholder(split=-1),
SetResponsesHeader(), SetResponsesHeader(suffix=None),
AddParametersOnParameters(), AddParametersOnParameters(split=-1),
], ]
"v1.1": [SetResponsesHeader("v1.1"), AddParametersOnParameters()], for key in ["post"]
}
| {
key: [
SetResponsesHeader("legacy"),
AddParametersOnParameters(split=2),
]
for key in ["v1.1-get", "v1.1-post", "v2.0-get", "v2.0-post"]
}, },
}, },
"dart": { "dart": {
"openapi": [], "openapi": [],
"request": { "request": {
key: [ key: [
ReplaceQueryIdPlaceholder(), ReplaceQueryIdPlaceholder(split=-1),
AddSecuritySchemesOnHeader(), AddSecuritySchemesOnHeader(split=-1),
SetResponsesHeader(), SetResponsesHeader(suffix=None),
AddParametersOnParametersAsString(), AddParametersOnParametersAsString(split=-1),
] ]
for key in ["default", "user", "userList", "tweet"] for key in ["default", "user", "user-list", "tweet"]
} }
| { | {
"post": [ key: [
ReplaceQueryIdPlaceholder(), ReplaceQueryIdPlaceholder(split=-1),
AddSecuritySchemesOnHeader(), AddSecuritySchemesOnHeader(split=-1),
SetResponsesHeader(), SetResponsesHeader(suffix=None),
AddParametersOnParametersAsObject(), AddParametersOnParametersAsObject(split=-1),
], ]
"v1.1": [ for key in ["post"]
SetResponsesHeader("v1.1"), }
AddParametersOnParametersAsObject(), | {
], key: [
SetResponsesHeader(suffix="legacy"),
AddParametersOnParametersAsObject(split=2),
]
for key in ["v1.1-get", "v1.1-post", "v2.0-get", "v2.0-post"]
}, },
}, },
"typescript": { "typescript": {
"openapi": [AddSecuritySchemesOnSecuritySchemes()], "openapi": [AddSecuritySchemesOnSecuritySchemes()],
"request": { "request": {
key: [ key: [
ReplaceQueryIdPlaceholder(), ReplaceQueryIdPlaceholder(split=-1),
SetResponsesHeader(), SetResponsesHeader(suffix=None),
AddParametersOnParametersAsString(), AddParametersOnParametersAsString(split=-1),
] ]
for key in ["default", "user", "userList", "tweet"] for key in ["default", "user", "user-list", "tweet"]
} }
| { | {
"post": [ key: [
ReplaceQueryIdPlaceholder(), ReplaceQueryIdPlaceholder(split=-1),
SetResponsesHeader(), SetResponsesHeader(suffix=None),
AddParametersOnParametersAsObject(), AddParametersOnParametersAsObject(split=-1),
], ]
"v1.1": [ for key in ["post"]
SetResponsesHeader("v1.1"), }
AddParametersOnParametersAsObject(), | {
], key: [
SetResponsesHeader(suffix="legacy"),
AddParametersOnParametersAsObject(split=2),
]
for key in ["v1.1-get", "v1.1-post", "v2.0-get", "v2.0-post"]
}, },
}, },
"test": { "test": {
"openapi": [AddSecuritySchemesOnSecuritySchemes()], "openapi": [AddSecuritySchemesOnSecuritySchemes()],
"request": { "request": {
key: [ key: [
ReplaceQueryIdPlaceholder(), ReplaceQueryIdPlaceholder(split=-1),
SetResponsesHeader(), SetResponsesHeader(suffix=None),
AddParametersOnParametersAsString(), AddParametersOnParametersAsString(split=-1),
] ]
for key in ["default", "user", "userList", "tweet"] for key in ["default", "user", "user-list", "tweet"]
} }
| { | {
"post": [ key: [
ReplaceQueryIdPlaceholder(), ReplaceQueryIdPlaceholder(split=-1),
SetResponsesHeader(), SetResponsesHeader(suffix=None),
AddParametersOnParametersAsString(), AddParametersOnParametersAsString(split=-1),
], ]
"v1.1": [ for key in ["post"]
SetResponsesHeader("v1.1"), }
AddParametersOnParametersAsString(), | {
], key: [
SetResponsesHeader(suffix="legacy"),
AddParametersOnParametersAsObject(split=2),
]
for key in ["v1.1-get", "v1.1-post", "v2.0-get", "v2.0-post"]
}, },
}, },
} }

View file

@ -15,9 +15,9 @@ class HookBase:
properties = {i: fn(obj[i]) for i in obj} properties = {i: fn(obj[i]) for i in obj}
value = { value = {
"type": "object", "type": "object",
"required": [i for i in obj],
"properties": properties, "properties": properties,
} }
value.update({"required": [i for i in obj]} if len(obj) > 0 else {})
value.update({"default": properties} if default else {}) value.update({"default": properties} if default else {})
value.update({"example": properties} if example else {}) value.update({"example": properties} if example else {})
return value return value
@ -50,27 +50,46 @@ class HookBase:
return yaml.safe_load(f) return yaml.safe_load(f)
# HookBase extends
class OpenapiHookBase(HookBase): class OpenapiHookBase(HookBase):
def hook(self, value: dict): def hook(self, value: dict):
return value return value
class RequestHookBase(HookBase): class RequestHookBase(HookBase):
split: int
path_name: str
def __init__(self, split=1):
super().__init__()
self.split = split
def hook(self, path: str, value: dict): def hook(self, path: str, value: dict):
value["parameters"] = value.get("parameters", [])
self.path_name = "/".join(path.split("/")[self.split :])
return path, value return path, value
class AddSecuritySchemesOnSecuritySchemes(HookBase): # OpenapiHookBase extends
class AddSecuritySchemesOnSecuritySchemes(OpenapiHookBase):
def hook(self, value: dict): def hook(self, value: dict):
value = super().hook(value)
component = self.load_component("security_schemes") component = self.load_component("security_schemes")
param = component["components"]["securitySchemes"] param = component["components"]["securitySchemes"]
value["components"]["securitySchemes"].extend(param) value["components"]["securitySchemes"].extend(param)
return value return value
# RequestHookBase extends
class AddSecuritySchemesOnHeader(RequestHookBase): class AddSecuritySchemesOnHeader(RequestHookBase):
def hook(self, path: str, value: dict): def hook(self, path: str, value: dict):
value["parameters"] = value.get("parameters", []) path, value = super().hook(path, value)
component = self.load_component("security_schemes") component = self.load_component("security_schemes")
param = component["paths"]["/parameters"]["get"]["parameters"] param = component["paths"]["/parameters"]["get"]["parameters"]
value["parameters"].extend(param) value["parameters"].extend(param)
@ -79,30 +98,30 @@ class AddSecuritySchemesOnHeader(RequestHookBase):
class ReplaceQueryIdPlaceholder(RequestHookBase): class ReplaceQueryIdPlaceholder(RequestHookBase):
def hook(self, path: str, value: dict): def hook(self, path: str, value: dict):
path_name = path.split("/")[-1] path, value = super().hook(path, value)
new = self.PLACEHOLDER[path_name]["queryId"] new = self.PLACEHOLDER[self.path_name]["queryId"]
return path.replace(r"{{queryId}}", new), value return path.replace(r"{{queryId}}", new), value
class SetResponsesHeader(RequestHookBase): class SetResponsesHeader(RequestHookBase):
prexix: str suffix: str
def __init__(self, prexix: str = ""): def __init__(self, suffix: str | None = None):
super().__init__() super().__init__()
self.prexix = prexix if prexix == "" else "_" + prexix self.suffix = "" if suffix is None else "_" + suffix
def hook(self, path: str, value: dict): def hook(self, path: str, value: dict):
component = self.load_component("response_header" + self.prexix) path, value = super().hook(path, value)
component = self.load_component("response_header" + self.suffix)
value["responses"]["200"]["headers"] = component["components"]["headers"] value["responses"]["200"]["headers"] = component["components"]["headers"]
return path, value return path, value
class AddParametersOnParametersAsString(RequestHookBase): class AddParametersOnParametersAsString(RequestHookBase):
def hook(self, path: str, value: dict): def hook(self, path: str, value: dict):
value["parameters"] = value.get("parameters", []) path, value = super().hook(path, value)
path_name = path.split("/")[-1] for key in self.PLACEHOLDER[self.path_name].keys():
for key in self.PLACEHOLDER[path_name].keys(): example = json.dumps(self.PLACEHOLDER[self.path_name][key])
example = json.dumps(self.PLACEHOLDER[path_name][key])
value["parameters"].append( value["parameters"].append(
{ {
"name": key, "name": key,
@ -120,10 +139,9 @@ class AddParametersOnParametersAsString(RequestHookBase):
class AddParametersOnParametersAsObject(RequestHookBase): class AddParametersOnParametersAsObject(RequestHookBase):
def hook(self, path: str, value: dict): def hook(self, path: str, value: dict):
value["parameters"] = value.get("parameters", []) path, value = super().hook(path, value)
path_name = path.split("/")[-1] for key in self.PLACEHOLDER[self.path_name].keys():
for key in self.PLACEHOLDER[path_name].keys(): example = json.dumps(self.PLACEHOLDER[self.path_name][key])
example = json.dumps(self.PLACEHOLDER[path_name][key])
value["parameters"].append( value["parameters"].append(
{ {
"name": key, "name": key,
@ -141,9 +159,8 @@ class AddParametersOnParametersAsObject(RequestHookBase):
class AddParametersOnContent(RequestHookBase): class AddParametersOnContent(RequestHookBase):
def hook(self, path: str, value: dict): def hook(self, path: str, value: dict):
value["parameters"] = value.get("parameters", []) path, value = super().hook(path, value)
path_name = path.split("/")[-1] for key in self.PLACEHOLDER[self.path_name].keys():
for key in self.PLACEHOLDER[path_name].keys():
value["parameters"].append( value["parameters"].append(
{ {
"name": key, "name": key,
@ -152,7 +169,7 @@ class AddParametersOnContent(RequestHookBase):
"content": { "content": {
"application/json": { "application/json": {
"schema": self.placeholder_to_yaml( "schema": self.placeholder_to_yaml(
self.PLACEHOLDER[path_name][key] self.PLACEHOLDER[self.path_name][key]
), ),
}, },
}, },
@ -163,16 +180,15 @@ class AddParametersOnContent(RequestHookBase):
class AddParametersOnParameters(RequestHookBase): class AddParametersOnParameters(RequestHookBase):
def hook(self, path: str, value: dict): def hook(self, path: str, value: dict):
value["parameters"] = value.get("parameters", []) path, value = super().hook(path, value)
path_name = path.split("/")[-1] for key in self.PLACEHOLDER[self.path_name].keys():
for key in self.PLACEHOLDER[path_name].keys():
value["parameters"].append( value["parameters"].append(
{ {
"name": key, "name": key,
"in": "query", "in": "query",
"required": True, "required": True,
"schema": self.placeholder_to_yaml( "schema": self.placeholder_to_yaml(
self.PLACEHOLDER[path_name][key] self.PLACEHOLDER[self.path_name][key]
), ),
} }
) )
@ -181,9 +197,8 @@ class AddParametersOnParameters(RequestHookBase):
class AddParametersOnBody(RequestHookBase): class AddParametersOnBody(RequestHookBase):
def hook(self, path: str, value: dict): def hook(self, path: str, value: dict):
value["parameters"] = value.get("parameters", []) path, value = super().hook(path, value)
path_name = path.split("/")[-1] data = self.PLACEHOLDER[self.path_name]
data = self.PLACEHOLDER[path_name]
schema = {i: self.placeholder_to_yaml(data[i]) for i in data.keys()} schema = {i: self.placeholder_to_yaml(data[i]) for i in data.keys()}
value["requestBody"] = { value["requestBody"] = {
"description": "body", "description": "body",