Skip to content

Commit

Permalink
Merge pull request #2 from jorgechato/feature/api-first-contract-and-…
Browse files Browse the repository at this point in the history
…definition

UDPATE api contract and definition
  • Loading branch information
Jorge Chato committed Apr 2, 2019
2 parents 831e302 + 14f48e5 commit 352e0e2
Show file tree
Hide file tree
Showing 10 changed files with 190 additions and 1 deletion.
10 changes: 9 additions & 1 deletion README.md
Expand Up @@ -21,7 +21,9 @@ TODO: architecture

## API

TODO: Swagger file
Base API contract is stored in the [doc](/doc/contract.json) folder.
You can see the UI in http://<ENDPOINT>:<PORT>/ and the live documentation in
http://<ENDPOINT>:<PORT>/swagger.json tho.

## Run

Expand All @@ -31,6 +33,12 @@ $ FLASK_APP=src/app flask run
$ python src/app.py
```

```bash
$ curl -X PUT http://<ENDPOINT>:<PORT>/search \
-H 'content-type: application/json' \
-d @'base.template.json'
```

## Deploy

The deployment is automated by the CI/CD pipeline but you can always run it in
Expand Down
7 changes: 7 additions & 0 deletions base.template.json
@@ -0,0 +1,7 @@
{
"query": {
"word": "fit",
"strict": true
},
"source": "https://www.virtusize.jp/"
}
8 changes: 8 additions & 0 deletions complex.template.json
@@ -0,0 +1,8 @@
{
"query": {
"word": "fit",
"strict": false
},
"source": "https://www.virtusize.jp/"
}

122 changes: 122 additions & 0 deletions doc/contract.json
@@ -0,0 +1,122 @@
{
"swagger": "2.0",
"basePath": "/",
"paths": {
"/health": {
"get": {
"responses": {
"200": {
"description": "Success"
}
},
"operationId": "get_health",
"tags": [
""
]
}
},
"/search": {
"put": {
"responses": {
"200": {
"description": "Success",
"schema": {
"$ref": "#/definitions/Word"
}
}
},
"operationId": "put_search",
"parameters": [
{
"name": "payload",
"required": true,
"in": "body",
"schema": {
"$ref": "#/definitions/Search"
}
},
{
"name": "X-Fields",
"in": "header",
"type": "string",
"format": "mask",
"description": "An optional fields mask"
}
],
"tags": [
""
]
}
}
},
"info": {
"title": "Word search engine",
"version": "1.0",
"description": "The service will allow a user to search an specific word in an URL"
},
"produces": [
"application/json"
],
"consumes": [
"application/json"
],
"tags": [
{
"name": "",
"description": "Simple word search engine"
}
],
"definitions": {
"Search": {
"properties": {
"query": {
"$ref": "#/definitions/Query"
},
"source": {
"type": "string"
}
},
"type": "object"
},
"Query": {
"properties": {
"word": {
"type": "string"
},
"strict": {
"type": "boolean",
"default": true
}
},
"type": "object"
},
"Word": {
"properties": {
"__this": {
"type": "string"
},
"query": {
"$ref": "#/definitions/Query"
},
"source": {
"type": "string"
},
"found": {
"type": "boolean"
},
"count": {
"type": "integer"
}
},
"type": "object"
}
},
"responses": {
"ParseError": {
"description": "When a mask can't be parsed"
},
"MaskError": {
"description": "When any error occurs on mask"
}
}
}
1 change: 1 addition & 0 deletions environment.yml
Expand Up @@ -4,3 +4,4 @@ dependencies:
- flask
- pip:
- flask-restplus
- prometheus-client
17 changes: 17 additions & 0 deletions src/api/controller.py
Expand Up @@ -3,11 +3,28 @@
from flask_restplus import abort
from flask import request

from api.schema import response_schema
from api.schema import request_schema
from api.schema import query_schema


ns = Namespace('', description='Simple word search engine')

ns.add_model('Word', response_schema)
ns.add_model('Query', query_schema)
ns.add_model('Search', request_schema)


@ns.route("/health")
class Health(Resource):
def get(self, **kwargs):
return {"alive": True}


@ns.route("/search")
class Search(Resource):
@ns.doc(body=request_schema)
@ns.expect(request_schema)
@ns.marshal_with(response_schema, skip_none=True, code=200)
def put(self, **kwargs):
return {"strict": True}
4 changes: 4 additions & 0 deletions src/api/model.py
@@ -0,0 +1,4 @@
class Search:
def __init__(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
21 changes: 21 additions & 0 deletions src/api/schema.py
@@ -0,0 +1,21 @@
from flask_restplus import fields
from flask_restplus import Model


query_schema = Model('Query', {
'word': fields.String,
'strict': fields.Boolean(default=True),
})

response_schema = Model('Word', {
'__this': fields.Url(absolute=True),
'query': fields.Nested(query_schema),
'source': fields.String,
'found': fields.Boolean,
'count': fields.Integer,
})

request_schema = Model('Search', {
'query': fields.Nested(query_schema),
'source': fields.String,
})
Empty file added src/api/utils/__init__.py
Empty file.
1 change: 1 addition & 0 deletions src/requirements.txt
Expand Up @@ -3,3 +3,4 @@ get==1.0.3
httplib2==0.11.3
pytest==4.2.0
flask-restplus==0.12.1
prometheus-client==0.6.0

0 comments on commit 352e0e2

Please sign in to comment.