Table of Contents
Date | Notes |
---|---|
2021-Sep-28 | Using summary and patterns style. |
2020-Oct-04 | Initial version in Wiki. |
When building a digital ecosystem API usability becomes a business priority. Success of your ecosystem depends on APIs that are easy to discover, simple to use, fit for purpose, and consistent across your products.
This document offers guidance that Microsoft Graph API producer teams MUST follow to ensure that Microsoft Graph has a consistent and easy to use API surface. A new API design should meet the following goals:
- Developer friendly via consistent naming, patterns, and web standards (HTTP, REST, JSON)
- Work well with SDKs in many programming languages.
- Sustainable & evolvable via clear API contracts.
The Microsoft Graph guidelines are an extension of the Microsoft REST API guidelines. Readers are assumed also be reading and following the Microsoft REST API guidelines except where this document outlines specific differences or exceptions to those guidelines. Together these guidelines and a library of API patterns serve as the means by which API teams discuss and come to consensus on API review requirements.
Technology and software are constantly changing and evolving, and as such, this is intended to be a living document. API guidelines that change frequently lead to an uneven and inconsistent API surface. Consequently, this document will more frequently change to add guidance in areas previously uncovered, or to clarify existing guidance. It will less frequently change the directional guidance it has already provided. Open an issue to suggest a change or propose a new idea.
This document offers prescriptive guidance labeled as follows:
✔️ MUST satisfy this specification.
⛔ MUST NOT use this pattern.
☑️ SHOULD fulfill this specification.
If not following these advices, you MUST disclose your reasons during the Graph API review.
The design of your API is arguably the most important investment you will make. API design is what creates the first impression for developers when they discover and learn how to use your APIs. We promote API-first design approach where you begin your product design by focusing on how information will be exchanged and represented and creating an interface contract for your API which is followed by design and implementation of the backing service. This approach ensures decoupling of the interface from your implementation and is essential for agility, predictability, and reuse of your APIs. Established interface contract allows developers to use your API while internal teams are still working on implementation; API specifications enable designing of user experience and test cases in parallel. Starting with user-facing contracts also promotes a good understanding of system interactions, your modeling domain, and understanding of how the service will evolve. Microsoft Graph supports resource and query-based API styles which follow HTTP, REST, and JSON standards, where API contract is described using ODATA conventions and schema definition (see Documentation · OData - the Best Way to REST). Documentation · OData - the Best Way to REST).
In general API design includes the following steps:
-
Outline the key current and future scenarios for API consumers
-
Define your domain model
-
Derive and name your API resources
-
Describe relationships between resources
-
Determine required behavior
-
Determine user roles and application permissions
-
Specify errors
When creating your API contract you will define resources based on the domain model supporting your service and identify interactions based on user scenarios. Good API design goes beyond modeling the current state of resources and it is important to plan ahead how API evolves. For this it is essential to understand and document your user scenarios as the foundation of the API design. There is no one-to-one correspondence between domain model elements and API resources because you should simplify your customer facing APIs for better usability and to obfuscate implementation details. We recommend creating a simple resource diagram, like below, to show resources and their relationships and make it easier to reason about modeling choices and the shape of your API.
After resources are defined it’s time to think about the behavior of your API which can be expressed via HTTP methods and operational resources such as functions and actions. As you think about API behavior you identify a happy path and various exceptions and deviations which will be expressed as errors and represented using HTTP codes and error messages.
At every step of your design you need to consider security, privacy and compliance as intrinsic components of your API implementation.
API resources are typically described by nouns. Resource and property names appear in API URLs and payloads and must be descriptive and easy to understand for developers. Ease of understanding comes from familiarity and recognition therefore when thinking about naming you should favor consistency with other Graph APIs, names in the product user interface, and industry standards. Microsoft Graph naming conventions follow Microsoft REST API Guidelines.
Below is a short summary of the most often used conventions.
Requirements | Example |
---|---|
⛔ MUST NOT use redundant words in names. | - Right: /places/{id}/displayName and /phones/{id}/number - Wrong /places/{id}/placeName and /phones/{id}/phoneNumber |
- Right: chat - Wrong teamsChat |
|
- Right: url or htmlSignature - Wrong msodsUrl or dlp |
|
✔️ MUST use singular nouns for type names. | - Right: address - Wrong addresses |
✔️ MUST use plural nouns for collections (for listing a type or collection properties). | - Right: addresses - Wrong address |
☑️ SHOULD pluralize the noun even when followed by an adjective (a "postpositive"). | - Right: passersby or mothersInLaw - Wrong notaryPublics or motherInLaws |
casing | |
✔️ MUST use lower camel case for all names and namespaces | - Right: automaticRepliesStatus. - Wrong kebab-case or snake_case. |
☑️ SHOULD case two-letter acronyms with the same case. | - Right: ioLimit or totalIOAmount - Wrong iOLimit or totalIoAmount |
☑️ SHOULD case three+ letter acronyms the same as a normal word. | - Right: fidoKey or oauthUrl - Wrong webHTML |
⛔ MUST NOT capitalize the word following a prefix or words within a compound word. | - Right: subcategory, geocoordinate or crosswalk - Wrong metaData, semiCircle or airPlane |
✔️ MUST capitalize within hyphenated and open (spaced) compound words. | - Right: fiveYearOld, daughterInLaw or postOffice - Wrong paperclip or fullmoon |
prefixes and suffixes | |
✔️ MUST suffix date and time properties with | - Right: dueDate — an Edm.Date - Right: createdDateTime — an Edm.DateTimeOffset - Right: recurringMeetingTime — an Edm.TimeOfDay - Wrong dueOn or startTime - - Right: instead both above are an Edm.DateTimeOffset |
☑️ SHOULD use the Duration type for durations, but if using an int, append the units. | - Right: passwordValidityPeriod — an Edm.Duration - Right: passwordValidityPeriodInDays — an Edm.Int32 (NOTE use of Edm.Duration type is preferable) - Wrong passwordValidityPeriod — an Edm.Int32 |
⛔ MUST NOT use suffix property names with primitive type names unless the type is temporal. | - Right: isEnabled or amount - Wrong enabledBool |
☑️ SHOULD prefix property names for properties concerning a different entity. | - Right: siteWebUrl on driveItem, or userId on auditActor - Wrong webUrl on contact when its the companyWebUrl |
☑️ SHOULD prefix Boolean properties with is, unless this leads to awkward or unnatural sounding names for Boolean properties. | - Right: isEnabled or isResourceAccount - Wrong enabled or allowResourceAccount - Right: allowNewTimeProposals or allowInvitesFrom — subjectively more natural than the examples below - Wrong isNewTimeProposalsAllowed or isInvitesFromAllowed — subjectively more awkward that the examples above |
⛔ MUST NOT use 'collection', 'response', 'request ' suffixes . | - Right: addresses - Wrong addressCollection |
A Uniform Resource Locator (URL) is how developers access the resources of your API.
Navigation paths to Microsoft Graph resources are generally broken into multiple segments:
{scheme}://{host}/{version}/{category}/[{pathSegment}][?{query}] where
-
scheme and host segments are always https://graph.microsoft.com;
-
version can be V1.0 or beta;
-
category segment is a logical grouping of APIs into top-level categories;
-
pathSegment is one or many navigation segments which can address an entity, collection of entities, property or operation available for an entity
-
query string must follow the OData standard for query representations and is covered in Query section of OData specifications.
While HTTP defines no constraints on how different resources are related together, it does encourage the use of URL path segment hierarchies to convey relationships. In Microsoft Graph relationships between resources are supported by the OData concepts of singletons, entitySets, entities, complex types and navigation properties.
In Microsoft Graph a top-level API category may represent one of the following groupings:
-
A core user-centric concept of the Graph, i.e. /users, /groups or /me.
-
A Microsoft product or service offerings covering multiple use cases, i.e. /teamwork, /directory.
-
A feature offering covering a single use case and shared across multiple Microsoft products, i.e. /search, /notifications, /subscriptions.
-
Administrative configuration functions for specific products. i.e. /admin/exchange.
-
Internal Microsoft requirements for publishing Privileged and Hidden APIs, routing, and load testing, i.e./loadTestEntities.
Effectively top-level categories define a perimeter for the API surface thus a new category creation requires additional rigor and governance approval.
Microsoft Graph APIs should support basic query options in conformance with OData specifications and Microsoft REST API Guidelines.
Requirements |
---|
✔️ MUST support $select on resource to enable properties projection |
☑️ SHOULD support $filter with eq, ne operations on properties of entities for collections |
✔️ MUST support server-side pagination using a nextLink for collections |
☑️ SHOULD support pagination $top, $skip and $count for collections |
☑️ SHOULD sorting with $orderby both ascending and descending on properties of the entities |
The query options part of an OData URL can be quite long, potentially exceeding the maximum length of URLs supported by components involved in transmitting or processing the request. One way to avoid this is to use the POST verb instead of GET with $query segment, and pass the query options part of the URL in the request body as described in the chapter OData Query Options.
Another way is to use JSON batch as described in the [Microsoft Graph Documentation] (https://docs.microsoft.com/en-us/graph/json-batching#bypassing-url-length-limitations-with-batching).
You can model structured resources for your APIs using OData Entity Type or Complex Type. The main difference between these types is that Entity type declares a key property to uniquely identify its objects and Complex Type does not. In Microsoft Graph this key property is called "id" for server-created key values. If there is a natural name for the key property then the workload can use that. Since objects of complex types on Graph don’t have unique identifiers, they are not directly addressable via URIs and therefore you must not use Complex Type to model addressable resources, such as individually addressable items within a collection, for more information refer to Microsoft REST API Guidelines. Complex types are better suited to represent composite properties of API entities.
<EntityType Name="Author">
<Key>
<PropertyRef Name="id" />
</Key>
<Property Name="id" Type="Edm.String" Nullable="false" />
<Property Name="name" Type="Edm.String" />
<Property Name="address" Type="microsoft.graph.Address" />
</EntityType>
<ComplexType Name="Address">
<Property Name="city" Type="Edm.String" />
<Property Name="street" Type="Edm.String" />
<Property Name="stateOrProvince" Type="Edm.String" />
<Property Name="country" Type="Edm.String" />
</ComplexType>
Microsoft Graph rules for modeling complex resources |
---|
✔️ MUST use String type for id |
✔️ MUST use a primary key composed of a single property |
✔️ MUST use an object as the root of all JSON payloads |
✔️ MUST use a root object with a value property to return a collection |
✔️ MUST include @odata.type annotations when the type is ambiguous |
There are different approaches for designing an API resource model in situations with multiple variants of a common concept. Type Hierarchy, Facets, and Flat bag of properties are three most often used patterns in Microsoft Graph today:
-
Type hierarchy is represented by one abstract base type with a few common properties and one sub-type for each variant Modelling with Subtypes Pattern
-
Facets are represented by a single entity type with common properties and one facet property (of complex type) per variant. The facet properties only have a value when the object represents that variant Modelling with Facets Pattern
-
Flat bag of properties is represented by one entity type with all the potential properties plus an additional property to distinguish the variants, often called type. The type property describes the variant and also defines properties that are required/meaningful for the variant given by the type property. Modelling with Flat Bag Pattern
The following table shows summary of main qualities for each pattern and will help to select a pattern fit for your use case.
API qualities\ Patterns |
Properties and behavior described in metadata |
Supports combinations of properties and behaviors |
Simple query construction |
---|---|---|---|
Type hierarchy | yes | no | no |
Facets | partially | yes | yes |
Flat bag | no | no | yes |
The HTTP operations dictate how your API behaves. The URL of an API, along with its request/response bodies, establishes the overall contract that developers have with your service. As an API provider, how you manage the overall request / response pattern should be one of the first implementation decisions you make. APIs SHOULD use resource-based designs with standard HTTP methods rather than operation resources if possible. Operation resources are either functions or actions. According to ODATA standards a function represents an operation which returns a single instance or collection of instances of any type and doesn’t have an observable side effect. An action may have side effects and may return a result represented as a single entity or collection of any type.
Microsoft Graph rules for modeling behavior |
---|
✔️ MUST use POST to create new entities in insertable entity sets or collections. This approach requires the server to produce system generated identities. |
✔️ MUST use PATCH to edit updatable resources |
✔️ MUST use DELETE to delete deletable resources |
✔️ MUST use GET for listing and reading resources. |
☑️ SHOULD avoid using multiple round trips to complete a single logical operation. |
Operation resources must have a binding parameter matching the type of the bound resource. In addition both actions and functions support overloading, meaning an API definition may contain multiple actions or functions with the same name.
For a complete list of standard HTTP operations you can refer to the Microsoft REST API Guidelines.
Microsoft REST API Guidelines provide guidelines that Microsoft Graph APIs should follow when returning error condition responses. You can improve API traceability and consistency by using recommended Graph error model and the Graph Utilities library to provide a standard implementation for your service :
{
"error": {
"code": "BadRequest",
"message": "Cannot process the request because a required field is missing.",
"target": "query",
"innererror": {
"code": "RequiredFieldMissing",
}
}
}
The top-level error code must be aligned with HTTP response status codes according to rfc7231 (ietf.org). The following examples demonstrate error modeling for common use cases:
- Simple error: An API wants to report an error with top-level details only. Then the error object contains the top-level error code, message and target (optional).
{
"error": {
"code": "BadRequest",
"message": "Cannot process the request because it is malformed or incorrect.",
"target": "Resource X (Optional)"
}
}
- Detailed error: An API needs to provide service-specific details of the error via the innererror property of the error object. It is intended to allow services to supply a specific error code to help differentiate errors that share the same top-level error code but reported for different reasons.
{
"error": {
"code": "BadRequest",
"message": "Cannot process the request because it is malformed or incorrect.",
"innererror": {
"code": "requiredFieldOrParameterMissing",
}
}
}
Microsoft Graph enforces the following error rules |
---|
✔️ MUST return an error property with a child code property in all error responses. |
✔️ MUST return a 403 Forbidden error when the application or signed-in user have insufficient permissions are present in the auth token. |
✔️ MUST return a 429 Too Many Requests error when client exceeded throttling limits and 503 Service Unavailable when service overloaded but client is within throttling limits. |
☑️ SHOULD return a 404 Not Found error if a 403 would result in information disclosure. |
For a complete mapping of error codes to HTTP statuses you can refer to the rfc7231 (ietf.org).
Microsoft Graph definition of breaking changes is based on the Microsoft REST API Guidelines. In general, making all but additive changes to the API contract for existing elements is considered breaking. Adding new elements is allowed and not considered a breaking change.
** Non-breaking changes:**
- Addition of properties that are nullable or have a default value
- Addition of a member, after the sentinel member, to an evolvable enumeration
- Removal, rename, or change to the type of an annotation
- Changes to the order of properties
- Changes to the length or format of opaque strings, such as resource IDs
- Addition or removal of an annotation OpenType="true"
** Breaking changes:**
- Changes to the URL or fundamental request/response associated with a resource
- Removal, rename, or change to an incompatible type of a declared property
- Removal or rename of APIs or API parameters
- Addition of a required request header
- Addition of a EnumType members for non-evolvable enumerations
- Addition of a Nullable="false" properties to existing types
- Addition of a parameter not marked as Nullable to existing actions
- Addition of a parameter not marked as Optional to an existing function
- Changes to top-level error codes
- Introduction of server-side pagination to existing collections
- Significant changes to the performance of APIs such as increased latency, rate limits or concurrency.
As the market and technology evolves your APIs will require modifications in this case you must avoid breaking changes and add new resources and features incrementally. If that is not possible then you must version elements of your APIs. Microsoft Graph allows versioning of elements including entities and properties. Versioning involves adding a new, uniquely named version of the element and marking the old version as deprecated.
In some cases, there will be a natural new name for the element. In other cases, where the original name is still the most descriptive, the suffix _v2 can be added to the original name to make it unique. The original element is then marked as deprecated using annotations.
Microsoft Graph provides two public endpoints to support API lifecycle:
- API sets on the v1.0 endpoint (https://graph.microsoft.com/v1.0) are in general availability (GA) status.
- API sets on the beta endpoint (https://graph.microsoft.com/beta) are in beta or private preview status.
Microsoft Graph APIs in the GA version guarantee API stability and consistency for its clients. If your API requires a breaking change in GA, then you MUST create new element versions and support deprecated elements for a minimum of 36 months or 24 months with demonstrated non-usage. On the beta endpoint breaking changes and deprecation of APIs are allowed with consideration of dependencies and customer impact. It is best practice to test new element versions on the beta endpoint at first then promote API changes to the GA endpoint. Detailed requirements for versioning and deprecation are described in the Deprecation guidelines.
The guidelines in previous sections are intentionally brief and provide a jump start for Graph API developers. More detailed design guidance on REST APIs is published at the Microsoft REST API Guidelines and Graph specific patterns are outlined in the table below.
Recommended API Design patterns:
Pattern | Description | Reference |
---|---|---|
Type Hierarchy | The ability to model is-a relationships using subtypes. | Subtypes |
Facets | The ability to model parent-child relationships using Facet pattern. | Facets |
Dictionary | The ability for clients to provide an unknown quantity of data elements of the same type. | Dictionary |
|