Designing a RESTful API which follows common REST principles can be a challenge for many developers. In this tutorial, we are going to cover the importance of designing an API specification and why RAML makes it easy for developers to design and document their APIs. If a developer follows best practices, an API can serve as documentation to other developers in your organization. Reuse is the most important feature of a well-designed API, so it’s important that a RAML specification promotes standardization and reusability through being modular.
As a developer, you only want to have to build something once. When you build an application or integration, you want others to be able to build onto the work you’ve already done without having to modify the original code or spend hours creating custom code to fit within your current application.
The first step to building an API is to list out what your API needs to do. Do you have to send a text message, change a password, or edit a database entry for example? Once you identify what your API is going to accomplish, remember to design it with reusability in mind from the get go. Since other developers are going to be consuming and accessing this API for years to come, you need to make sure that the initial contract sets the ground rules of how the API should be interfaced. If you go and make changes to your contract later, it could break critical systems which could lead to downtime or other catastrophic results.
Creating an API Specification enables you to code around the APIs definition, rather than defining your API with code. With RAML, you can outline how you envision your API is supposed to operate it, and then test it live in the browser while you are testing. If you are using MuleSoft’s API Designer, you can turn on the mocking service to try out your design live in the browser and identify major design-related issues before development starts.
If you are building out a REST API, make sure to use nouns as resources instead of verbs. The reasoning behind this is that verbs don’t give you as much flexibility when you are designing your methods since they are tightly coupled to a specific action. When you use nouns, you can have loosely coupled resources that accomplish multiple tasks. For example, there would be no need to create the endpoint /getContacts when you could just name your resource /contacts and send a GET request against that resource.
Additionally, it’s helpful to keep endpoints in the plural form unless you are explicit that you will only be fetching one singular value from your API Endpoint. For resources with more than 2 words, use lowercase for both words such as /allusers or use kebab-case such as /all-users.
Each method that you define should follow the correct verb logic.
- GET: For obtaining data.
- POST: To store data.
- PATCH: To update data. It will update partial data of an instance.
- PUT: To update data. It will update the entire instance.
- DELETE: To delete an instance.
- 200: Successfully read the resource you requested
- 201: Successfully created the resource you sent
- 401: Authentication is missing or incorrect
- 403: Authentication succeeded, but the user does not have access to the resource
- 404: The resource cannot be found, client-side error
- 500: There was an error on the server-side
When you are creating your endpoints and thinking about how users will consume with your APIs, there are a few best practices to follow when approaching your API design. Make sure to always use snake_case such as date_from or date_to. Also when you are dealing with collections, use commas to separate values such as /users?fields=name, last_name etc.
Sorting, on a database, for instance, can be a very expensive operation and if not performed efficiently can lead to large costs down the road. If you are creating an API for this similar use case, you should offer some sort of sorting operation such as a query string parameter called sort where you can sort by sort=date_added or sort=date_added DESC if you want to choose a sort direction by defining an additional query parameter.
Filtering is another useful feature to control results and restrict based on certain values. For instance, you could implement a query parameter like city=San Francisco to find all records in that region. Paging can list out results by batching the database for only 250 entries at a time for instance. You will see lots of developers set up a query parameter such as page which starts at 1 and has a limit for the page size.
Modularization of your RAML code gives you the ability to separate code into multiple documents to help organize your data. A library fragment can hold multiple types and is referred from other documents using the uses: statement. Library fragments can hold multiple types, and are referred to using dot notation: type: library.typeInsideLibrary
A custom DataType is helpful in your RAML DataType fragments hold a single type of data and are referenced from other documents using the !include tag.
When you are designing your REST API, most APIs will need mechanisms to securely access data, identify requests, and determine user access and visibility. Security Schemes allow you to implement security protocols such as OAuth, Basic Authentication, and token verification directly into your API. When designing your API in API Designer, lots of these protocols are already written for you in RAML, so it’s as easy and copy and pasting code to implement security directly into your API. Additionally, security policies defined in API Designer are enforced with API Manager. This means that if you apply a security policy, API Manager will block all incoming bad requests from hitting your Mule application which protects you from potential errors of vulnerabilities.
In this tutorial, we are going to build out our API Spec using a Library, Security Scheme, and DataType in API Designer. This API will integrate directly with Twilio and will allow you to send an SMS to a phone number by simply passing a simple POST request with your desired Message and ToPhoneNumber. In Anypoint Studio, we will build out the integration with our Twilio Client ID and Secret which will NOT be exposed to the API Consumer. This means that users interacting with our API only need to be issued a client ID and client secret from our API and can then send text messages without needing to expose our private credentials.
First, log into Anypoint Platform, and go to the Design Center. Click on the Create New button at the top right and click Create API Specification. Name your application SendSMSAPI or whatever you wish, choose Text Editor, RAML 1.0, and Save location: Design Center. Then click Create Specification.
When you first open up API Designer, you will be placed into the root file which contains your RAML code. We are going to first create a Library and DataType before we start building out our root file. The library will allow us to abstract our RAML code out of our root file. After we add our library, we are going to assign our endpoint with a DataType which sets rules on how we are allowed to interact with our API. Create a new file by clicking the + and call it library.raml and make sure to set the Library DataType in the dropdown menu. Copy and paste the below code into your library.raml file:
This code sets our DataType to be equal to the file dataType.raml (which we haven’t created yet). We define under resourceTypes that the resource will be defined under the variable text. When a POST request is sent, add the following description, and set the responses equal to the DataType. Next, let’s create the dataType.raml file. First, click the + button again and create a new folder and call it dataTypes then create a new file under that folder and call it dataType.raml and make sure you select DataType from the drop-down menu. Copy and paste the following code into dataType.raml:
As you can see, we set each of the fields to be required, or else the API will return a 400 response. We also defined that each value must be an integer for the phone number and string for the message. You can see the changes reflected on the preview window on the right hand side of API designer.
Finally, we have to add our Library and DataType to our root raml file. Add the following code to your root raml file:
As you can see, we are importing our library.raml file in our root file, and are referencing the text variable under type: library.text. We are defining that /text will be our endpoint, and that the endpoint should follow the rules set in the library under library.text.
When you save your root file, and enable the mocking service on the top right, you will see a preview of your API on the right-hand side of the screen. You can see with DataTypes and Libraries, that we were able to abstract all of the code out of the main raml file. Additionally, the mocking service window still generates all of the previews needed to properly interface with the API.
Create a new file, and call it securityScheme.raml and make sure to select the Security Scheme option from the drop-down menu. Copy and paste the following code into your securityScheme.raml file:
Once we deploy our API later in this tutorial, you will find the same RAML code located above under the API Specification snippet in API Manager. This code will generate when you apply a new policy to your already deployed API.
Next, go into your library.raml file and paste the following code under usage:
Now navigate back to your root raml file, and added the following code under the title variable:
This code will now secure the entire API with Basic Authentication security, which means users will have to provide a client_id and client_secret that’s issued to them by API manager
Now it's time to try out the API. Enable the mocking service, and click the send button to send a test payload. If you get the desired 200 OK response, you’ve done it! Now click the Publish button, and publish your API Specification to Exchange.
Open up Anypoint Studio and go to File -> New Mule Project. Enter your project name, and click the green plus button to import your API from Exchange. Search for your API in the search bar, then click the Add > button.
When you add the API Specification to your, Anypoint Studio will automatically apply scaffolding to your project using API Kit. Scroll down to the post:\text:application\json flow, we are going to build out our Twilio integration in this flow. The first step is to add an HTTP listener connector to the flow. Set the Path to: /text and when setting up the HTTP Listener config use:
To set up HTTPS, you will need to generate a keystore on your local machine. It’s super easy to do, and is just one line in the terminal. For instructions, please click here to see how to generate a keytool keystore.
Once you have generated your keystore, in the TLS section of the HTTP Listener, under Key Store Configuration, set:
Click Test Connection to verify that it worked correctly.
Next, drag the HTTP Request Connector into your flow and set the HTTP Request config to:
Click Save. Go to the Request section, and for Method type: POST and for the URL type:
Don't forget to put in your account SID from Twilio in the URL. Then go to the Request body and add the following code:
Next, under headers enter the code below. Make sure to press the fx button to allow you to enter your DataWeave code. Keep in mind where it says Account SID and Auth Token, you will get those both from your Twilio Dashboard. We combine both of the token values into the basic authorization format by using base64 encoding.
In order to deploy your application, you must first setup API Autodiscovery so we can assign security policies to our API. Log into Anypoint Platform and go to API Manager. In API Manager, click on the Manage API button, and click Manage API from Exchange. Find the API you created, and make sure to check the box saying you are using Mule 4 and above. Click Save, then click on the API and copy and paste the Autodiscovery API ID.
Go back into Anypoint Studio, and click on the Global Elements tab. Click the Create button, and search for API Autodiscovery. Paste in your API ID into the window and select your main flow under flow name.
Now right click on your project folder, and click Anypoint Platform, Deploy to Cloudhub.
In order for API to autodiscover, we need to include our anypoint platform client ID and secret under Properties upon deployment. See the screenshot below.
To find your client id and secret, go to Anypoint Platform, navigate to Access Management, Environments, and click on whatever environment you are deploying on (whether that is Sandbox, Production etc), and copy and paste your client id and secret into the corresponding fields on the deployment screen. Finally, click the deploy button! Nice work.
Navigate to Anypoint Platform, and go to API Manager. Click on your now Active API and got to Policies, then click the Apply New Policy button. Select the Client ID enforcement policy, leave all the settings as default.
When you apply this API level policy, making any POST request to your API endpoint will result in an error if you don’t include the proper headers. To grab your client ID and client secret for your API, go to Exchange, search for your API, and click Request Access. Enter your API Instance, your Application, and then click Request Access. This will generate your unique client ID and client secret that you will use to send POST requests to your API.
As you can see from the screenshot below, you will get a 401 unauthorized response if you don’t include the proper client_id and client_secret headers in your request.
However, when you enter both of the headers correctly based off the keys you get from Exchange, your text message will successfully be sent through Twilio.
We hope that this tutorial was helpful and helped walk you through the main steps of designing, developing, and deploying an API. Now that you have a good idea on how to build your first RAML specification and successfully deploy, take a look at our developer tutorials homepage where you can find more tutorials related to API design and development. Please rate this article and your feedback below.