Custom HTTPS Endpoints
On this page
You can define custom HTTPS endpoints to create app-specific API routes or webhooks that integrate with external services. A custom endpoint uses a serverless function that you write to handle incoming requests for a specific URL and HTTP method.
Note
Custom HTTPS Endpoints are not supported in private endpoints.
Endpoints use standard, encrypted HTTPS requests, which means that you don't need to install any database drivers or opinionated libraries to call them. Instead, you send requests like this from any HTTP client:
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/hello" \ -X POST \ -H "Accept: application/json" \ -H "apiKey: TpqAKQgvhZE4r6AOzpVydJ9a3tB1BLMrgDzLlBLbihKNDzSJWTAHMVbsMoIOpnM6" \ -d '{ "name": "Casey" }'
Structure of an Endpoint
An endpoint handles one or more HTTP methods sent to a specific URL.
Base URL
Endpoints in an app share a base URL. The URL uses your App ID to uniquely point to your app.
Globally deployed apps use the following format:
https://data.mongodb-api.com/app/<App ID>/endpoint
Endpoints in a locally deployed app use a base URL specific to the app's
deployment region (e.g. us-east-1
)
https://<Region>.aws.data.mongodb-api.com/app/<App ID>/endpoint
Endpoint Routes
Every HTTPS endpoint has a route that serves as a name for the endpoint. An endpoint's route is arbitrary and specific to your app. However, it appears in the endpoint URL path and so should represent the action the route performs.
Route names must begin with a forward slash (/
) and may contain
additional forward slashes to indicate a nested path.
/my/nested/route
You call an endpoint by appending its route to your app's base URL and sending an HTTP request.
https://data.mongodb-api.com/app/<App ID>/endpoint/my/nested/route
HTTP Methods
Each endpoint in your app handles one or more HTTP methods for a given route. For example, you might have a
single route that accepts POST
requests to create a new resource and
a GET
request to list existing resources.
You can define multiple custom endpoints that serve the same route but handle different request methods. Alternatively, you can define a single endpoint for the route that handles all methods.
Custom endpoints support the following standard HTTP methods:
Create a Custom HTTPS Endpoint
You can configure the Data API for your app from the App Services UI or by deploying configuration files with App Services CLI:
Click HTTPS Endpoints in the left navigation menu and then click Add An Endpoint.
Define the endpoint Route. Route names must begin with a forward slash (
/
) and may contain additional forward slashes to indicate a nested path.Choose an HTTP method for the endpoint from the dropdown. You can choose either a specific method (e.g.
GET
orPOST
) or configure the endpoint to accept any HTTP method (i.e.ANY
).Choose a response type, either JSON or EJSON. You can enable Respond With Result to automatically include the endpoint function's return value as the response body.
Write an endpoint function that handles requests for the endpoint. Alternatively, specify an existing function by name.
For additional security, you can configure request authorization.
Save the Data API configuration.
Configure access permissions to allow requests to securely read and write data.
Save and deploy your app.
Pull the latest version of your app.
appservices pull --remote="<Your App ID>" Define a configuration object for the custom endpoint.
http_endpoints/config.json[ { "route": "<Endpoint route name>", "http_method": "<HTTP method>", "function_name": "<Endpoint function name", "validation_method": "<Authorization scheme>", "respond_result": <boolean>, "fetch_custom_user_data": <boolean>, "create_user_on_auth": <boolean>, "disabled": <boolean> } ] Define rules for one or more collections.
data_sources/mongodb-atlas/<db>/<collection>/rules.json{ "database": "<Database Name>", "collection": "<Collection Name>", "roles": [<Role>], "filters": [<Filter>] } Deploy your app.
appservices push
Authentication
Custom endpoints run in the context of a specific user, which allows your app to enforce rules and validate document schemas for each request.
By default, endpoints use Application Authentication, which requires each request to include credentials for one of your application users, like an API key or JWT. You can also configure other custom authentication schemes to fit your application's needs.
For examples of how to authenticate requests, see Authenticate Data API Requests.
Application authentication requires users to log in with an authentication provider that you have enabled for your App. Requests can either include an access token granted by the authentication provider or the credentials the user would log in with (e.g. their API key or email and password).
User ID authentication runs all requests as a single, pre-selected application user. This is useful if all requests should have the same permissions regardless of who called the endpoint.
To select the user, specify their User Account ID in the endpoint configuration.
[ { ..., "run_as_user_id": "628e47baf4c2ac2796fc8a91" } ]
Script authentication calls a function to determine which application user a request runs as. You can use this to implement custom authentication and authorization schemes.
The function must return an existing application user's Account ID
as a string or { "runAsSystem": true }
to run the request
as a system user that has full access to
MongoDB CRUD and Aggregation APIs and is not subject to any
rules, roles, or limited permissions.
To define the function, specify the source code in the endpoint configuration.
[ { ..., "run_as_user_id_script_source": "exports = () => {return \"628e47baf4c2ac2796fc8a91\"}" } ]
System authentication configures an endpoint to run as a system user that requires no credentials, has full access to MongoDB CRUD and Aggregation APIs, and is not subject to any rules, roles, or limited permissions.
[ { ..., "run_as_system": true } ]
Tip
New endpoints that you create in the UI use System authentication by default.
Authorization
An endpoint can require authenticated users to provide additional authorization information in the request. You define the authorization scheme for each custom endpoint by configuring the endpoint function.
Endpoints natively support a set of built-in authorization schemes that use a secret string to prove that the request is authorized. You can also define a custom authorization scheme that you can use together with or instead of the built-in schemes.
To learn how to configure authorization for a specific function, see Define a Function.
Built-In Authorization Schemes
Endpoints support the following built-in authorization schemes:
All authenticated users are authorized to call the endpoint. Authenticated requests do not need to include authorization information.
Authenticated users must prove that they are authorized to call
the endpoint by including a specific string as the value of the
secret
query parameter.
You define the string in a secret and reference the secret by name in the endpoint configuration.
[ { ..., "verification_method": "SECRET_AS_QUERY_PARAM", "secret_name": "secret_verification_string" } ]
To learn how to include the secret in a request, see Authorize the Request.
Authenticated users must prove that they are authorized to call
the endpoint by including an Endpoint-Signature
header that
contains a hexadecimal-encoded HMAC SHA-256 hash generated from the request body
and a secret string.
You define the string in a secret and reference the secret by name in the endpoint configuration.
To learn how to sign your requests, see Authorize the Request.
Custom Authorization Schemes
You can define a custom authorization expression to
determine if an incoming authenticated request is allowed to run. The
expression is evaluated for each request and must evaluate to true
to allow the request. If the expression evaluates to false
, the
request is not authorized and fails with an error. Requests that fail
authorization are not counted toward your App's billed usage.
Authorization expressions can use variables like
%%user
to authorize based on the calling user's data
or %%request
to make decisions based on the specifics
of each incoming request.
To define a custom authorization scheme, specify the expression in the endpoint function's configuration:
[ { ..., "can_evaluate": { "%%request.requestHeaders.x-secret-key": "my-secret" } } ]
Write an Endpoint Function
Every custom endpoint is associated with a function that runs whenever the endpoint receives an incoming request. In the function, you can import libraries from npm, connect to a linked MongoDB Atlas cluster, and call other serverless functions.
To define a new function when creating an endpoint in the App Services UI, navigate to the Function section and select + New Function from the dropdown.
Depending on your workflow, you can also define and edit endpoint handler functions:
On the Functions page in the App Services UI.
In the
functions
directory of your application using the App Services CLI.From your client using the Admin API.
Endpoint functions always receive two arguments:
A Request object that lets you access incoming request headers, query parameters, and body data.
A Response object that you use to configure the HTTPS response sent back to the caller.
For a sample function and an example request and response, see Example.
Access Request Data
A custom endpoint Request
object represents the HTTP request that
called the endpoint. You can access the incoming request's headers,
query parameters, and body data.
{ "headers": { "<Header>": ["<Header Value>"] }, "query": { "<Query Parameter>": "<Parameter Value>" }, "body": <BSON.Binary> }
Field | Description | |||||
---|---|---|---|---|---|---|
query | An object where each field maps a URL query parameter to its value. If a key is used multiple times in the query string, only the first occurence is represented in this object. To work with the full query string, use context.request.rawQueryString. ExampleThe following
| |||||
headers | An object where each field maps a request header name to an array of one or more values. Example
| |||||
body | A BSON.Binary object that contains the
request body. If the request did not include a body, this value
is To access data in the request body, you need to serialize the binary:
|
Return an HTTPS Response
A custom endpoint Response
object lets you configure the HTTPS
response sent back to the caller. You can set the status code, customize
headers, and include data in the response body.
Method | Description | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
setStatusCode(code) - code: number | Set the HTTP response status code. Example
| |||||||||
setBody(body) - body: string | BSON.Binary | Set the HTTP response body. If Example
| |||||||||
setHeader(name, value) - name: string - value: string | Set the HTTP response header specified
by Example
| |||||||||
addHeader(name, value) - name: string - value: string | Set the HTTP response header specified
by Example
|
Example
Consider an endpoint function that parses the body of an incoming POST
request, stores the parsed body in a MongoDB collection, and then
responds to the caller:
exports = async function MyCustomEndpoint(request, response) { try { // 1. Parse data from the incoming request if (request.body === undefined) { throw new Error(`Request body was not defined.`); } const body = JSON.parse(request.body.text()); // 2. Handle the request const { insertedId } = await context.services .get("mongodb-atlas") .db("myDb") .collection("myCollection") .insertOne({ date: new Date(), requestBody: body }); // 3. Configure the response response.setStatusCode(201); // tip: You can also use EJSON.stringify instead of JSON.stringify. response.setBody( JSON.stringify({ insertedId, message: "Successfully saved the request body", }) ); } catch (error) { response.setStatusCode(400); response.setBody(error.message); } };
The function receives the following POST
request:
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/custom" \ -X POST \ -H "Accept: application/json" \ -H "apiKey: TpqAKQgvhZE4r6AOzpVydJ9a3tB1BLMrgDzLlBLbihKNDzSJWTAHMVbsMoIOpnM6" \ -d '{ "type": "event", "date": "2024-01-01T00:00:00.000Z", "name": "New Year Begins", "comment": "Happy New Year!" }'
{ "message": "Successfully saved the request body", "insertedId": "639a521bbdec9b85ba94014b" }
After the function verifies that the body of the incoming request
is defined, it stores the parsed body as a new document in a collection
named myCollection
. The resulting output displays the configured
response, which includes a custom message and the insertedId
.
Call a Custom Endpoint
You can call a custom endpoint from any standard HTTPS client.
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/hello" \ -X POST \ -H "Accept: application/json" \ -H "apiKey: TpqAKQgvhZE4r6AOzpVydJ9a3tB1BLMrgDzLlBLbihKNDzSJWTAHMVbsMoIOpnM6" \ -d '{ "name": "Casey" }'
HTTP/1.1 or greater is required when making requests.
Choose a Response Data Format
A request can include an Accept
header to request a specific data
format for the response body, either JSON or EJSON. If a request does
not include a valid Accept
header, the response uses the default
data format specified in the endpoint configuration.
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/hello/latest" \ -X GET \ -H "Accept: application/ejson" \ -H "apiKey: TpqAKQgvhZE4r6AOzpVydJ9a3tB1BLMrgDzLlBLbihKNDzSJWTAHMVbsMoIOpnM6"
{ "greeting": "Hello, Leafie!", "date": { "$date": { "$numberLong": "1654589430998" } } }
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/hello/latest" \ -X GET \ -H "Accept: application/json" \ -H "apiKey: TpqAKQgvhZE4r6AOzpVydJ9a3tB1BLMrgDzLlBLbihKNDzSJWTAHMVbsMoIOpnM6"
{ "greeting": "Hello, Leafie!", "date": "2022-06-07T08:10:30.998Z" }
Authenticate the Request
If an endpoint is configured to use Application Authentication then you must include a valid user access token or login credentials with every request.
In general, bearer authentication with an access token has higher throughput and is more secure than credential headers. Use an access token instead of credential headers when possible. The token lets you run multiple requests without re-authenticating the user. It also lets you send requests from a web browser that enforces CORS.
To use an access token, first authenticate the user through an App Services authentication provider. Then, get the access token returned from App Services and include it in the request's Authorization header using a Bearer token scheme. For more information on how to acquire and use an access token, see Bearer Token Authentication.
curl -X GET \ -H 'Authorization: Bearer <AccessToken>' \ -H 'Content-Type: application/json' \ https://data.mongodb-api.com/app/myapp-abcde/endpoint/hello
Alternatively, you can include valid login credentials for the user in the request headers.
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/hello" \ -X POST \ -H "Accept: application/json" \ -H "email: bob@example" \ -H "password: Pa55w0rd!" \ -d '{ "name": "Bob" }'
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/hello" \ -X POST \ -H "Accept: application/json" \ -H "apiKey: TpqAKQgvhZE4r6AOzpVydJ9a3tB1BLMrgDzLlBLbihKNDzSJWTAHMVbsMoIOpnM6" \ -d '{ "name": "Alice" }'
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/hello" \ -X POST \ -H "Accept: application/json" \ -H "jwtTokenString: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ0ZXN0LWN1c3RvbS1lbmRwb2ludHMtZWhtenQiLCJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiZXhwIjoyMTQ1OTE2ODAwfQ.pIMvnXWrcDvmPzmE33ZPrwkBAFSwy-GxW8sP-qLtYiw" \ -d '{ "name": "Carlos" }'
Important
Don't Use API Keys in User-Facing Clients
If you're authenticating from a browser or another user-facing client application, avoid using an API key to log in. Instead, use another authentication provider that takes user-provided credentials. Never store API keys or other sensitive credentials locally.
Authorize the Request
Depending on the endpoint configuration, your requests may need to include additional authorization information.
All authenticated users are authorized to call the endpoint. Authenticated requests do not need to include authorization information.
Authenticated users must prove that they are authorized to call
the endpoint by including the endpoint's secret string as the
value of the secret
query parameter.
Example
The following curl
request uses secret query parameter
validation with the secret string "Super5ecr3tPa55w0rd"
:
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/passwordRequired?secret=Super5ecr3tPa55w0rd" \ -X GET \ -H "Accept: application/json" \ -H "apiKey: TpqAKQgvhZE4r6AOzpVydJ9a3tB1BLMrgDzLlBLbihKNDzSJWTAHMVbsMoIOpnM6" \ -d '{ "data": "VGhpcyBpcyBzb21lIGRhdGEgdGhhdCB3YXMgZW5jb2RlZCBhcyBhIEJhc2U2NCBBU0NJSSBzdHJpbmc=" }'
Authenticated users must prove that they are authorized to call
the endpoint by including an Endpoint-Signature
header that
contains a hexadecimal-encoded HMAC SHA-256 hash generated from the request body
and the endpoint's secret string.
Endpoint-Signature: sha256=<hex encoded hash>
You could use the following function to generate the payload signature:
/** * Generate an HMAC request signature. * @param {string} secret - The secret validation string, e.g. "12345" * @param {object} body - The endpoint request body e.g. { "message": "MESSAGE" } * @returns {string} The HMAC SHA-256 request signature in hex format. */ exports = function signEndpointRequest(secret, body) { const payload = EJSON.stringify(body); return utils.crypto.hmac(payload, secret, "sha256", "hex"); };
Example
The following curl
request includes a payload signature header
signed with the secret value Super5ecr3tPa55w0rd
:
curl -s "https://data.mongodb-api.com/app/myapp-abcde/endpoint/sendMessage" \ -X POST \ -H "Accept: application/json" \ -H "apiKey: TpqAKQgvhZE4r6AOzpVydJ9a3tB1BLMrgDzLlBLbihKNDzSJWTAHMVbsMoIOpnM6" \ -H "Endpoint-Signature: sha256=d4f0537db4e230d7a6028a6f7c3bb1b57c9d16f39176d78697e559ac333e0b36" \ -d '{ "message": "Hello!" }'