Ghost API & Python 3.x, #1
In this series of posts I show you how to work with Python 3.x and the Ghost REST API (Admin API and Content API).
Let's assume you have the 2 Ghost sites somedomain1 and somedomain2. On both sites you would like to create, edit, delete etc. posts using Python and the Ghost API.
On both sites go to the Ghost admin page (e.g. https://somedomain1/ghost/), click on Integrations in the left pane and there, under CUSTOM INTEGRATIONS click on +Add custom integration. Give it a name e.g. "Ghost API" and the configuration page opens. There you see a line Content API Key and a line Admin API Key. Both keys will be used in our code.
Create a file ghostAdmin.py and add the code sections below (You will find the complete code for this tutorial in Part 4. If you hover over a code sample you can copy the code by clicking on the tooltip in the upper right corner of the code block).
- The imports
import json, requests, jwt
from datetime import datetime as dt
from io import BytesIO
The package jwt is used for authentication (see later createToken()) and BytesIO is used for images (see later loadImage()).
2. Create the class GhostAdmin
Add the methods setSiteData(), createToken() and createHeaders().
class GhostAdmin():
def __init__(self, siteName):
self.siteName = siteName
self.site = None
self.setSiteData()
self.token = None
self.headers = None
self.createHeaders()
def setSiteData(self):
sites = [{'name': 'somedomain1', 'url': 'https://somedomain1.com/', 'AdminAPIKey': '5f...1', 'ContentAPIKey': '0b...9'},\
{'name': 'somedomain2', 'url': 'https://somedomain2.com/', 'AdminAPIKey': '5f...', 'ContentAPIKey': '25...e'}]
self.site = next((site for site in sites if site['name'] == self.siteName), None)
return None
def createToken(self):
key = self.site['AdminAPIKey']
id, secret = key.split(':')
iat = int(dt.now().timestamp())
header = {'alg': 'HS256', 'typ': 'JWT', 'kid': id}
payload = {'iat': iat, 'exp': iat + (5 * 60), 'aud': '/v3/admin/'}
self.token = jwt.encode(payload, bytes.fromhex(secret), algorithm='HS256', headers=header)
return self.token
def createHeaders(self):
if self.site != None:
self.createToken()
self.headers = {'Authorization': 'Ghost {}'.format(self.token.decode())}
return self.headers
3. Customize your class
In the method setSiteData() there is a list with all your Ghost sites. Each list item is a dict with the name, url and the AdminAPIKey and ContentAPIKey. Set all dict values to the values of your ghost sites. For the AdminAPIKey and ContentAPIKey see CUSTOM INTEGRATIONS above.
4. Authentication
All API requests to Ghost must be authenticated. For authenticating with the Admin API you must create an access token. This is done in the method createToken(). These are short-lived single-use JSON Web Tokens (JWTs). The lifespan of a token has a maximum of 5 minutes (see above: iat+(5 * 60)). Be aware of token expiration: If you work in the debugger and your app pauses on a breakpoint, the token can expire.
5. HTTP headers
All requests to the Ghost API require HTTP headers: the application name and the access token. The headers are created with the method createHeaders().
6. Endpoints
Now we want to work with the API and use some of its endpoints. First we want to browse through all settings of a site. We add the method getSettings(). This method uses the the endpoint /settings/ of the Content API.
def getSettings(self):
settings = {}
url = self.site['url']+'ghost/api/v3/content/settings/?key='+self.site['ContentAPIKey']
result = requests.get(url, headers=self.headers)
if result.ok:
settings = json.loads(result.content)['settings']
return settings
In this method you create the request url. It accepts just one parameter, the content api key. It has this form:
https://somedomain1/ghost/api/v3/content/settings/?key='ContentAPIKey'
Given this url and the headers you send a request:
requests.get(url, headers=self.headers)
Now we can already use our class. At the bottom of ghostAdmin.py insert the following code:
if __name__ == '__main__':
ga = GhostAdmin('somedomain1') # the name of your ghost site
settings = ga.getSettings()
The returned value settings is a dict with key, values like title, logo etc.