We are going to create a program that allows us to post draft articles from Markdown to DEV.to with ease.
Requirements
We are going to need the following tooling so make sure it is installed on your machine.
- Go 1.x or higher
- VS Code or any other editor
- Any terminal
- A DEV.to account
- A DEV.to API key
Getting Started
1. Scaffolding the project
First, let's set up the project structure so have a base to work on.
mkdir devAutomation && cd devAutomation
touch .env
touch main.go
go mod init devAutomation
echo "# Hello Dev.To
Lorem ipsum dolor sit amet, consectetur adipiscing elit." >> example.md
Here we are doing a few things, on the first line, we are creating a directory for our project and changing directory into that folder.
Secondly, we are creating a few files. The .env
file is for the environment variables like the API key which we are getting in step 2. And the main.go
is the starting point of our program.
Then we need to initialize the module using go mod init
and lastly we need an example Markdown file to post to DEV.to.
2. Getting the API key
Let's get the API key go to this page and scroll down to the section named "DEV API Keys". Create a new API key and name accordingly.
Let's save the API key in the .env
file we created in step 1.
DEV_TO_API_KEY='your-api-key'
3. Reading Markdown
Reading the Markdown file is quite easy. We are going to read the example markdown using ioutil.ReadFile
and using fmt.Println
we are for now printing the contents to the terminal.
func main() {
file, err := ioutil.ReadFile("./example.md")
if err != nil {
fmt.Println(err)
}
fmt.Println(string(file))
}
You should have an output looking like the following:
# Hello Dev.To
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
4. Creating the API Request
The API call is the hardest part of this tutorial. First, we need some types. These are needed to ensure the data we are posting to the API will get through correctly.
Using these types we can also see that what we can send over to the API.
type DevTo struct {
Article Article `json:"article"`
}
type Article struct {
Title string `json:"title"`
Published bool `json:"published"`
Series string `json:"series"`
MainImage string `json:"main_image"`
Canonical string `json:"canonical_url"`
Description string `json:"description"`
Tags []string `json:"tags"`
BodyMarkdown string `json:"body_markdown"`
}
Let's create a new function called publish
and create the request logic in there.
For the sake of this demo, I will split the example markdown file on a new line so we have a separate title and body for our article.
For more advanced articles please take a look at the Frontmatter options that DEV.to supports.
In this part, we will create the responseBody
and add our data.
Then we create the payload
and added it to the request.
After that, we are doing a few if checks to make sure we get the appropriate log message printed to the terminal when the API call fails, succeeds, or returns with another status code.
func request(body string) {
url := "https://dev.to/api/articles"
content := strings.Split(body, "\n")
responseBody := DevTo{
Article: Article{
Published: false, // this will ensure it's a draft
Title: content[0],
BodyMarkdown: content[1],
},
}
payload, _ := json.Marshal(responseBody)
request, err := http.NewRequest("POST", url, bytes.NewBuffer(payload))
request.Header.Add("api-key", apikey)
request.Header.Add("Content-Type", "application/json")
client := &http.Client{}
response, err := client.Do(request)
if err != nil {
log.Fatalln(err)
}
defer response.Body.Close()
if response.StatusCode == 200 || response.StatusCode == 201 {
log.Println("Created new article on Dev.To")
}
if response.StatusCode != 200 && response.StatusCode != 201 {
responseMessage, _ := ioutil.ReadAll(response.Body)
log.Fatalln(string(responseMessage))
}
}
5. Loading in the API key
We also need to set the API to authorize the post request. For this, we will need the godotenv
module to read the .env
file.
go get github.com/joho/godotenv
Here we have a utility function to get the API key. On the first line, we are reading the .env
file and if there is an error we will print that. Otherwise, it's correctly read and we print a message that it's correctly loaded in.
func env(key string) string {
err := godotenv.Load("./.env")
if err != nil {
log.Fatalf("Error loading .env file")
}
log.Println("Loaded the .env file")
return os.Getenv(key)
}
Revisited the request
function we created in step 4, and add the following line.
If you have kept a close eye you would have spotted that apikey
wasn't declared.
// ... other code
func request(body string) {
apikey := env("DEV_TO_API_KEY") // <-- this line
url := "https://dev.to/api/articles"
content := strings.Split(body, "\n")
// ...rest of the function
}
6. Connecting all the pieces
Now go back to the main
function we created in step 3. And add the following line.
func main() {
file, err := ioutil.ReadFile("./example.md")
if err != nil {
fmt.Println(err)
}
request(string(file)) // <-- this line
}
This will bootstrap all the functions we created and pass along the contents of the markdown file.
If you run this in the terminal you should see the following output
18:51:36 Loaded the .env file
18:51:37 Created new article on Dev.To
Open up your DEV.to dashboard, and you should see a new entry be listed there.
Wrapping it up.
Congrats, you now have a program to upload your Markdown-based articles to Dev.to using Golang.
Top comments (0)