API: OpenAPI 3 spec and auto generated docs (#3650)
This commit is contained in:
parent
4a45996bfc
commit
35526bef9b
18 changed files with 1638 additions and 388 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -58,3 +58,5 @@ _docker-storage/
|
|||
|
||||
# YARD generated doc (in the Gitdocs folder)
|
||||
docs/.static/ruby-doc/
|
||||
# ReDoc generated API doc (in the Gitdocs folder)
|
||||
docs/.static/api/
|
||||
|
|
|
|||
|
|
@ -31,12 +31,7 @@ module Api
|
|||
end
|
||||
|
||||
def show
|
||||
relation = Article.published.includes(:user)
|
||||
@article = if params[:id] == "by_path"
|
||||
relation.find_by!(path: params[:url]).decorate
|
||||
else
|
||||
relation.find(params[:id]).decorate
|
||||
end
|
||||
@article = Article.published.includes(:user).find(params[:id]).decorate
|
||||
end
|
||||
|
||||
def onboarding
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ class CacheBuster
|
|||
bust_home_pages(article)
|
||||
bust_tag_pages(article)
|
||||
bust("/api/articles/#{article.id}")
|
||||
bust("/api/articles/by_path?url=#{article.path}")
|
||||
return unless article.collection_id
|
||||
|
||||
article.collection&.articles&.find_each do |a|
|
||||
|
|
|
|||
|
|
@ -14,31 +14,36 @@ json.array! @articles do |article|
|
|||
json.positive_reactions_count article.positive_reactions_count
|
||||
json.published_timestamp article.published_timestamp
|
||||
|
||||
user = article.user
|
||||
user_profile_image = ProfileImage.new(article.user)
|
||||
json.user do
|
||||
json.name article.user.name
|
||||
json.username article.user.username
|
||||
json.twitter_username article.user.twitter_username
|
||||
json.github_username article.user.github_username
|
||||
json.website_url article.user.processed_website_url
|
||||
json.profile_image ProfileImage.new(article.user).get(640)
|
||||
json.profile_image_90 ProfileImage.new(article.user).get(90)
|
||||
json.name user.name
|
||||
json.username user.username
|
||||
json.twitter_username user.twitter_username
|
||||
json.github_username user.github_username
|
||||
json.website_url user.processed_website_url
|
||||
json.profile_image user_profile_image.get(640)
|
||||
json.profile_image_90 user_profile_image.get(90)
|
||||
end
|
||||
|
||||
if article.organization
|
||||
organization = article.organization
|
||||
organization_profile_image = ProfileImage.new(article.organization)
|
||||
json.organization do
|
||||
json.name article.organization.name
|
||||
json.username article.organization.username
|
||||
json.slug article.organization.slug
|
||||
json.profile_image ProfileImage.new(article.organization).get(640)
|
||||
json.profile_image_90 ProfileImage.new(article.organization).get(90)
|
||||
json.name organization.name
|
||||
json.username organization.username
|
||||
json.slug organization.slug
|
||||
json.profile_image organization_profile_image.get(640)
|
||||
json.profile_image_90 organization_profile_image.get(90)
|
||||
end
|
||||
end
|
||||
|
||||
if FlareTag.new(article).tag
|
||||
flare_tag = FlareTag.new(article).tag
|
||||
if flare_tag
|
||||
json.flare_tag do
|
||||
json.name FlareTag.new(article).tag.name
|
||||
json.bg_color_hex FlareTag.new(article).tag.bg_color_hex
|
||||
json.text_color_hex FlareTag.new(article).tag.text_color_hex
|
||||
json.name flare_tag.name
|
||||
json.bg_color_hex flare_tag.bg_color_hex
|
||||
json.text_color_hex flare_tag.text_color_hex
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -22,8 +22,6 @@ json.last_comment_at @article.last_comment_at&.utc&.iso8601
|
|||
|
||||
json.body_html @article.processed_html
|
||||
json.body_markdown @article.body_markdown
|
||||
json.ltag_style(@article.liquid_tags_used.map { |ltag| Rails.application.assets["ltags/#{ltag}.css"].to_s.html_safe })
|
||||
json.ltag_script(@article.liquid_tags_used.map { |ltag| ltag.script.html_safe })
|
||||
|
||||
json.user do
|
||||
json.name @article.user.name
|
||||
|
|
|
|||
|
|
@ -1,331 +0,0 @@
|
|||
<% title "DEV API" %>
|
||||
|
||||
<%= content_for :page_meta do %>
|
||||
<link rel="canonical" href="https://dev.to/api" />
|
||||
<meta name="description" content="<%= ApplicationConfig["COMMUNITY_NAME"] %> API info and guides">
|
||||
<meta name="keywords" content="software development,engineering,rails,javascript,ruby,security">
|
||||
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="https://dev.to/api" />
|
||||
<meta property="og:title" content="<%= ApplicationConfig["COMMUNITY_NAME"] %> API" />
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:site" content="@<%= ApplicationConfig["SITE_TWITTER_HANDLE"] %>">
|
||||
<meta name="twitter:title" content="<%= ApplicationConfig["COMMUNITY_NAME"] %> API">
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.16.0/themes/prism-tomorrow.css" integrity="sha256-0dkohC9ZEupqWbq0hS5cVR4QQXJ+mp6N2oJyuks6gt0=" crossorigin="anonymous" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.16.0/prism.min.js"
|
||||
integrity="sha256-NFZVyNmS1YlmiklazBA+TALYJlJtZj/y/i/oADk6CVE=" crossorigin="anonymous" defer></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.16.0/components/prism-bash.min.js"
|
||||
integrity="sha256-0W9ddRPtgrjvZVUxGhU/ShLxFi3WGNV2T7A7bBTuDWo=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.16.0/components/prism-json.min.js"
|
||||
integrity="sha256-18m89UBQcWGjPHHo64UD+sQx4SpMxiRI1F0MbefKXWw=" crossorigin="anonymous" defer></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.16.0/components/prism-markdown.min.js"
|
||||
integrity="sha256-e4izlzFmEQlenZQnzkYK5oyxV5mX6lwVQjL6onkHiy0=" crossorigin="anonymous"></script>
|
||||
<% end %>
|
||||
|
||||
<div class="blank-space"></div>
|
||||
|
||||
<div class="container article">
|
||||
<div class="title">
|
||||
<h1>
|
||||
DEV Articles API (beta)
|
||||
</h1>
|
||||
|
||||
<h3>
|
||||
As of May 16th 2019 DEV has released a beta version of a REST API to create or update articles.
|
||||
Check back to this page for all updates related to the API.
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="body">
|
||||
<div class="body" style="width: 90%;">
|
||||
<h2>
|
||||
<a name="getting-an-access-token" href="#getting-an-access-token" class="anchor">
|
||||
</a>
|
||||
About the Articles API
|
||||
</h2>
|
||||
<p>
|
||||
"Articles" are all the posts that users create on DEV that typically show up in the feed.
|
||||
They can be a blog post, a discussion question, a help thread etc. but is referred to as
|
||||
<code>article</code> within the code.
|
||||
They are different from <a href="/listings">listings</a>, comments, podcasts, etc.
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
<a name="getting-an-access-token" href="#getting-an-access-token" class="anchor">
|
||||
</a>
|
||||
Getting an access token
|
||||
</h2>
|
||||
|
||||
<p>Authentication for the Articles API requires the <em>DEV API access token.</em> To obtain one, please follow these steps:</p>
|
||||
|
||||
<ul>
|
||||
<li>Connect to <a href="https://dev.to/settings/account">https://dev.to/settings/account</a>
|
||||
</li>
|
||||
<li>
|
||||
<p>In the <strong>DEV API Access Tokens</strong> section create a new token by adding a description and clicking on "Generate Token":</p>
|
||||
|
||||
<p></p>
|
||||
<p>
|
||||
<img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F4Ya4WgC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/4zm0cbutj9o9eau0jm9t.png" alt="DEV Access tokens page" loading="lazy">
|
||||
</p>
|
||||
</li>
|
||||
|
||||
<li><p>You'll see the newly generated token in the same view:</p></li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
<img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kp5L6-9G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ra01mo6fp1es261db2ho.png" alt="DEV access tokens page with a generated token" loading="lazy">
|
||||
</p>
|
||||
|
||||
<h2>
|
||||
<a name="creating-an-article-through-the-api" href="#creating-an-article-through-the-api" class="anchor">
|
||||
</a>
|
||||
Creating an article through the API
|
||||
</h2>
|
||||
|
||||
<p>Here is an example of how to create an article:</p>
|
||||
|
||||
<div class="highlight">
|
||||
<pre class="highlight"><code class="language-bash">curl -X POST -H "Content-Type: application/json" \
|
||||
-H "api-key: ACCESS_TOKEN" \
|
||||
-d '{"article": {"title": "Title", "body_markdown": "Body", "published": false, "tags": ["discuss", "javascript"]}}' \
|
||||
https://dev.to/api/articles</code></pre></div>
|
||||
|
||||
<p>If <code>published</code> is set to <code>true</code> then the article will be live instantly.</p>
|
||||
|
||||
<h3>
|
||||
<a name="successful-response" href="#successful-response" class="anchor">
|
||||
</a>
|
||||
Successful response
|
||||
</h3>
|
||||
|
||||
<p>In case of a successful response (HTTP 201), the full article resource will be returned to the client:</p>
|
||||
|
||||
<div class="highlight"><pre class="highlight plaintext"><code class="language-json">{
|
||||
"type_of": "article",
|
||||
"id": 110878,
|
||||
"title": "Title",
|
||||
"description": "Body\n\n...",
|
||||
"cover_image": null,
|
||||
"readable_publish_date": null,
|
||||
"social_image": "http://dev.to/social_previews/article/110878.png",
|
||||
"tag_list": "discuss, javascript",
|
||||
"tags": [
|
||||
"discuss",
|
||||
"javascript"
|
||||
],
|
||||
"slug": "title-2bp3-temp-slug-5875367",
|
||||
"path": "/rhymes/title-2bp3-temp-slug-5875367",
|
||||
"url": "https://dev.to/rhymes/title-2bp3-temp-slug-5875367",
|
||||
"canonical_url": "https://dev.to/rhymes/title-2bp3-temp-slug-5875367",
|
||||
"comments_count": 0,
|
||||
"positive_reactions_count": 0,
|
||||
"created_at": "2019-05-21T13:34:26Z",
|
||||
"edited_at": null,
|
||||
"crossposted_at": null,
|
||||
"published_at": null,
|
||||
"last_comment_at": "2017-01-01T05:00:00Z",
|
||||
"body_html": "<p>Body</p>\n\n",
|
||||
"ltag_style": [],
|
||||
"ltag_script": [],
|
||||
"user": {
|
||||
"name": "rhymes",
|
||||
"username": "rhymes",
|
||||
"twitter_username": "rhymes_",
|
||||
"github_username": "rhymes",
|
||||
"website_url": null,
|
||||
"profile_image": "https://res.cloudinary.com/practicaldev/image/fetch/s--qhCNe-v6--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://thepracticaldev.s3.amazonaws.com/uploads/user/profile_image/2693/146201.jpeg",
|
||||
"profile_image_90": "https://res.cloudinary.com/practicaldev/image/fetch/s--IQPhTQnb--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://thepracticaldev.s3.amazonaws.com/uploads/user/profile_image/2693/146201.jpeg"
|
||||
}
|
||||
}</code></pre></div>
|
||||
<h3>
|
||||
<a name="create-an-article-on-behalf-an-organisation" href="#create-an-article-on-behalf-an-organisation" class="anchor">
|
||||
</a>
|
||||
Create an article on behalf an organisation
|
||||
</h3>
|
||||
|
||||
<p>Just add <code>organization_id: your_org_id</code> to the JSON request:</p>
|
||||
<div class="highlight"><pre class="highlight plaintext"><code class="language-bash">curl -X POST -H "Content-Type: application/json" \
|
||||
-H "api-key: ACCESS_TOKEN" \
|
||||
-d '{"article": {"title": "Title", "body_markdown": "Body", "published": false, "organization_id": 99999}}' \
|
||||
https://dev.to/api/articles</code></pre></div>
|
||||
<h3>
|
||||
<a name="using-the-front-matter" href="#using-the-front-matter" class="anchor">
|
||||
</a>
|
||||
Using the front matter
|
||||
</h3>
|
||||
|
||||
<p>You can omit most JSON parameters by using the markdown front matter. So for example, if you have markdown article similar to the following:</p>
|
||||
<div class="highlight"><pre class="highlight plaintext"><code class="language-markdown">---
|
||||
title: "A sample article about JavaScript"
|
||||
published: false
|
||||
description: "this is a sample article about javascript"
|
||||
tags: discuss, javascript
|
||||
series: intro-to-javascript
|
||||
canonical_url: canonical URL of the article
|
||||
---
|
||||
|
||||
This is an intro about JavaScript</code></pre></div>
|
||||
|
||||
<p>you can send it within the <code>body_markdown</code> parameter:</p>
|
||||
|
||||
<div class="highlight"><pre class="highlight plaintext"><code class="language-bash">curl -X POST -H "Content-Type: application/json" \
|
||||
-H "api-key: ACCESS_TOKEN" \
|
||||
-d '{"article": {"body_markdown": "---\ntitle: A sample article about...\npublished: false\n---\n..."}}' \
|
||||
https://dev.to/api/articles</code></pre></div>
|
||||
|
||||
<p>The front matter will take precedence on other JSON params with the same name.</p>
|
||||
|
||||
<h3>
|
||||
<a name="available-json-parameters" href="#available-json-parameters" class="anchor">
|
||||
</a>
|
||||
Available JSON parameters
|
||||
</h3>
|
||||
|
||||
<div class="highlight"><pre class="highlight plaintext"><code>title: The title of an article (string, optional)
|
||||
description: Description of the article (string, optional)
|
||||
body_markdown: The Markdown body, with or without a front matter (string, required)
|
||||
published: True if the article should be published right away, defaults to false (boolean, optional)
|
||||
tags: A list of tags for the article (array, optional)
|
||||
series: The name of the series the article should be published within (string, optional)
|
||||
organization_id: Your organization's ID, if you wish to create an article under an organization (string, optional)
|
||||
main_image: URL of the image to use as the cover (string, optional)
|
||||
canonical_url: canonical URL of the article (string, optional)</code></pre></div>
|
||||
<h3>
|
||||
<a name="error-responses" href="#error-responses" class="anchor">
|
||||
</a>
|
||||
Error responses
|
||||
</h3>
|
||||
|
||||
<p><strong>Unauthorized</strong></p>
|
||||
<div class="highlight"><pre class="highlight plaintext"><code class="language-json">{
|
||||
"error": "unauthorized",
|
||||
"status": 401
|
||||
}</code></pre></div>
|
||||
|
||||
<p><strong>Parameter validation error</strong></p>
|
||||
|
||||
<div class="highlight"><pre class="highlight plaintext"><code class="language-json">{
|
||||
"error": "Validation failed: Title can't be blank",
|
||||
"status": 422
|
||||
}</code></pre></div>
|
||||
|
||||
<h2>
|
||||
<a name="updating-an-article-through-the-api" href="#updating-an-article-through-the-api" class="anchor">
|
||||
</a>
|
||||
Updating an article through the API
|
||||
</h2>
|
||||
|
||||
<p>Here is an example of how to update an article:</p>
|
||||
<div class="highlight"><pre class="highlight plaintext"><code class="language-shell">curl -X PUT -H "Content-Type: application/json" \
|
||||
-H "api-key: ACCESS_TOKEN" \
|
||||
-d '{"article": {"title": "New Title"}}' \
|
||||
https://dev.to/api/articles/ARTICLE_ID</code></pre></div>
|
||||
|
||||
<h3>
|
||||
<a name="successful-response" href="#successful-response" class="anchor">
|
||||
</a>
|
||||
Successful response
|
||||
</h3>
|
||||
|
||||
<p>In case of a successful response (HTTP 200), the full article resource will be returned to the client:</p>
|
||||
<div class="highlight"><pre class="highlight plaintext"><code class="language-json">{
|
||||
"type_of": "article",
|
||||
"id": 110878,
|
||||
"title": "New Title",
|
||||
"description": "Body\n\n...",
|
||||
"cover_image": null,
|
||||
"readable_publish_date": null,
|
||||
"social_image": "http://dev.to/social_previews/article/110878.png",
|
||||
"tag_list": "discuss, javascript",
|
||||
"tags": [
|
||||
"discuss",
|
||||
"javascript"
|
||||
],
|
||||
"slug": "title-2bp3-temp-slug-5875367",
|
||||
"path": "/rhymes/title-2bp3-temp-slug-5875367",
|
||||
"url": "https://dev.to/rhymes/title-2bp3-temp-slug-5875367",
|
||||
"canonical_url": "https://dev.to/rhymes/title-2bp3-temp-slug-5875367",
|
||||
"comments_count": 0,
|
||||
"positive_reactions_count": 0,
|
||||
"created_at": "2019-05-21T13:34:26Z",
|
||||
"edited_at": null,
|
||||
"crossposted_at": null,
|
||||
"published_at": null,
|
||||
"last_comment_at": "2017-01-01T05:00:00Z",
|
||||
"body_html": "<p>Body</p>\n\n",
|
||||
"ltag_style": [],
|
||||
"ltag_script": [],
|
||||
"user": {
|
||||
"name": "rhymes",
|
||||
"username": "rhymes",
|
||||
"twitter_username": "rhymes_",
|
||||
"github_username": "rhymes",
|
||||
"website_url": null,
|
||||
"profile_image": "https://res.cloudinary.com/practicaldev/image/fetch/s--qhCNe-v6--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://thepracticaldev.s3.amazonaws.com/uploads/user/profile_image/2693/146201.jpeg",
|
||||
"profile_image_90": "https://res.cloudinary.com/practicaldev/image/fetch/s--IQPhTQnb--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://thepracticaldev.s3.amazonaws.com/uploads/user/profile_image/2693/146201.jpeg"
|
||||
}
|
||||
}</code></pre></div>
|
||||
|
||||
<h3>
|
||||
<a name="notes-about-the-front-matter-during-an-update" href="#notes-about-the-front-matter-during-an-update" class="anchor">
|
||||
</a>
|
||||
Notes about the front matter during an update
|
||||
</h3>
|
||||
|
||||
<p>Keep in mind that if the original article was created with the front matter in the markdown then that front matter will still take precedence over the partial updates. So if you need to change parameters present in the front matter, you should send the whole edited body (with the front matter parameter changed) in the <code>body_markdown</code> parameter.</p>
|
||||
<h3>
|
||||
<a name="available-json-parameters" href="#available-json-parameters" class="anchor">
|
||||
</a>
|
||||
Available JSON parameters
|
||||
</h3>
|
||||
<div class="highlight"><pre class="highlight plaintext"><code>title: The title of an article (optional)
|
||||
description: Description of the article (optional)
|
||||
body_markdown: The Markdown body, with or without a front matter (required)
|
||||
published: True if the article should be published right away, defaults to false (optional)
|
||||
series: The name of the series the article should be published within (optional)
|
||||
organization_id: Your organization's ID, if you wish to create an article under an organization (string, optional)
|
||||
main_image: URL of the image to use as the cover (optional)
|
||||
canonical_url: canonical URL of the article (optional)</code></pre></div>
|
||||
<h3>
|
||||
<a name="error-responses" href="#error-responses" class="anchor">
|
||||
</a>
|
||||
Error responses
|
||||
</h3>
|
||||
|
||||
<p><strong>Unauthorized</strong></p>
|
||||
<div class="highlight"><pre class="highlight plaintext"><code class="language-json">{
|
||||
"error": "unauthorized",
|
||||
"status": 401
|
||||
}</code></pre></div>
|
||||
|
||||
<p><strong>Parameter validation error</strong></p>
|
||||
|
||||
<div class="highlight"><pre class="highlight plaintext"><code class="language-json">{
|
||||
"error": "Validation failed: Title can't be blank",
|
||||
"status": 422
|
||||
}</code></pre></div>
|
||||
<h2>
|
||||
<a name="rate-limiting" href="#rate-limiting" class="anchor">
|
||||
</a>
|
||||
Rate limiting
|
||||
</h2>
|
||||
|
||||
<p>There is a limit of 10 articles created each 30 seconds by the same user. </p>
|
||||
|
||||
<p>There are no limits on the updates.</p>
|
||||
|
||||
<h2>
|
||||
<a name="additional-resources" href="#additional-resources" class="anchor">
|
||||
</a>
|
||||
Additional resources
|
||||
</h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="https://github.com/thepracticaldev/dev.to/blob/master/spec/requests/api/v0/articles_spec.rb">Rails tests for the Articles API</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -246,7 +246,7 @@ Rails.application.routes.draw do
|
|||
|
||||
# You can have the root of your site routed with "root
|
||||
get "/about" => "pages#about"
|
||||
get "/api", to: "pages#api"
|
||||
get "/api", to: redirect("https://docs.dev.to/api")
|
||||
get "/privacy" => "pages#privacy"
|
||||
get "/terms" => "pages#terms"
|
||||
get "/contact" => "pages#contact"
|
||||
|
|
|
|||
|
|
@ -17,6 +17,11 @@
|
|||
"title": "Ruby doc",
|
||||
"href": "http://docs.dev.to/ruby-doc",
|
||||
"target": "_blank"
|
||||
},
|
||||
{
|
||||
"title": "API doc",
|
||||
"href": "http://docs.dev.to/api",
|
||||
"target": "_blank"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,17 @@
|
|||
.PHONY: build
|
||||
|
||||
build: ruby-doc gitdocs
|
||||
build: api-doc ruby-doc gitdocs
|
||||
|
||||
api-doc:
|
||||
# docs/.static/api will let gitdocs serve the API doc as static content
|
||||
cd .. && \
|
||||
npm install -g redoc-cli@latest && \
|
||||
redoc-cli bundle docs/api_v0.yml --options.suppressWarnings --options.pathInMiddlePanel --options.jsonSampleExpandLevel=all --options.menuToggle -t docs/api_template.hbs && \
|
||||
mkdir -p docs/.static/api/ && \
|
||||
mv redoc-static.html docs/.static/api/index.html
|
||||
|
||||
ruby-doc:
|
||||
# docs/.static/ruby-doc will let gitdocs serve the Ruby doc as static content
|
||||
# docs/.static/ruby-doc will let gitdocs serve the Ruby doc as static content
|
||||
cd .. && yard doc -o docs/.static/ruby-doc
|
||||
|
||||
gitdocs:
|
||||
|
|
|
|||
33
docs/api_template.hbs
Normal file
33
docs/api_template.hbs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{{! This template is used by ReDoc to render the final API doc }}
|
||||
{{! It is written in HandlerbarsJS syntax }}
|
||||
{{! Please refer to https://github.com/Redocly/redoc/blob/master/cli/README.md }}
|
||||
{{! and https://github.com/Redocly/redoc/blob/master/cli/template.hbs }}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf8" />
|
||||
<title>DEV API (beta)</title>
|
||||
<meta name="description" content="DEV REST API documentation">
|
||||
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:url" content="https://docs.dev.to/api" />
|
||||
<meta property="og:title" content="DEV API (beta)" />
|
||||
|
||||
<!-- needed for adaptive design -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
{{{redocHead}}}
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{{{redocHTML}}}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
808
docs/api_v0.yml
Normal file
808
docs/api_v0.yml
Normal file
|
|
@ -0,0 +1,808 @@
|
|||
openapi: '3.0.2'
|
||||
info:
|
||||
title: DEV API
|
||||
description: Access DEV articles, comments and other resources via API
|
||||
version: '0.5.0'
|
||||
termsOfService: https://dev.to/terms
|
||||
contact:
|
||||
name: DEV Team
|
||||
url: https://dev.to/contact
|
||||
email: yo@dev.to
|
||||
x-logo: # https://github.com/Redocly/redoc/blob/master/docs/redoc-vendor-extensions.md#x-logo
|
||||
url: https://practicaldev-herokuapp-com.freetls.fastly.net/assets/devlogo-pwa-128-1a9016906487b8ba17f2d3d3c28f9d1cb3ae9b45d685cc2711e20f6b3c6730df.png
|
||||
backgroundColor: "#000"
|
||||
altText: "DEV logo"
|
||||
|
||||
servers:
|
||||
- url: https://dev.to/api
|
||||
description: Production server
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
api_key:
|
||||
type: apiKey
|
||||
description: |
|
||||
API Key authentication.
|
||||
|
||||
### Getting an API key
|
||||
|
||||
Authentication for the Articles API requires an API key (DEV API access token).
|
||||
To obtain one, please follow these steps:
|
||||
|
||||
- visit https://dev.to/settings/account
|
||||
- in the "DEV API Access Tokens" section create a new token by adding a
|
||||
description and clicking on "Generate Token"
|
||||
|
||||

|
||||
- You'll see the newly generated token in the same view
|
||||

|
||||
name: api-key
|
||||
in: header
|
||||
|
||||
schemas:
|
||||
APIError:
|
||||
type: object
|
||||
required:
|
||||
- error
|
||||
- status
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
status:
|
||||
type: integer
|
||||
format: int32
|
||||
ArticleIndex:
|
||||
type: object
|
||||
required:
|
||||
- type_of
|
||||
- id
|
||||
- title
|
||||
- description
|
||||
- cover_image
|
||||
- published_at
|
||||
- tag_list
|
||||
- slug
|
||||
- path
|
||||
- url
|
||||
- canonical_url
|
||||
- positive_reactions_count
|
||||
- published_timestamp
|
||||
- user
|
||||
properties:
|
||||
type_of:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
format: int32
|
||||
title:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
cover_image:
|
||||
type: string
|
||||
format: url
|
||||
published_at:
|
||||
type: string
|
||||
format: date-time
|
||||
tag_list:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
slug:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
format: path
|
||||
url:
|
||||
type: string
|
||||
format: url
|
||||
canonical_url:
|
||||
type: string
|
||||
format: url
|
||||
positive_reactions_count:
|
||||
type: integer
|
||||
format: int32
|
||||
published_timestamp:
|
||||
description: Crossposting or published date time
|
||||
type: string
|
||||
format: date-time
|
||||
user:
|
||||
type: object
|
||||
$ref: '#/components/schemas/User'
|
||||
organization:
|
||||
description: Organization the article belongs to
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
username:
|
||||
type: string
|
||||
slug:
|
||||
type: string
|
||||
profile_image:
|
||||
description: Profile image (640x640)
|
||||
type: string
|
||||
format: url
|
||||
profile_image_90:
|
||||
description: Profile image (90x90)
|
||||
type: string
|
||||
format: url
|
||||
flare_tag:
|
||||
description: Flare tag of the article
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
bg_color_hex:
|
||||
description: Background color (hexadecimal)
|
||||
type: string
|
||||
text_color_hex:
|
||||
description: Text color (hexadecimal)
|
||||
type: string
|
||||
ArticleShow:
|
||||
type: object
|
||||
required:
|
||||
- type_of
|
||||
- id
|
||||
- title
|
||||
- description
|
||||
- cover_image
|
||||
- readable_publish_date
|
||||
- social_image
|
||||
- tag_list
|
||||
- tags
|
||||
- slug
|
||||
- path
|
||||
- url
|
||||
- canonical_url
|
||||
- comments_count
|
||||
- positive_reactions_count
|
||||
- created_at
|
||||
- edited_at
|
||||
- crossposted_at
|
||||
- published_at
|
||||
- last_comment_at
|
||||
- body_html
|
||||
- body_markdown
|
||||
- user
|
||||
properties:
|
||||
type_of:
|
||||
type: string
|
||||
id:
|
||||
type: integer
|
||||
format: int32
|
||||
title:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
cover_image:
|
||||
type: string
|
||||
format: url
|
||||
readable_publish_date:
|
||||
type: string
|
||||
social_image:
|
||||
type: string
|
||||
format: url
|
||||
tag_list:
|
||||
type: string
|
||||
tags:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
slug:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
format: path
|
||||
url:
|
||||
type: string
|
||||
format: url
|
||||
canonical_url:
|
||||
type: string
|
||||
format: url
|
||||
comments_count:
|
||||
type: integer
|
||||
format: int32
|
||||
positive_reactions_count:
|
||||
type: integer
|
||||
format: int32
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
edited_at:
|
||||
type: string
|
||||
format: date-time
|
||||
crossposted_at:
|
||||
type: string
|
||||
format: date-time
|
||||
published_at:
|
||||
type: string
|
||||
format: date-time
|
||||
last_comment_at:
|
||||
type: string
|
||||
format: date-time
|
||||
body_html:
|
||||
type: string
|
||||
body_markdown:
|
||||
type: string
|
||||
user:
|
||||
type: object
|
||||
$ref: '#/components/schemas/User'
|
||||
ArticleCreate:
|
||||
type: object
|
||||
properties:
|
||||
article:
|
||||
type: object
|
||||
required:
|
||||
- title
|
||||
properties:
|
||||
title:
|
||||
type: string
|
||||
body_markdown:
|
||||
description: |
|
||||
The body of the article.
|
||||
|
||||
It can contain an optional front matter. For example
|
||||
|
||||
```markdown
|
||||
---
|
||||
title: Hello, World!
|
||||
published: true
|
||||
tags: discuss, help
|
||||
date: 20190701T10:00Z
|
||||
series: Hello series
|
||||
canonical_url: https://example.com/blog/hello
|
||||
cover_image: article_published_cover_image
|
||||
---
|
||||
```
|
||||
|
||||
`date`, `series` and `canonical_url` are optional.
|
||||
`date` is the publication date-time
|
||||
`series` is the name of the series the article belongs to
|
||||
`canonical_url` is the canonical URL of the article
|
||||
`cover_image` is the main image of the article
|
||||
|
||||
*If the markdown contains a front matter, it will take precedence
|
||||
on the equivalent params given in the JSON payload.*
|
||||
type: string
|
||||
published:
|
||||
description: |
|
||||
True to create a published article, false otherwise. Defaults to false
|
||||
type: boolean
|
||||
series:
|
||||
description: |
|
||||
Article series name.
|
||||
|
||||
All articles belonging to the same series need to have the same name
|
||||
in this parameter.
|
||||
type: string
|
||||
main_image:
|
||||
type: string
|
||||
format: url
|
||||
canonical_url:
|
||||
type: string
|
||||
format: url
|
||||
description:
|
||||
type: string
|
||||
tags:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
organization_id:
|
||||
description: |
|
||||
Only users belonging to an organization can assign the article to it
|
||||
type: integer
|
||||
format: int32
|
||||
ArticleUpdate:
|
||||
type: object
|
||||
properties:
|
||||
article:
|
||||
type: object
|
||||
properties:
|
||||
title:
|
||||
type: string
|
||||
body_markdown:
|
||||
description: |
|
||||
The body of the article.
|
||||
|
||||
It can contain an optional front matter. For example
|
||||
|
||||
```markdown
|
||||
---
|
||||
title: Hello, World!
|
||||
published: true
|
||||
tags: discuss, help
|
||||
date: 20190701T10:00Z
|
||||
series: Hello series
|
||||
canonical_url: https://example.com/blog/hello
|
||||
cover_image: article_published_cover_image
|
||||
---
|
||||
```
|
||||
|
||||
`date`, `series` and `canonical_url` are optional.
|
||||
`date` is the publication date-time
|
||||
`series` is the name of the series the article belongs to
|
||||
`canonical_url` is the canonical URL of the article
|
||||
`cover_image` is the main image of the article
|
||||
|
||||
*If the markdown contains a front matter, it will take precedence
|
||||
on the equivalent params given in the JSON payload.*
|
||||
type: string
|
||||
published:
|
||||
description: |
|
||||
True to create a published article, false otherwise. Defaults to false
|
||||
type: boolean
|
||||
series:
|
||||
description: |
|
||||
Article series name.
|
||||
|
||||
All articles belonging to the same series need to have the same name
|
||||
in this parameter.
|
||||
|
||||
To remove an article from a series, the `null` value can be used.
|
||||
type: string
|
||||
main_image:
|
||||
type: string
|
||||
format: url
|
||||
canonical_url:
|
||||
type: string
|
||||
format: url
|
||||
description:
|
||||
type: string
|
||||
tags:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
organization_id:
|
||||
description: |
|
||||
Only users belonging to an organization can assign the article to it
|
||||
type: integer
|
||||
format: int32
|
||||
|
||||
User:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
username:
|
||||
type: string
|
||||
twitter_username:
|
||||
type: string
|
||||
github_username:
|
||||
type: string
|
||||
website_url:
|
||||
type: string
|
||||
format: url
|
||||
profile_image:
|
||||
description: Profile image (640x640)
|
||||
type: string
|
||||
profile_image_90:
|
||||
description: Profile image (90x90)
|
||||
type: string
|
||||
|
||||
examples:
|
||||
ErrorNotFound:
|
||||
value:
|
||||
error: not found
|
||||
status: 404
|
||||
ErrorUnauthorized:
|
||||
value:
|
||||
error: unauthorized
|
||||
status: 401
|
||||
ArticleShow:
|
||||
value:
|
||||
type_of: article
|
||||
id: 150589
|
||||
title: 'Byte Sized Episode 2: The Creation of Graph Theory '
|
||||
description: The full story of Leonhard Euler and the creation of this fundamental
|
||||
computer science principle, delivered in a few minutes.
|
||||
cover_image: https://res.cloudinary.com/practicaldev/image/fetch/s--qgutBUrH--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://thepracticaldev.s3.amazonaws.com/i/88e62fzblbluz1dm7xjf.png
|
||||
readable_publish_date: Aug 1
|
||||
social_image: https://res.cloudinary.com/practicaldev/image/fetch/s--6wSHHfwd--/c_imagga_scale,f_auto,fl_progressive,h_500,q_auto,w_1000/https://thepracticaldev.s3.amazonaws.com/i/88e62fzblbluz1dm7xjf.png
|
||||
tag_list: computerscience, graphtheory, bytesized, history
|
||||
tags:
|
||||
- computerscience
|
||||
- graphtheory
|
||||
- bytesized
|
||||
- history
|
||||
slug: byte-sized-episode-2-the-creation-of-graph-theory-34g1
|
||||
path: "/bytesized/byte-sized-episode-2-the-creation-of-graph-theory-34g1"
|
||||
url: https://dev.to/bytesized/byte-sized-episode-2-the-creation-of-graph-theory-34g1
|
||||
canonical_url: https://dev.to/bytesized/byte-sized-episode-2-the-creation-of-graph-theory-34g1
|
||||
comments_count: 19
|
||||
positive_reactions_count: 276
|
||||
created_at: '2019-07-31T11:15:06Z'
|
||||
edited_at:
|
||||
crossposted_at:
|
||||
published_at: '2019-08-01T15:47:54Z'
|
||||
last_comment_at: '2019-08-06T09:12:45Z'
|
||||
body_html: |+
|
||||
<p>Today's episode of Byte Sized is about Leonhard Euler and the creation of <a href="https://en.wikipedia.org/wiki/Graph_theory">Graph Theory</a>.</p>
|
||||
|
||||
<p>For more about how Graph Theory works, check out this video from BaseCS!</p>...
|
||||
body_markdown: "---\r\ntitle: Byte Sized Episode 2: The Creation of Graph Theory \r\npublished:
|
||||
true\r\ndescription: The full story of Leonhard Euler and the creation of this fundamental
|
||||
computer science principle, delivered in a few minutes.\r\ntags: computerscience,
|
||||
graphtheory, bytesized, history\r\ncover_image: https://thepracticaldev.s3.amazonaws.com/i/88e62fzblbluz1dm7xjf.png\r\nseries:
|
||||
Byte Sized Season 1\r\n---\r\n\r\nToday's episode of Byte Sized is about Leonhard
|
||||
Euler and the creation of [Graph Theory](https://en.wikipedia.org/wiki/Graph_theory).\r\n\r\nFor
|
||||
more about how Graph Theory works, check out this video from BaseCS!..."
|
||||
user:
|
||||
name: Vaidehi Joshi
|
||||
username: vaidehijoshi
|
||||
twitter_username: vaidehijoshi
|
||||
github_username: vaidehijoshi
|
||||
website_url: http://www.vaidehi.com
|
||||
profile_image: https://res.cloudinary.com/practicaldev/image/fetch/s--eDGAYAoK--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://thepracticaldev.s3.amazonaws.com/uploads/user/profile_image/2882/K2evUksb.jpg
|
||||
profile_image_90: https://res.cloudinary.com/practicaldev/image/fetch/s--htZnqMn3--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://thepracticaldev.s3.amazonaws.com/uploads/user/profile_image/2882/K2evUksb.jpg
|
||||
ArticleCreateTitleBody:
|
||||
value:
|
||||
article:
|
||||
title: Hello, World!
|
||||
published: true
|
||||
body_markdown: Hello DEV, this is my first post
|
||||
tags: discuss, help
|
||||
series: Hello series
|
||||
canonical_url: https://example.com/blog/hello
|
||||
ArticleCreateFrontMatter:
|
||||
value:
|
||||
article:
|
||||
body_markdown: |
|
||||
---
|
||||
title: Hello, World!
|
||||
published: true
|
||||
tags: discuss, help
|
||||
date: 20190701T10:00Z
|
||||
series: Hello series
|
||||
canonical_url: https://example.com/blog/hello
|
||||
---
|
||||
|
||||
Hello DEV, this is my first post
|
||||
ArticleCreateOrganization:
|
||||
value:
|
||||
article:
|
||||
title: Hello, World!
|
||||
published: true
|
||||
body_markdown: Hello DEV, this is my first post
|
||||
tags: discuss, help
|
||||
series: Hello series
|
||||
canonical_url: https://example.com/blog/hello
|
||||
organization_id: 1234
|
||||
|
||||
|
||||
paths:
|
||||
/articles:
|
||||
get:
|
||||
summary: Published articles
|
||||
description: |
|
||||
This endpoint allows the client to retrieve a list of articles.
|
||||
|
||||
"Articles" are all the posts that users create on DEV that typically
|
||||
show up in the feed. They can be a blog post, a discussion question,
|
||||
a help thread etc. but is referred to as article within the code.
|
||||
|
||||
By default it will return featured, published articles ordered
|
||||
by descending popularity.
|
||||
|
||||
Each page will contain `30` articles.
|
||||
|
||||
Responses, according to the combination of params, are cached for 24 hours.
|
||||
tags:
|
||||
- articles
|
||||
parameters:
|
||||
- name: page
|
||||
in: query
|
||||
description: |
|
||||
Pagination page.
|
||||
|
||||
This param can be used in conjuction with all other params
|
||||
(except when asking for fresh and rising articles by themselves).
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
example: 1
|
||||
- name: tag
|
||||
in: query
|
||||
description: |
|
||||
Adding this parameter will return articles that contain the
|
||||
requested tag.
|
||||
|
||||
This param can be used by itself, with `page` or with `top`.
|
||||
schema:
|
||||
type: string
|
||||
example: discuss
|
||||
- name: username
|
||||
in: query
|
||||
description: |
|
||||
Adding this parameter will return articles belonging to a User or Organization
|
||||
ordered by descending `published_at`.
|
||||
|
||||
If `state=all` the number of items returned will be `1000` instead of the default `30`.
|
||||
|
||||
This param can be used by itself or only with `page` and `state`.
|
||||
schema:
|
||||
type: string
|
||||
example: ben
|
||||
- name: state
|
||||
in: query
|
||||
description: |
|
||||
Adding this will allow the client to check which articles are fresh or rising.
|
||||
|
||||
If `state=fresh` the server will return published fresh articles.
|
||||
If `state=rising` the server will return published rising articles.
|
||||
|
||||
This param can only be used by itself or with `username` if set to `all`.
|
||||
schema:
|
||||
type: string
|
||||
example: ben
|
||||
- name: top
|
||||
in: query
|
||||
description: |
|
||||
Adding this will allow the client to return the most popular articles
|
||||
in the last `N` days.
|
||||
|
||||
`top` indicates the number of days since publication of the articles
|
||||
returned.
|
||||
|
||||
This param can only be used by itself or with `tag`.
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
example: 2
|
||||
responses:
|
||||
200:
|
||||
description: A list of articles
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ArticleIndex'
|
||||
examples:
|
||||
articles-success:
|
||||
summary: Successful response
|
||||
value:
|
||||
type_of: article
|
||||
id: 150589
|
||||
title: 'Byte Sized Episode 2: The Creation of Graph Theory'
|
||||
description: The full story of Leonhard Euler and the creation of this fundamental
|
||||
computer science principle, delivered in a few minutes.
|
||||
cover_image: https://res.cloudinary.com/practicaldev/image/fetch/s--qgutBUrH--/c_imagga_scale,f_auto,fl_progressive,h_420,q_auto,w_1000/https://thepracticaldev.s3.amazonaws.com/i/88e62fzblbluz1dm7xjf.png
|
||||
published_at: '2019-08-01T15:47:54.000Z'
|
||||
tag_list:
|
||||
- computerscience
|
||||
- graphtheory
|
||||
- bytesized
|
||||
- history
|
||||
slug: byte-sized-episode-2-the-creation-of-graph-theory-34g1
|
||||
path: "/bytesized/byte-sized-episode-2-the-creation-of-graph-theory-34g1"
|
||||
url: https://dev.to/bytesized/byte-sized-episode-2-the-creation-of-graph-theory-34g1
|
||||
canonical_url: https://dev.to/bytesized/byte-sized-episode-2-the-creation-of-graph-theory-34g1
|
||||
comments_count: 15
|
||||
positive_reactions_count: 210
|
||||
published_timestamp: '2019-08-01T15:47:54Z'
|
||||
user:
|
||||
name: Vaidehi Joshi
|
||||
username: vaidehijoshi
|
||||
twitter_username: vaidehijoshi
|
||||
github_username: vaidehijoshi
|
||||
website_url: http://www.vaidehi.com
|
||||
profile_image: https://res.cloudinary.com/practicaldev/image/fetch/s--eDGAYAoK--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://thepracticaldev.s3.amazonaws.com/uploads/user/profile_image/2882/K2evUksb.jpg
|
||||
profile_image_90: https://res.cloudinary.com/practicaldev/image/fetch/s--htZnqMn3--/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://thepracticaldev.s3.amazonaws.com/uploads/user/profile_image/2882/K2evUksb.jpg
|
||||
organization:
|
||||
name: Byte Sized
|
||||
username: bytesized
|
||||
slug: bytesized
|
||||
profile_image: https://res.cloudinary.com/practicaldev/image/fetch/s--sq0DrZfn--/c_fill,f_auto,fl_progressive,h_640,q_auto,w_640/https://thepracticaldev.s3.amazonaws.com/uploads/organization/profile_image/865/652f7998-32a8-4fd9-85ca-dd697d2a9ee9.png
|
||||
profile_image_90: https://res.cloudinary.com/practicaldev/image/fetch/s--1Pt_ICL---/c_fill,f_auto,fl_progressive,h_90,q_auto,w_90/https://thepracticaldev.s3.amazonaws.com/uploads/organization/profile_image/865/652f7998-32a8-4fd9-85ca-dd697d2a9ee9.png
|
||||
x-code-samples: # https://github.com/Redocly/redoc/blob/master/docs/redoc-vendor-extensions.md#x-code-samples
|
||||
- lang: Shell
|
||||
label: curl (all articles)
|
||||
source: |
|
||||
curl https://dev.to/api/articles
|
||||
- lang: Shell
|
||||
label: curl (user's articles)
|
||||
source: |
|
||||
curl https://dev.to/api/articles?username=ben
|
||||
post:
|
||||
summary: Create a new article
|
||||
description: |
|
||||
This endpoint allows the client to create a new article.
|
||||
|
||||
"Articles" are all the posts that users create on DEV that typically
|
||||
show up in the feed. They can be a blog post, a discussion question,
|
||||
a help thread etc. but is referred to as article within the code.
|
||||
|
||||
### Rate limiting
|
||||
|
||||
There is a limit of 10 articles created each 30 seconds by the same user.
|
||||
|
||||
### Additional resources
|
||||
|
||||
- [Rails tests for Articles API](https://github.com/thepracticaldev/dev.to/blob/master/spec/requests/api/v0/articles_spec.rb)
|
||||
tags:
|
||||
- articles
|
||||
requestBody:
|
||||
description: Article to create
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ArticleCreate'
|
||||
examples:
|
||||
article-create-title-body:
|
||||
$ref: '#/components/examples/ArticleCreateTitleBody'
|
||||
article-create-front-matter:
|
||||
$ref: '#/components/examples/ArticleCreateFrontMatter'
|
||||
article-create-organization:
|
||||
$ref: '#/components/examples/ArticleCreateOrganization'
|
||||
|
||||
responses:
|
||||
201:
|
||||
description: A newly created article
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
$ref: '#/components/schemas/ArticleShow'
|
||||
examples:
|
||||
article-success:
|
||||
$ref: '#/components/examples/ArticleShow'
|
||||
headers:
|
||||
Location:
|
||||
description: The URL of the new article
|
||||
schema:
|
||||
type: string
|
||||
format: url
|
||||
401:
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
$ref: '#/components/schemas/APIError'
|
||||
examples:
|
||||
article-unauthorized:
|
||||
$ref: '#/components/examples/ErrorUnauthorized'
|
||||
security:
|
||||
- api_key: []
|
||||
x-code-samples: # https://github.com/Redocly/redoc/blob/master/docs/redoc-vendor-extensions.md#x-code-samples
|
||||
- lang: Shell
|
||||
label: curl
|
||||
source: |
|
||||
curl -X POST -H "Content-Type: application/json" \
|
||||
-H "api-key: ACCESS_TOKEN" \
|
||||
-d '{"article":{"title":"Title","body_markdown":"Body","published":false,"tags":["discuss", "javascript"]}}' \
|
||||
https://dev.to/api/articles
|
||||
- lang: Shell
|
||||
label: curl (with front matter)
|
||||
source: |
|
||||
curl -X POST -H "Content-Type: application/json" \
|
||||
-H "api-key: ACCESS_TOKEN" \
|
||||
-d '{"article":{"body_markdown":"---\ntitle:A sample article about...\npublished:false\n---\n..."}}' \
|
||||
https://dev.to/api/articles
|
||||
|
||||
/articles/{id}:
|
||||
get:
|
||||
summary: A published article
|
||||
description: |
|
||||
This endpoint allows the client to retrieve a single
|
||||
published article given its `id`.
|
||||
|
||||
Responses are cached for 5 minutes.
|
||||
tags:
|
||||
- articles
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
description: Id of the article
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
example: 150589
|
||||
responses:
|
||||
200:
|
||||
description: An article
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
$ref: '#/components/schemas/ArticleShow'
|
||||
examples:
|
||||
article-success:
|
||||
$ref: '#/components/examples/ArticleShow'
|
||||
404:
|
||||
description: Resource not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
$ref: '#/components/schemas/APIError'
|
||||
examples:
|
||||
article-not-found:
|
||||
$ref: '#/components/examples/ErrorNotFound'
|
||||
x-code-samples: # https://github.com/Redocly/redoc/blob/master/docs/redoc-vendor-extensions.md#x-code-samples
|
||||
- lang: Shell
|
||||
label: curl
|
||||
source: |
|
||||
curl https://dev.to/api/articles/150589
|
||||
put:
|
||||
summary: Update an existing article
|
||||
description: |
|
||||
This endpoint allows the client to updated an existing article.
|
||||
|
||||
"Articles" are all the posts that users create on DEV that typically
|
||||
show up in the feed. They can be a blog post, a discussion question,
|
||||
a help thread etc. but is referred to as article within the code.
|
||||
|
||||
### Rate limiting
|
||||
|
||||
There are no limits on the amount of updates.
|
||||
|
||||
### Additional resources
|
||||
|
||||
- [Rails tests for Articles API](https://github.com/thepracticaldev/dev.to/blob/master/spec/requests/api/v0/articles_spec.rb)
|
||||
tags:
|
||||
- articles
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
description: Id of the article
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
example: 150589
|
||||
requestBody:
|
||||
description: |
|
||||
Article params to update.
|
||||
|
||||
*Note: if the article contains a front matter in its body, its front
|
||||
matter properties will still take precedence over any JSON equivalent
|
||||
params, which means that the full body_markdown with the modified
|
||||
front matter params needs to be provided for an update to be successful*
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ArticleUpdate'
|
||||
examples:
|
||||
article-update-title-body:
|
||||
$ref: '#/components/examples/ArticleCreateTitleBody'
|
||||
article-update-front-matter:
|
||||
$ref: '#/components/examples/ArticleCreateFrontMatter'
|
||||
article-update-organization:
|
||||
$ref: '#/components/examples/ArticleCreateOrganization'
|
||||
responses:
|
||||
200:
|
||||
description: The updated article
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
$ref: '#/components/schemas/ArticleShow'
|
||||
examples:
|
||||
article-success:
|
||||
$ref: '#/components/examples/ArticleShow'
|
||||
401:
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
$ref: '#/components/schemas/APIError'
|
||||
examples:
|
||||
article-unauthorized:
|
||||
$ref: '#/components/examples/ErrorUnauthorized'
|
||||
security:
|
||||
- api_key: []
|
||||
x-code-samples: # https://github.com/Redocly/redoc/blob/master/docs/redoc-vendor-extensions.md#x-code-samples
|
||||
- lang: Shell
|
||||
label: curl
|
||||
source: |
|
||||
curl -X PUT -H "Content-Type: application/json" \
|
||||
-H "api-key: ACCESS_TOKEN" \
|
||||
-d '{"article":{"title":"Title"}' \
|
||||
https://dev.to/api/articles/{id}
|
||||
|
||||
security:
|
||||
- api_key: []
|
||||
29
docs/contributing_api.md
Normal file
29
docs/contributing_api.md
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
---
|
||||
title: Contributing to API spec docs
|
||||
---
|
||||
|
||||
# Contributing to API spec docs
|
||||
|
||||
The API docs follow the [OpenAPI 3 specification](http://spec.openapis.org/oas/v3.0.2).
|
||||
|
||||
## Where The Docs Are Located
|
||||
|
||||
We auto generate the documentation from `api_v0.yml` within the `/docs` directory.
|
||||
We use [ReDoc](https://github.com/Redocly/redoc) to turn the OpenAPI 3 format into a readable and searchable HTML documentation.
|
||||
|
||||
## Running and editing the Docs Locally
|
||||
|
||||
If you want to browse the documentation locally you can use:
|
||||
|
||||
```shell
|
||||
yarn api-docs:serve
|
||||
```
|
||||
|
||||
This will let you browse the auto generated version of the doc locally and it will reload the doc after every modification
|
||||
of the spec file.
|
||||
|
||||
If you have Visual Studio Code we suggest you install the following extensions that enable validation and navigation within
|
||||
the spec file:
|
||||
|
||||
- [OpenAPI (Swagger) editor](https://marketplace.visualstudio.com/items?itemName=42Crunch.vscode-openapi)
|
||||
- [openapi-designer live preview](https://marketplace.visualstudio.com/items?itemName=philosowaffle.openapi-designer)
|
||||
|
|
@ -8,6 +8,7 @@ items:
|
|||
- design
|
||||
- tests
|
||||
- contributing.md
|
||||
- contributing_api.md
|
||||
- faqs.md
|
||||
- licensing.md
|
||||
- self-hosting.md
|
||||
|
|
|
|||
|
|
@ -18,6 +18,12 @@
|
|||
[[redirects]]
|
||||
from = "http://docs.dev.to/ruby-doc/"
|
||||
to = "https://docs.dev.to/ruby-doc/index.html"
|
||||
[[redirects]]
|
||||
from = "http://docs.dev.to/api"
|
||||
to = "https://docs.dev.to/api/index.html"
|
||||
[[redirects]]
|
||||
from = "http://docs.dev.to/api/"
|
||||
to = "https://docs.dev.to/api/index.html"
|
||||
[[redirects]]
|
||||
from = "http://docs.dev.to/*"
|
||||
to = "https://docs.dev.to/:splat"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@
|
|||
"test": "jest app/javascript/ --coverage",
|
||||
"test:watch": "jest app/javascript/ --watch",
|
||||
"storybook": "start-storybook -p 6006 -c app/javascript/.storybook -s app/javascript/.storybook/assets",
|
||||
"build-storybook": "build-storybook -c app/javascript/.storybook -s app/javascript/.storybook/assets"
|
||||
"build-storybook": "build-storybook -c app/javascript/.storybook -s app/javascript/.storybook/assets",
|
||||
"api-docs:serve": "yarn redoc-cli serve docs/api_v0.yml --options.pathInMiddlePanel --options.jsonSampleExpandLevel=all --options.menuToggle -t docs/api_template.hbs --watch"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
|
|
@ -82,6 +83,7 @@
|
|||
"preact-render-spy": "1.3.0",
|
||||
"preact-render-to-json": "^3.6.6",
|
||||
"prettier": "^1.18.2",
|
||||
"redoc-cli": "0.8.6",
|
||||
"webpack-dev-server": "^2.11.3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
|
|||
|
|
@ -65,6 +65,16 @@ RSpec.describe "Api::V0::Articles", type: :request do
|
|||
get api_articles_path(tag: tag.name)
|
||||
expect(JSON.parse(response.body).size).to eq(0)
|
||||
end
|
||||
|
||||
it "returns flare tag in the response" do
|
||||
create(:article, featured: true, tags: "discuss")
|
||||
|
||||
get api_articles_path
|
||||
response_article = JSON.parse(response.body)[0]
|
||||
expect(response_article["flare_tag"]).to be_present
|
||||
expect(response_article["flare_tag"].keys).to eq(%w[name bg_color_hex text_color_hex])
|
||||
expect(response_article["flare_tag"]["name"]).to eq("discuss")
|
||||
end
|
||||
end
|
||||
|
||||
describe "GET /api/articles/:id" do
|
||||
|
|
@ -453,7 +463,7 @@ RSpec.describe "Api::V0::Articles", type: :request do
|
|||
expect(response).to have_http_status(:ok)
|
||||
end
|
||||
|
||||
it "does not update title if only given a title" do
|
||||
it "does not update title if only given a title because the article has a front matter" do
|
||||
put_article(title: Faker::Book.title + rand(100).to_s)
|
||||
expect(response).to have_http_status(:ok)
|
||||
expect(article.reload.title).to eq(article.title)
|
||||
|
|
|
|||
|
|
@ -26,9 +26,9 @@ RSpec.describe "Pages", type: :request do
|
|||
end
|
||||
|
||||
describe "GET /api" do
|
||||
it "has proper headline" do
|
||||
it "redirects to the API docs" do
|
||||
get "/api"
|
||||
expect(response.body).to include("DEV Articles API")
|
||||
expect(response.body).to redirect_to("https://docs.dev.to/api")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue