Deploying the API
The Media Masher API describes over a dozen methods that allow you to create, manage, and process a collection of media. These are provided through a RESTful interface using JSON for both the request and response body. Your web server might call some or all of these methods, typically in response to requests coming from your clients or from other scripts you’ve written.
The API is available as a paid service through this site, but can also be self-hosted. There is also a headless container product available in the AWS Marketplace, built to easily integrate into your existing AWS infrastructure.
A reference implementation is included as part of the open source offering, in the form of the @mashermedia/express package which is available on AWS CodeArtifact (their npm). There is also a public container that uses it in the AWS Elastic Container Registry (their DockerHub). It is based on ExpressJS running on NodeJS. The MMExpressApi class defines route handlers for each of the methods.
The reference implementation is intended as an example to illustrate the API, and uses extremely lax security measures by default. Before deploying it in production, you MUST at least replace its authentication mechanism. For instance, the default implementation accepts any password and passes it unencrypted through basic HTTP authentication.
By default the implementation handles all methods internally. The container comes preinstalled with SQLite, FFmpeg, and the other tools necessary for more advanced processing. It uses storage on the container itself for uploads and other files.
It can also be customized to proxy some or all requests to the API. Currently the simplest approach would be to subclass the MMExpressApi class and override the routes you want to proxy, using code similar to what’s outlined below. Future versions will likely include a way to do this by providing environment variable to the container at startup.
Local First
There are actually use cases for Media Masher that don’t include a web server or remote calls to the API. Because the client stores all imported media and mashes locally first (before making any calls to the server) you can simply access this data from other client code you’ve written.
The MEDIA-MASHER element automatically handles storing this data for you, and provides methods to retrieve it. But you can also just access the underlying storage mechanisms like IndexedDB and File System directly. Data persists across browser refreshes and relaunches, though not forever. Browsers will sometimes just throw it all away, or perhaps prompt the user when certain storage thresholds are reached.
Under the hood, the client is actually using an API instance to achieve this, which it gets from the ApisPlugin. The SyncPlugin provides the API instance access to the local storage mechanisms and automatically propagates updates as each change is made to media.
The client can actually be configured to support multiple APIs, and this can be customized at both the client and server level, so things can seem confusing at first. But the default configuration is simply for this one, local-first API.
Without further configuration, the ‘save’ and ‘render’ buttons will not appear within the editor and no server calls will be made. The media browser will also be empty until the user starts importing files. It’s possible to supply an additional API in the client configuration to load some default media and an initial mash to edit. See the Embedding Guide for more information.
Architectures
More typically, deployments involve supporting some or all of the API methods on your existing web server or serverless solution you’re using. Which ones you choose to support depends entirely on the application you’re buidling.
For instance, an application that simply allows anonymous users to mash up your existing media might only require that the add
method be implemented. This method is responsible for handling requests containing the mash data, and storing it some how. The implementation could be as simple as writing JSON data to disk, cloud storage, or perhaps a database. No need to use the API.
This application could even make these mashups publicly viewable by deploying just the player portion of the editor, and pointing it directly to the saved JSON files. You only really need to call the encode
method of the API when you need a true video file produced from a mash.
Allowing users of the application to import their own media is a little trickier, but still possible without using the API. Your server would need to support the file
method to receive uploads, then save them to disk or cloud storage.
You’re probably not storing everything in the same directory as the html containing the editor, so you’d also need to add the path or host to the media data somehow. This can happen either in the client though configuration, or on server in the add
method. Alternatively, the download
or find
methods could be supported to set these at request time.
Many applications choose to decode
and transcode
uploaded media in order to optimize its use within the editor, but this is not required. It handles raw files just fine, and they might even work better if they are small and you’re just playing them back.
The processing methods like encode
, decode
and transcode
are harder to implement and require significant server resources you wouldn’t want running on the same machine as your application.
Many libraries and tools are required, as well as a custom build of FFmpeg.
For this reason mainly, most deployments either proxy these requests to the API or to some custom application they’ve built atop one of the container distributions. For instance, a proxy flow starts with the client making a request for the encode
endpoint on your server. Your code there then adds your secret API key to the Authorization header and passes the request to the API.
A common and recommended architecture is a hybrid approach: implement simple methods like find
and add
on your own server to work with your preferred storage mechanism, while you essentially proxy the resource-intensive processing requests to the API. But you probably do NOT want to do this in the application we’ve been describing because it allows these methods to be triggered by anonymous users.
Authorization
Applications that support the processing methods will typically also insist their users authenticate before triggering them. Applications may also require authentication for the other methods if they want to associate media to specific users.
The media objects being passed around the system can include string properties for userId
, accountId
, or both. A userId
always refers to a user in your application, while an accountId
always refers either to you in our system, or another account that has shared media with you.
Methods like find
allow you to limit results by either or both properties as well. Both are typically optional, since userId
is for your use only and the API will default to your accountId
based on the key you’ve provided in your request. You only need to include the accountId
when making find
requests for media owned by another Media Masher account. You need to include the userId
when you want results to include only media owned by one of your users.
There is no requirement that the
userId
property be an actual ID of a user on your system, or even related to authorization at all. The value can be any string, so this mechanism supports a wide range of filtering options.
Assuming you do have users who will be owning media, you want to first authenticate them in most of the methods your server supports. Use whatever mechanism your site currently relies on to associate each request with a specific user ID. Add that ID to relevant requests before or after you add the Authorization header containing your API key.
Invocation
Media Masher hosts its API at api.masher.media for registered users to access with an API key they generate. It accepts HTTPS POST requests with a JSON formatted body and headers that include the key. Responses are JSON formatted objects with either a data
property containing the actual response or error
property containing an error object.
Authentication
The server requires an API key to authenticate requests. This key must be generated on masher.media and added to your server’s environment variables or configuration file.
If you’ve used Media Masher before, you may already have an API key. If not, you can create one by following these steps:
- Log in to masher.media.
- Click on the user button in the top right corner of the page.
- Select Security from the dropdown menu.
- Click on the API Keys link in the left navigation.
- Enter a name for your API key so you can identify it later.
- Optionally,
- Set an expiration date for the key.
- Choose a hashing algorithm for the key.
- Click Generate Key to create a new API key.
Requests
To authenticate your requests, include the API key in the Authorization
header (it should NOT be prefixed with Bearer
). For example, the following code will retrieve your ten most recently updated media objects:
// best to retrieve key from environment or configuration
const key = 'your-api-key'
const endpoint = 'https://api.masher.media/mash'
const headers = {
'Authorization': key, 'Content-Type': 'application/json'
}
const body = JSON.stringify({ max: 10 })
const request = { method: 'POST', headers, body }
const response = await fetch(endpoint, request)
const { data, error } = await response.json()
Responses
If the request is handled successfully, the API will return a 200
status code along with an object in JSON format having a data
property that contains the actual response data which can be of any type.
If errors arise a 200
code may still be returned, but the object will contain an error
property that contains an error object having a message
property describing the issue.
If there are problems with the API itself you may receive 4XX
or 5XX
codes, with an unspecified body.
Methods
As described in the Embedding Guide, the Media Masher client can be configured to load its media from an API by calling its mash
and find
methods.
These are just two of many methods included in the Api interface which might be supported.
In addition to mash
and find
, another read method is media
, which returns a single media object for a given ID.
Each API can support a number of write methods like add
and remove
as well, that together allow the client to sync local changes made to media with the server.
Additionally, there are a few execute methods that process with media in some way, specifically decode
, encode
, and transcode
.
These are all long running server processes, so these functions return an object that can be passed to the API’s status
function to check for completion.
Method | Type | Interface |
---|---|---|
add | Write | ApiAddFunction |
apis | Read | ApiApisFunction |
decode | Execute | ApiDecodeFunction |
delete | Write | ApiDeleteFunction |
download | Read | ApiDownloadFunction |
encode | Execute | ApiEncodeFunction |
find | Read | ApiFindFunction |
insert | Write | ApiInsertFunction |
mash | Read | ApiMashFunction |
media | Read | ApiMediaFunction |
remove | Write | ApiRemoveFunction |
status | Execute | ApiStatusFunction |
transcode | Execute | ApiTranscodeFunction |
upload | Read | ApiUploadFunction |
The execute methods are not relient on the read/write methods. For instance, a mash does not need to be written to an API before it can be encoded as a video file. Similarly, a media resource does not need to be written before metadata can be decoded from it. The underlying files need to be uploaded somewhere, but you’re able to build requests that point anywhere.
add
Request | Response |
---|---|
ApiAddRequest | Numbers |
The add
method allows you to add media to your collection as well as update media previously added.
The request includes a media
property containing an array of StoredMedia objects. For each object, the response array will contain a number which is a timestamp indicating the moment the media was added or updated.
apis
Request | Response |
---|---|
ApiApisRequest | ApiOptions[] |
The apis
method returns a description of the API itself, and/or other APIs that the client has access to.
decode
Request | Response |
---|---|
ApiDecodeRequest | MediaResource |
The decode
method allows you to extract metadata from a raw resource file. This process involves retrieving and analyzing the file to determine information such as dimensions, duration, and format.
The arg
property of the request should be a RawStorableResource object with a request
that points to the uploaded file.
The response contains an id
property containing the resourceId
from the request, or a new UUID if empty. It also contains a mediaId
property containing the mediaId
from the request or a new UUID. The response can be passed directly to the status method as a request to check for completion.
delete
Request | Response |
---|---|
ApiDeleteRequest | true |
The delete
method allows you to delete multiple resources from multiple media objects.
The args
property of the request is an object having keys that are media IDs and values that are arrays of StoredResource objects. The objects will be deleted from their media’s resources
array and any underlying files will be deleted from storage. When the deletion succeeds the response will simply be a true boolean value.
download
Request | Response |
---|---|
ApiDownloadRequest | ApiDownloadResponse[] |
The download
method provides requests that can be used to fetch the resources of a media object. The request is an array of ApiDownloadRequest objects having a resource
property containing a
StoredResource, plus the associated accountId
and mediaId
.
The response is an array of ApiDownloadResponse objects, containing a request
property that can be used to retrieve the file.
encode
Request | Response |
---|---|
ApiEncodeRequest | MediaResource | Encoding |
The encode
method allows you to convert a mash into a single output file of any type.
The arg
property of the request should be a StorableMash object and any associated media should be placed in the mashMedia
property. Any raw resource associated with this media must have a valid request
property that points to its underlying files.
The response contains an id
property containing the resourceId
from the request, or a new UUID if empty. It also contains a mediaId
property containing the id
from the mash object, or the mediaId
from the request or a new UUID. The response can be passed directly to the status method as a request to check for completion.
find
Request | Response |
---|---|
ApiFindRequest | ApiFindResponse[] |
The find
method allows you to search for media and page through results.
The search can be limited by media id, type, source, label, update time, acountId, or userId.
If you already know the IDs of the media you want to retrieve, they can be specified in the ids
array property. The results will be in the same order as the IDs.
Otherwise, the other request properties are used to limit and sort results.
An empty request will return all media, sorted by its update timestamp in descending order (latest to earliest).
To return just the media updated since a particular time, include a timestamp for the updatedSince
property.
To limit results to a RawType supply it as the type
property.
You can also provide a source
to limit results to media from that source.
Providing a prefix
property will limit results to media whose label begins with that string. It will also change the default sort
property from -1 to 1, so the results are sorted alphabetically (A to Z). In either case the order can be reversed by negating the default sort
property.
To receive a subset of media from the set, supply the desired number of results in the max
property.
If this is less than the set count, a next
property will be included in the response, which can be passed in subsquent requests to page through the set.
The response includes a media
property with an array of StoredMedia objects. If max
and includeInfo
have been supplied in the request, the count
and updatedAt
number properties will be included, indicatinh the set count and maximum update timestamp.
insert
Request | Response |
---|---|
ApiInsertRequest | ResourcesByMediaId |
The insert
method allows you to insert multiple resources into multiple media objects. The args
property of the request is an object having keys that are media IDs and values that are arrays of StoredResource objects.
The objects will be inserted into their media’s resources
array.
The resources
property of the response is the same object as the args
property of the request, but with updated resources.
mash
Request | Response |
---|---|
ApiMashRequest | ApiMashResponse |
The mash
method returns a single media object to be loaded initially into the editor.
If a specific media object is desired, its ID can be provided in the request’s mediaId
property.
The media
property of the response can contain a StoredMedia object.
Typically this is the most recently updated mash, but the client will construct a mash from any media object. It can also be undefined, in which case the client will construct a new blank mash.
media
Request | Response |
---|---|
ApiMediaRequest | ApiMediaResponse |
The media
method returns a single media object for a the supplied id
property. If the media belongs to another user, their ID should be included in the user
property.
The media
property of the response contains a StoredMedia object.
remove
Request | Response |
---|---|
ApiRemoveRequest | Numbers |
The remove
method allows you to remove one or more media objects from your collection by ID.
The mediaIds
property of the request is an array of media IDs. The response is an array of timestamps indicating the moment the media was removed.
status
Request | Response |
---|---|
ApiStatusRequest | MediaResource | StoredResource |
The status
method allows you to check the progress of a previous decode, encode, or transcode call.
The request is the MediaResource object returned by the previous method call. The response will be the same object if it’s still in progress, or a Resource object once it has completed.
transcode
Request | Response |
---|---|
ApiTranscodeRequest | MediaResource | Transcoding |
The transcode
method allows you to convert media files from one format to another, or downsample them for a more optimized editing experience.
The arg
property of the request is a RawStorableResource object. The desired output TranscodingSource is supplied in the source
property. Depending on its value, the opt
property contains either an EncodeOutputOptions, WaveformOutputOptions, or BitmapsOutputOptions object.
The response contains an id
property containing the resourceId
from the request, or a new UUID if empty. It also contains a mediaId
property containing the mediaId
from the request or a new UUID. The response can be passed directly to the status method as a request to check for completion.
upload
Request | Response |
---|---|
ApiUploadRequest[] | ApiUploadResponse[] |
The upload
method provides requests that can be used to pass a file from the client to the server. The request is an array of ApiUploadRequest objects having a resource
property containing a StoredResource, plus the associated mediaId
and accountId
.
The response is an array of ApiUploadResponse objects, containing a request
property containing an EndpointRequest that can be used to upload the file and an optional fileProperty
string. For PUT requests, the file data itself is added to this request as the body. If POST is used, the default method will be ‘multipart/form-data’, and the file will be placed in the body data under the value of fileProperty
(defaults to ‘file’).