Adding REST services, shapes, and queries

You can add any REST API as a service in TakeShape. When you combine REST APIs with custom Queries & Mutations, you can enable powerful, custom functionality in your project's GraphQL API.

Connecting a REST service requires you to know the endpoint you're connecting to and any authentication requirements it has.

Here's some REST APIs you can freely connect to try it out:

In the following walkthrough, we'll be using the Open Weather API.

Connect a REST service

Start by going to your project's schema tab. Then, click Connect Service in the top right corner of the services table. From here, select REST as the service you'd like to connect.

Here, we're connecting with the Open Weather API by providing a basic Name and Slug for our service, then defining the Endpoint for the API we're connecting.

The Open Weather API doesn't require any authentication, but many other REST APIs do. Authentication for REST APIs can take many forms. The REST service supports four authentication schemes:

  1. Header When using Header authentication, the Auth Prop field should be the name of the header field providing the auth, while the Access Token field provides its value.
  2. Query Parameter When using Query Parameter authentication, the Auth Prop and Access Token will be appended as a query string parameter to the API's URL.
  3. Bearer Token When using Bearer Token authentication, the Auth Prop value is not used. Instead, the Access Token value should contain your API access token or secret.
  4. Basic Auth When using Basic Auth authentication, the Auth Prop value is not used. Instead, the Access Token value should be use the format of username:password.

When your service is fully configured, click Save.

Create a query or mutation for a REST service by editing the schema file

After connecting your REST service, you'll probably want to add some queries that make use of it.

Currently, there's no way to add queries for REST services in the TakeShape web client, so using the TakeShape CLI we will need to export your project's schema.json file, directly edit it to add the shapes and queries you'd like to expose in your GraphQL API, and then import it back into your project. Learn more about exporting and importing your project schema.

Using the connected Weather service as an example, we'll be editing our project schema to  add a query that returns the current weather conditions for a provided zip code:

{
  getWeather(zip: "06378") {
    name 
    main {
      temp
      temp_min
      temp_max
      feels_like
    }
  }
}

Define your query

After connecting the Open Weather service and exporting your project schema to a schema.json file, we'll open the file in our favorite code editor. To the queries object in schema.json, we'll add:

"getWeather": {
	"description": "Returns the weather for a provided location",
	"args": "WeatherArgs",
  "shape": "Weather",
  "resolver": {
    "name": "rest:get",
    "service": "rest:weather",
		"options": {
      "path": "weather"
    },
    "argsMapping": {
      "searchParams.zip": [["jsonPath", {"path": "$.args.zip"}]],
      "searchParams.units": [["set", {"value": "imperial"}]]
    }
  }
}

Here, we're creating a query by defining the shapes for the query's input arguments, the shape of the query's response, and the resolver the query will use to fulfill our request.

The resolver describe how the query should be implemented. In this case, we're saying that the resolver should make a GET call to the /weather path of the service we connected in the last step.

Mapping query arguments to REST parameters

In the resolver, we're also defining a mapping between our GraphQL query's input arguments and the arguments the REST endpoint expects. Since we're making a GET request, we'll pass our arguments as query string arguments, also referred to as search params.

Our values are defined using directives, which are a composable set of instructions. Each directive is a two-element array, which combines an operation like "jsonPath" or "set" with a configuration.

  • For the units argument, we're providing a literal string value to the "set" directive
  • For the zip argument, we're actually passing through the zip argument from our query's input args! We access those input values by passing the argument's path to the jsonPath directive.

Learn more about configuring Resolvers

Define your shapes

Next, we'll need to create the shapes that we defined in the query above: WeatherArgs and Weather. We'll also add a helper shape for Weather named WeatherMain.

We'll start by adding a WeatherArgs entry to our schema's "shapes" object:

"WeatherArgs": {
  "id": "weather-args-id",
  "name": "WeatherArgs",
  "title": "WeatherArgs",
  "schema": {
    "type": "object",
    "properties": {
      "zip": {
        "type": "string",
        "title": "Zip Code"
      }
    },
    "required": ["zip"]
  }
}

For the WeatherArgs shape, we're providing an id, name, and title, then defining the shape's schema. It has one field, zip, that is a required string.

Next, we'll add a Weather and supporting WeatherMain shape to the "shapes" object:

"Weather": {
  "id": "weather-id",
  "name": "Weather",
  "title": "Weather",
  "schema": {
    "type": "object",
    "properties": {
      "main": {
        "$ref": "#/shapes/WeatherMain/schema"
      },
      "id": {
        "type": "number"
      },
      "name": {
        "type": "string"
      },
      "code": {
        "type": "string"
      }
    }
  }
},
"WeatherMain": {
  "id": "weather-main-id",
  "name": "WeatherMain",
  "title": "WeatherMain",
  "schema": {
    "type": "object",
    "properties": {
      "temp": {
        "type": "number"
      },
      "feels_like": {
        "type": "number"
      },
      "temp_min": {
        "type": "number"
      },
      "temp_max": {
        "type": "number"
      },
      "pressure": {
        "type": "number"
      },
      "humidity": {
        "type": "number"
      }
    }
  }
}

Why two shapes? We need to match the structure of the response that comes back from the Open Weather API, and Shapes only support 1 layer of properties. So, since the response comes back looking like:

{
	code: "02134",
	name: "Boston, MA",
	main: {
		"temp": 72.5
	}
}

We need a shape to capture the contents of main, so we add the WeatherMain shape that contains all the fields that it can return. Then, we link the WeatherMain shape to the Weather shape's main property using the $ref syntax.

Upload your edited schema

Now that we've added our query and shapes, we can finally upload our new schema to our project using the CLI or API.

As long as the schema is valid, the upload will succeed and the project will now support the new getWeather query!

Try using it in your project's API explorer:

getWeather(zip: "02134") {
	name
	main {
		temp
	}
}

Join us

Interested in joining the team as coworker or investor?

contact@takeshape.com