Docs Menu

Docs HomeAtlas App Services

Custom HTTPS Endpoints

On this page

  • Structure of an Endpoint
  • Base URL
  • Endpoint Routes
  • HTTP Methods
  • Create a Custom HTTPS Endpoint
  • Authentication
  • Authorization
  • Write an Endpoint Function
  • Access Request Data
  • Return an HTTPS Response
  • Example
  • Call a Custom Endpoint
  • Choose a Response Data Format
  • Authenticate the Request
  • Authorize the Request

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.

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"
}'

An endpoint handles one or more HTTP methods sent to a specific 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:

Endpoint Base URL (Global Apps):
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)

Endpoint Base URL (Local Apps)
https://<Region>.aws.data.mongodb-api.com/app/<App ID>/endpoint

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.

An endpoint route
/my/nested/route

You call an endpoint by appending its route to your app's base URL and sending an HTTP request.

An endpoint URL
https://data.mongodb-api.com/app/<App ID>/endpoint/my/nested/route

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:

You can configure the Data API for your app from the App Services UI or by deploying configuration files with App Services CLI:

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.

Tip

New endpoints that you create in the UI use System authentication by default.

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.

Endpoints support the following built-in 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:

http_endpoints/config.json
[
{
...,
"can_evaluate": {
"%%request.requestHeaders.x-secret-key": "my-secret"
}
}
]

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:

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.

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.

Endpoint Request Object
{
"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.

Example

The following query object represents the query string ?regions=na,eu&currency=USD:

{
"regions": "na&eu",
"currency": "USD"
}
headers

An object where each field maps a request header name to an array of one or more values.

Example

{
"Content-Type": ["application/json"],
"Accept": ["application/json"],
"X-CustomHeader": ["some-value", "some-other-value"]
}
body

A BSON.Binary object that contains the request body. If the request did not include a body, this value is undefined.

To access data in the request body, you need to serialize the binary:

// Convert the request body to a JSON string
const serialized = request.body.text();
// Parse the string into a usable object
const body = JSON.parse(serialized);

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

response.setStatusCode(201);
setBody(body)
- body: string | BSON.Binary

Set the HTTP response body.

If body is a string, the endpoint automatically encodes it as a BSON.Binary.

Example

response.setBody(
"{'message': 'Hello, World!'}"
);
setHeader(name, value)
- name: string
- value: string

Set the HTTP response header specified by name to the value passed in the value argument. This overrides any other values that may have already been assigned to that header.

Example

response.setHeader(
"Content-Type",
"application/json"
);
addHeader(name, value)
- name: string
- value: string

Set the HTTP response header specified by name to the value passed in the value argument. Unlike setHeader, this does not override other values that have already been assigned to the header.

Example

response.addHeader(
"Cache-Control",
"max-age=600"
);
response.addHeader(
"Cache-Control",
"min-fresh=60"
)

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.

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.

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.

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.

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.

Depending on the endpoint configuration, your requests may need to include additional authorization information.

←  Data API EndpointsAuthenticate Data API Requests →