Getting Started

So You Want An API?

The easiest way to get started with Elide is to use the elide-standalone library. The standalone library bundles all ofthe dependencies you will need to stand up a web service. This tutorial will use elide-standalone, all of the code isavailable here–if you want to see a more fully fleshed out example of the standalone library checkout thisKotlyn blog example.

JPA beans are some of the most important code in any Elide project. Your beans are the view of your data model that youwish to expose. In this example we will be modeling a software artifact repository since most developers have ahigh-level familiarity with artifact repositories such as Maven, Artifactory, npm, and the like. If you are interested,the code is tagged for each step so you can follow along.

The first bean we’ll need is the ArtifactGroup bean, for brevity we will omit package names and import statements. Thiswill represent the <groupId> in Maven’s dependency coordinates.

  1. @Include(rootLevel = true)
  2. @Entity
  3. public class ArtifactGroup {
  4. @Id
  5. public String name = "";
  6. }

Spin up the API

So now we have a bean, but without an API it is not do very useful. Before we add the API component of the we need tocreate the schema in the database that our beans will use. Download and run the demo setup script; thisdemo uses MySQL, feel free to modify the setup script if you are using a different database provider.

You may notice that there are more tables that just ArtifactGroup, and that the ArtifactGroup table has more fieldsthat our bean. Not only will our bean work just fine, we expect that beans will normally expose only a subset of thefields present in the database. Elide is an ideal tool for building micro-services, each service in your system canexpose only the slice of the database that it requires.

Classes

Bringing life to our API is trivially easy. We need two new classes: Main and Settings.

  1. public class Main {
  2. public static void main(String[] args) throws Exception {
  3. ElideStandalone app = new ElideStandalone(new Settings());
  4. app.start();
  5. }
  6. }
  1. public class Settings implements ElideStandaloneSettings {
  2. @Override
  3. public String getModelPackageName() {
  4. return ArtifactGroup.class.getPackage().getName();
  5. }
  6. }

Supporting Files

Elide standalone also requires a hibernate config file. By default the standalone API expects to find your hibernateconfig at ./settings/hibernate.cfg.xml (with respect to CWD when you launch the app). If you want tosee the logs from your shiny new API you will also want a logback config. Your logback config should goin src/main/resources so logback can find it.

Running

With these new classes you have two options for running your project, you can either run the Main class using yourfavorite IDE, or we can add the following snippet to our gradle build script and run our project with ./gradlew run

  1. plugins {
  2. ...
  3. id 'application'
  4. }
  5. mainClassName = 'com.example.repository.Main' // the actual path to your Main class should go here

With the Main and Settings classes we can now run our API. If you navigate tohttp://localhost:8080/api/v1/artifactGroup in your browser you can see some of the sample data that the bootstrapscript added for us. Exciting!

  1. {"data":[{"type":"artifactGroup","id":"com.example.repository"},{"type":"artifactGroup","id":"com.yahoo.elide"}]}

Adding More Data

Now that we have an API that returns data, let’s add some more interesting behavior. Let’s update ArtifactGroup, andadd the ArtifactProduct and ArtifactVersion classes–which will be the <artifactId> and <version> tagsrespectively.

  1. @Include(rootLevel = true)
  2. @Entity
  3. public class ArtifactGroup {
  4. @Id
  5. public String name = "";
  6. public String commonName = "";
  7. public String description = "";
  8. @OneToMany(mappedBy = "group")
  9. public List<ArtifactProduct> products = new ArrayList<>();
  10. }
  1. @Include
  2. @Entity
  3. public class ArtifactProduct {
  4. @Id
  5. public String name = "";
  6. public String commonName = "";
  7. public String description = "";
  8. @ManyToOne
  9. public ArtifactGroup group = null;
  10. @OneToMany(mappedBy = "artifact")
  11. public List<ArtifactVersion> versions = new ArrayList<>();
  12. }
  1. @Include
  2. @Entity
  3. public class ArtifactVersion {
  4. @Id
  5. public String name = "";
  6. public Date createdAt = new Date();
  7. @ManyToOne
  8. public ArtifactProduct artifact;
  9. }

We add the missing fields to ArtifactGroup since we anticipate user will want to add some informative metadata to helpusers find the products and artifacts they are interested in. If we restart the API and request /artifactGroup we’llsee the other metadata we just added.

  1. {"data":[{"type":"artifactGroup","id":"com.example.repository","attributes":{"commonName":"Example Repository","description":"The code for this project"},"relationships":{"products":{"data":[]}}},{"type":"artifactGroup","id":"com.yahoo.elide","attributes":{"commonName":"Elide","description":"The magical library powering this project"},"relationships":{"products":{"data":[{"type":"artifactProduct","id":"elide-core"},{"type":"artifactProduct","id":"elide-standalone"},{"type":"artifactProduct","id":"elide-datastore-hibernate5"}]}}}]}

So now we have an API that can display information for a full <group>:<product>:<version> set. We can fetch data fromour API in the following ways:

  1. List groups: /artifactGroup/
  2. Show a group: /artifactGroup/<group id>
  3. List a group's products: /artifactGroup/<group id>/products/
  4. Show a product: /artifactGroup/<group id>/products/<product id>
  5. List a product's versions: /artifactGroup/<group id>/products/<product id>/versions/
  6. Show a version: /artifactGroup/<group id>/products/<product id>/versions/<version id>

We can now fetch almost all of the data we would wish, but let’s clean it up a bit. Right now all of our data types areprefixed with Artifact. This might make sense in Java so that we don’t have naming collisions with classes from otherlibraries, however the consumers of our API do not care about naming collisions. We can control how Elide exposes ourclasses by setting the type on our @Include annotations.

  1. @Include(type = "group")
  2. @Entity
  3. public class ArtifactGroup { ... }
  4. @Include(type = "product")
  5. @Entity
  6. public class ArtifactProduct { ... }
  7. @Include(type = "version")
  8. @Entity
  9. public class ArtifactVersion{ ... }

Now, instead of making a call to http://localhost:8080/api/v1/artifactGroup to fetch our data, we make a request tohttp://localhost:8080/api/v1/group. Our API returns the same data as before, mostly. The types of our objects nowreflect our preferences from the Include annotations.

  1. {"data":[{"type":"group","id":"com.example.repository",...},{"type":"group","id":"com.yahoo.elide",..."relationships":{"products":{"data":[{"type":"product","id":"elide-core"},...]}}}]}

Writing Data

So far we have defined our views on the database and exposed those views over HTTP. This is great progress, but so farwe have only read data from the database.

Inserting Data

Fortunately for us adding data is just as easy as reading data. For now let’s use cURL to put data in the database.

  1. curl -X POST http://localhost:8080/api/v1/group/com.example.repository/products \
  2. -H"Content-Type: application/vnd.api+json" -H"Accept: application/vnd.api+json" \
  3. -d '{"data": {"type": "product", "id": "elide-demo"}}'

When you run that cURL call you should see a bunch of json returned, that is our newly inserted object! If we queryhttp://localhost:8080/api/v1/group/com.example.repository/products/

  1. {"data":[{"type":"product","id":"elide-demo","attributes":{"commonName":"","description":""},"relationships":{"group":{"data":{"type":"group","id":"com.example.repository"}},"versions":{"data":[]}}}]}

Modifying Data

Notice that, when we created it, we did not set any of the attributes of our new product record. Unfortunately for ourusers this leaves the meaning of our elide-demo product ambiguous. What does it do, why should they use it? Updating ourdata to help our users is just as easy as it is to add new data. Let’s update our bean with the following cURL call.

  1. curl -X PATCH http://localhost:8080/api/v1/group/com.example.repository/products/elide-demo \
  2. -H"Content-Type: application/vnd.api+json" -H"Accept: application/vnd.api+json" \
  3. -d '{
  4. "data": {
  5. "type": "product",
  6. "id": "elide-demo",
  7. "attributes": {
  8. "commonName": "demo application",
  9. "description": "An example implementation of an Elide web service that showcases many Elide features"
  10. }
  11. }
  12. }'

It’s just that easy to create and update data using Elide.

原文: http://elide.io/pages/guide/01-start.html