Services

Anatomy of a service µSpec #

The µService specs are regular yaml files.

The “service-object” contains 5 fields. The fields name, package and methods are mandatory, the field target and description is optional and autogenerated when ommited.

You can have as many service definitions per file as you want. It makes sense that you put types in a file, that belongs togehter.

The field methods in µServcies will translate to services in the standard notation for compatibility reasons, because the standard notation is some years old and changing this would be a breaking change we do not want to do at the moment.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
- name: FruitService
  description: Fruits are healthy, so having a service which can list some fruits would be nice.
  package: fruit
  target: fruit_service.proto
  methods:
    - md: 'ListFruits: GET /fruits google.protobuf.Empty , fruit.FruitCollection #Filterable and searchable list of fruits with pagination.'
      qp:
        q: 'string #Use this to search for a fruit.'
        filter: 'string #Use this field to filter the fruits, this is not searching.'
        order_by: 'string #Use this field to specify the ordering.'
        page: 'string #Use this field to specify page to display.'

The Name #

The name of the Service. Visit the style guide for good naming. Can not contain spaces.

The Description #

Describe the intention of your service in some sentences. You can ommit this field. Furo will add a default description “developer was to lazy to give a description”.

The Package #

Define the package, this service belongs too.

The Target #

The target proto file for the generated proto. Furo can not generate proto files which mixes types and services.

The Method definition #

The method defiton is made like the type line in µTypes

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
methods:
- md: 'GetFruit: GET /fruits/{frt} google.protobuf.Empty , fruit.FruitCollection #Filterable list of fruits.'
   ^   !______!^ !__! !_____!!__!  !___________________! ^ !___________________! ^!________________________!
   |       |   |   |     |     |            |            |           |           |              |
this means |   |   |     |     |      the request type   |           |           |              |
  Method   |   |   |     |   placeholder                 |   the response type   |              |
 Definiton |   |   |   the URL                           |                       |           description
      method name  |                                  a comma                    |
               the http verb                                            (#) is a separator, indicating the
               |                                                            beginning of the description         
               |
                  (:) is just a separator

The Method Name #

The method name should follow the naming conventions from the google api design guide. Default names are (with fruit as example)

  • ListFruits with a verb GET to receive a list of fruits
  • GetFruit with a verb GET and an identifier placeholder to get a single record
  • UpdateFruit with a verb PUT or PATCH and an identifier placeholder to update a single record
  • CreateFruit with a verb POST to create a single record
  • DeleteFruit with a verb DELETE and an identifier placeholder to delete a single record
  • DeleteAllFruits with a verb DELETE to delete all records on this path
  • CustomMethod with a verb POST to do custom stuff that does not fit in the other methods. Uses always a POST.

The HTTP Verb #

Use the standard Http verbs (GET, PUT, PATCH, POST, DELETE) according to the idempotency, except on custom methods, they should always use POST.

The URL with Placeholder #

Usualy the path part is a noun in plural form. Use singular nouns only on singleton ressources. Do not append a prefix like /api to your paths. Use /fruits.

TIPP: Assume that your API is a host by its own. So you will address it with api.xy.com/fruits. Having api.xy.com/api/fruits will look strange in that moment.

Adding prefixes can be done by infrastructure. The furo client libs also have the posibillity to prefix your specs according to the situation.

You will loose portability capabilities when you prefix your paths.

The Request Type #

On GET requests you can not send a body, therfore you will put a google.protobuf.Empty type here. On DELETE requests you can not send a body, therfore you will put a google.protobuf.Empty type here. On the other verbs, set the type to one of the types in your project specs or installed specs.

The Response Type #

Usualy you should use a entity or collection type as response (this is what the client libs loves to work with). But you are free to define any response type as long all participants on client and server side know it.

Description #

Again, descriptions are always optional, but strongly recomended to fill in. They will apear in every generate and can give good hints to the devs who have to implement the specs.

The Query Params #

Methods can have query params as part of the URL path (placeholders) and as query part.

TIPP: be lazy and just write your /paths/with/{phdr}/fruits/{frt}.

Then run furo muSrvSanitize.

This will add the missing query params to your spec with a default description.

1
2
3
4
5
6
7
8
  qp: <--- this means QueryParams
    q: 'string #Use this to search for a fruit.'
    ^  !_____! !______________________________!
    |     |                |
    |    type           description   
    |
      the name of the query param

The Query Param Name #

The name must match with the used placeholders for the path part. Query params should fullfill the RFC3986. Otherwise you risk to never receive the param on the server side.

The Query Param Type #

The type is mostly a string. You can use any type which is url safe.

The Query Param Description #

Ceterum censeo, descriptions are useful information.

Custom Methods in Detail #

todo: write something about that.